fix(missions): every phase of a mission shared one branch
`branch_name` took `[..8]` of both the mission and the phase id. Both are
UUIDv7, which leads with a 48-bit timestamp, so ids minted in the same
millisecond — which is exactly what happens when a mission inserts its phases
in one transaction — share their leading hex. Production produced:
clawmates/mission-019fc40e-019fc40e
for both the research and the coding phase. Each phase's commit moved the ref
the previous one had just set, so a two-phase mission ended with one branch
and the earlier phase's work reachable only by sha.
The segments now come from opposite ends: the mission keeps its time-ordered
prefix so branches group and sort usefully, and the phase contributes its
random tail so siblings cannot collide.
The existing test missed this because it compared iteration 0 against
iteration 1 of the *same* phase, where the `-i2` suffix guaranteed a
difference. The new test asserts the precondition explicitly — two v7 ids
minted together do share leading hex — and then that their branches differ
anyway.
Also adds the `commit_policy` gate, which three workflow recipes have declared
since they were written with nothing reading it. Two properties it must have:
a failed gate redirects work to `<branch>-wip` rather than discarding it, and
an unrunnable or undiscoverable test suite counts as unproven, never as green.
`discover_test_command` returns None for a `package.json` with no test script,
because `npm test` exits non-zero for a missing script and would read as a red
suite rather than an absent one. Not yet wired to publishing.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ca1fd46e08
commit
3ea288dbb5
@@ -386,6 +386,32 @@ async fn excluded_paths_are_not_committed() {
|
||||
);
|
||||
}
|
||||
|
||||
/// Sibling phases of one mission must not share a branch.
|
||||
///
|
||||
/// They did. Both ids are UUIDv7, which leads with a timestamp, so two phases
|
||||
/// created in the same millisecond had identical leading hex and the name
|
||||
/// collapsed to one branch per mission — each phase quietly moving the ref the
|
||||
/// previous one had set. Production showed
|
||||
/// `clawmates/mission-019fc40e-019fc40e` for both phases of a mission.
|
||||
#[test]
|
||||
fn sibling_phases_get_distinct_branches() {
|
||||
let mission = Uuid::now_v7();
|
||||
// Minted back to back, so they share a timestamp prefix exactly as they do
|
||||
// when a mission inserts its phases in one transaction.
|
||||
let research = Uuid::now_v7();
|
||||
let coding = Uuid::now_v7();
|
||||
assert_eq!(
|
||||
research.simple().to_string()[..8],
|
||||
coding.simple().to_string()[..8],
|
||||
"precondition: v7 ids minted together share their leading hex"
|
||||
);
|
||||
|
||||
let a = mission_delivery::branch_name(mission, research, 0);
|
||||
let b = mission_delivery::branch_name(mission, coding, 0);
|
||||
assert_ne!(a, b, "each phase needs its own ref: {a} vs {b}");
|
||||
assert!(a.starts_with("clawmates/mission-"));
|
||||
}
|
||||
|
||||
/// A re-run must not collide with the pass before it.
|
||||
#[test]
|
||||
fn a_rerun_lands_on_its_own_branch() {
|
||||
|
||||
Reference in New Issue
Block a user