You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
State/merge error-path remediation moves from resident contract prose into the binary's own failure output (#465)
* D4: reword mod-block/merge-hook --set refusal tails, drop bare --force invitation
* D5: merge guard refuses a mod-block naming a missing merge mod (no-sentinel case)
* D3: merge guard armed/blocked/finalized default prose names the FO's next step
* D1: state commit/ready HALT stderr carries peer commit + FO remediation; ready resume prints re-boot line
* D2: state sweep distinguishes gh-unavailable UNKNOWN from truly empty; names the startup-hook mod-pointer next step
* Shrink shared-core and fo-merge-core prose per the guidance-coverage map (AC-1)
* Feedback cycle 1: strengthen D5 test coverage per adversarial audit
T1: dedicated test for the no-merge-hook-registered-at-all shape (the
deleted mod file was the workflow's only hook) — distinct from the
existing missing-mod test, which fixtures a workflow with a DIFFERENT
hook still registered. Catches a mutant that special-cases
modBlockNamesMissingMergeMod on len(mergeHooks)==0.
T2: pin the full remediation tail on the existing missing-mod refusal
test, not just the mod-name + "is missing" fragment.
Both mutants verified RED locally before landing, then reverted.
* Feedback cycle 2: fix ghRunnerExec to parse the --jq .state shape, not a JSON envelope
Root cause: ghRunnerExec called `gh pr view PR --json state` and
json.Unmarshal'd the result, while boot.go's already-proven PR_STATE
probe uses `gh pr view PR --json state --jq .state` (bare, jq-extracted
text). Against a `gh` whose output matches the latter shape — including
the shared ensigncycle shallow-boot fixture's stub gh, which PR #465's
codex-live scenario runs against — the JSON unmarshal fails and a
working probe was counted as an error by D2's gh-unavailable
classifier, making `state sweep` report UNKNOWN instead of advancing
the merged entity.
Fix: align ghRunnerExec with boot.go's proven invocation exactly (same
flags, same leading-"#" trim, same --jq extraction). The two probes now
agree on what "gh can answer" means.
Reproduced offline against the exact shared fixture shape before
fixing; regression tests pin both the direct probe
(TestGhRunnerExecParsesJqExtractedState) and the end-to-end sweep
(TestSweepWithRealGhStubDoesNotReportUnknown) using the real production
GhRunnerExec. Both verified RED against the pre-fix ghRunnerExec,
reverted, GREEN restored.
---------
Co-authored-by: Spike Test <spike@example.com>
t.Fatalf("HALT stderr should name the peer commit %q, got:\n%s", peerSHA, errOut)
150
+
}
151
+
if!strings.Contains(errOut, "Next: HALT dispatch — do not dispatch against this state tree. Surface the conflicting path(s) and peer commit to the operator and stop.") {
152
+
t.Fatalf("HALT stderr should name the FO's next action, got:\n%s", errOut)
153
+
}
154
+
if!strings.Contains(errOut, "Never `git push --force`/`--force-with-lease`; never re-run with `-X ours`/`-X theirs`; never discard either side.") {
155
+
t.Fatalf("HALT stderr should carry the never-force/never-auto-resolve line, got:\n%s", errOut)
156
+
}
157
+
}
158
+
159
+
// TestStateCommitHaltJSONCarriesPeerCommit pins AC-2's --json requirement: the
160
+
// halt envelope carries peer_commit alongside the existing conflicting_paths.
t.Fatalf("ready HALT stderr should name the peer commit %q, got:\n%s", peerSHA, errOut)
114
+
}
115
+
if!strings.Contains(errOut, "Next: HALT dispatch — do not dispatch against this state tree. Surface the conflicting path(s) and peer commit to the operator and stop.") {
116
+
t.Fatalf("ready HALT stderr should name the FO's next action, got:\n%s", errOut)
117
+
}
118
+
if!strings.Contains(errOut, "Never `git push --force`/`--force-with-lease`; never re-run with `-X ours`/`-X theirs`; never discard either side.") {
119
+
t.Fatalf("ready HALT stderr should carry the never-force/never-auto-resolve line, got:\n%s", errOut)
120
+
}
121
+
}
122
+
88
123
// TestStateReadyInlineNoOp pins AC-6 inline case: an inline workflow is a clean
89
124
// no-op (exit 0, nothing to sync, no git network op).
fmt.Fprintf(stderr, "The rebase was aborted (checkout left clean) and nothing was force-pushed; a peer's edit is preserved on origin. Manual intervention is required.\n")
fmt.Fprintf(stderr, "The rebase was aborted (checkout left clean) and nothing was force-pushed; a peer's edit is preserved on origin.\n")
228
+
fmt.Fprintf(stderr, "Next: HALT dispatch — do not dispatch against this state tree. Surface the conflicting path(s) and peer commit to the operator and stop.\n")
229
+
fmt.Fprintf(stderr, "Never `git push --force`/`--force-with-lease`; never re-run with `-X ours`/`-X theirs`; never discard either side.\n")
0 commit comments