* fix(#3518): pin uat_path to the phase's own UAT artifact via the shared phase-pinned resolver Both uat_path projectors in src/init.cts picked the phase's UAT file with a bare .find() over unsorted readdir order — no phase-membership check, no ordering — so a stray cross-phase 04-UAT.md in phase 03's directory could become phase 03's uat_path, filesystem-dependently (creation order on APFS, hash order on ext4/XFS): two machines on the same commit could emit different uat_path values for the same phase. Route both sites through a new resolveUatFile in src/verification.cts, the UAT counterpart of #3357/#3492's resolveVerificationFile, sharing the exact selection rule via one extracted core (resolvePhaseArtifactFile): the phase's own <token>-UAT.md always wins; otherwise the alphabetically-first dashed candidate (deterministic everywhere); a bare UAT.md only via allowBare when no dashed candidate exists. resolveVerificationFile now delegates to the same core — behavior byte-identical. Guarded by: two end-to-end repro tests in tests/init.test.cjs (plan-phase and phase-op, red on the pre-fix readdir pick), resolveUatFile contract anchors and a src/-wide call-site guard in tests/verification-status.test.cjs. * chore(#3518): add changeset fragment for PR #3525 --------- Co-authored-by: sim <sim@local>
994 B
type, pr
| type | pr |
|---|---|
| Fixed | 3525 |
uat_path is now pinned to the phase's own UAT artifact instead of being picked by unsorted directory-listing order — both uat_path projections (init plan-phase and init phase-op) selected the phase's *-UAT.md with a bare first-match .find() that had no phase-membership check and no ordering, so a stray or cross-phase 04-UAT.md sitting in phase 03's directory could become phase 03's uat_path, and which file won was filesystem-dependent (creation order on APFS, hash order on ext4/XFS) — meaning two machines on the same commit could emit different uat_path values for the same phase, sending downstream workflows to read another phase's UAT state. Both sites now route through a shared phase-pinned resolver (resolveUatFile, sibling of the resolveVerificationFile rule from #3357/#3492): the phase's own <token>-UAT.md always wins, otherwise the alphabetically-first dashed candidate, deterministically on every machine. (#3518)