dev-loops 0.6.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/.claude/.claude-plugin/plugin.json +1 -1
  2. package/.claude/agents/dev-loop.md +8 -7
  3. package/.claude/agents/fixer.md +1 -0
  4. package/.claude/agents/refiner.md +2 -2
  5. package/.claude/agents/review.md +4 -3
  6. package/.claude/commands/{auto.md → loop-auto.md} +1 -1
  7. package/.claude/commands/loop-continue.md +15 -0
  8. package/.claude/commands/loop-enqueue.md +22 -0
  9. package/.claude/commands/loop-grill.md +17 -0
  10. package/.claude/commands/{info.md → loop-info.md} +2 -2
  11. package/.claude/commands/loop-queue-status.md +24 -0
  12. package/.claude/commands/{start-spike.md → loop-start-spike.md} +2 -2
  13. package/.claude/commands/{start.md → loop-start.md} +1 -1
  14. package/.claude/commands/{status.md → loop-status.md} +1 -1
  15. package/.claude/hooks/_bash-command-classify.mjs +333 -29
  16. package/.claude/hooks/_hook-decisions.mjs +138 -15
  17. package/.claude/hooks/pre-tool-use-bash-gate.mjs +36 -15
  18. package/.claude/skills/copilot-pr-followup/SKILL.md +60 -34
  19. package/.claude/skills/dev-loop/SKILL.md +16 -12
  20. package/.claude/skills/docs/acceptance-criteria-verification.md +8 -3
  21. package/.claude/skills/docs/anti-patterns.md +5 -3
  22. package/.claude/skills/docs/artifact-authority-contract.md +30 -11
  23. package/.claude/skills/docs/confirmation-rules.md +1 -0
  24. package/.claude/skills/docs/contract-style-guide.md +37 -0
  25. package/.claude/skills/docs/copilot-loop-operations.md +19 -15
  26. package/.claude/skills/docs/cross-harness-regression-contract.md +60 -0
  27. package/.claude/skills/docs/debt-remediation-contract.md +1 -1
  28. package/.claude/skills/docs/epic-tree-refinement-procedure.md +25 -22
  29. package/.claude/skills/docs/issue-intake-procedure.md +26 -19
  30. package/.claude/skills/docs/local-planning-flow.md +1 -1
  31. package/.claude/skills/docs/local-planning-worked-example.md +1 -1
  32. package/.claude/skills/docs/merge-preconditions.md +30 -12
  33. package/.claude/skills/docs/plan-file-contract.md +1 -1
  34. package/.claude/skills/docs/pr-lifecycle-contract.md +44 -35
  35. package/.claude/skills/docs/public-dev-loop-contract.md +60 -44
  36. package/.claude/skills/docs/retrospective-checkpoint-contract.md +106 -79
  37. package/.claude/skills/docs/spike-mode-contract.md +14 -7
  38. package/.claude/skills/docs/stop-conditions.md +30 -15
  39. package/.claude/skills/docs/tracker-first-loop-state.md +13 -8
  40. package/.claude/skills/docs/ui-e2e-scoping-step.md +32 -0
  41. package/.claude/skills/docs/validation-policy.md +4 -5
  42. package/.claude/skills/docs/workflow-handoff-contract.md +39 -0
  43. package/.claude/skills/local-implementation/SKILL.md +62 -145
  44. package/.claude/skills/loop-grill/SKILL.md +163 -0
  45. package/AGENTS.md +1 -0
  46. package/CHANGELOG.md +101 -0
  47. package/README.md +9 -9
  48. package/agents/dev-loop.agent.md +11 -10
  49. package/agents/developer.agent.md +1 -1
  50. package/agents/docs.agent.md +1 -1
  51. package/agents/fixer.agent.md +2 -1
  52. package/agents/quality.agent.md +1 -1
  53. package/agents/refiner.agent.md +3 -3
  54. package/agents/review.agent.md +5 -4
  55. package/cli/index.mjs +35 -42
  56. package/extension/README.md +4 -4
  57. package/extension/checks.ts +1 -5
  58. package/extension/harness-types.ts +1 -0
  59. package/extension/index.ts +6 -0
  60. package/extension/pi-extension-adapter.ts +2 -0
  61. package/extension/presentation.ts +7 -19
  62. package/package.json +12 -12
  63. package/scripts/_core-helpers.mjs +2 -0
  64. package/scripts/claude/headless-dev-loop.mjs +1 -1
  65. package/scripts/docs/validate-rule-ownership.mjs +442 -0
  66. package/scripts/docs/validate-state-machine-conformance.mjs +1092 -0
  67. package/scripts/github/_review-thread-mutations.mjs +5 -2
  68. package/scripts/github/capture-review-threads.mjs +2 -9
  69. package/scripts/github/comment-issue.mjs +2 -9
  70. package/scripts/github/create-label.mjs +133 -0
  71. package/scripts/github/create-pr.mjs +119 -10
  72. package/scripts/github/detect-checkpoint-evidence.mjs +259 -18
  73. package/scripts/github/detect-linked-issue-pr.mjs +22 -6
  74. package/scripts/github/edit-pr.mjs +259 -0
  75. package/scripts/github/fetch-ci-logs.mjs +2 -9
  76. package/scripts/github/list-issues.mjs +2 -9
  77. package/scripts/github/list-review-threads.mjs +277 -0
  78. package/scripts/github/manage-sub-issues.mjs +46 -10
  79. package/scripts/github/offer-human-handoff.mjs +8 -5
  80. package/scripts/github/post-gate-findings.mjs +20 -5
  81. package/scripts/github/probe-ci-status.mjs +8 -2
  82. package/scripts/github/probe-copilot-review.mjs +21 -14
  83. package/scripts/github/ready-for-review.mjs +26 -8
  84. package/scripts/github/reconcile-draft-gate.mjs +7 -3
  85. package/scripts/github/reply-resolve-review-thread.mjs +16 -5
  86. package/scripts/github/reply-resolve-review-threads.mjs +69 -7
  87. package/scripts/github/request-copilot-review.mjs +98 -26
  88. package/scripts/github/resolve-handoff-candidates.mjs +7 -3
  89. package/scripts/github/resolve-tracker-local-spec.mjs +9 -3
  90. package/scripts/github/stage-reviewer-draft.mjs +10 -2
  91. package/scripts/github/tick-verified-checkboxes.mjs +202 -0
  92. package/scripts/github/upsert-checkpoint-verdict.mjs +105 -15
  93. package/scripts/github/verify-briefing-prefixes.mjs +191 -0
  94. package/scripts/github/verify-fresh-review-context.mjs +226 -32
  95. package/scripts/github/view-pr.mjs +150 -0
  96. package/scripts/github/wait-pr-checks.mjs +171 -0
  97. package/scripts/github/write-gate-context.mjs +458 -65
  98. package/scripts/github/write-gate-findings-log.mjs +128 -2
  99. package/scripts/lib/jq-output.mjs +18 -0
  100. package/scripts/loop/_post-convergence-change.mjs +211 -0
  101. package/scripts/loop/_pr-runner-coordination.mjs +70 -0
  102. package/scripts/loop/_repo-root-resolver.mjs +47 -0
  103. package/scripts/loop/build-handoff-envelope.mjs +14 -4
  104. package/scripts/loop/check-retro-tooling.mjs +14 -3
  105. package/scripts/loop/checkpoint-contract.mjs +7 -4
  106. package/scripts/loop/cleanup-worktree.mjs +12 -3
  107. package/scripts/loop/conductor-monitor.mjs +12 -18
  108. package/scripts/loop/copilot-pr-handoff.mjs +162 -14
  109. package/scripts/loop/debt-remediate.mjs +24 -12
  110. package/scripts/loop/detect-change-scope.mjs +38 -9
  111. package/scripts/loop/detect-copilot-loop-state.mjs +34 -8
  112. package/scripts/loop/detect-copilot-session-activity.mjs +7 -3
  113. package/scripts/loop/detect-initial-copilot-pr-state.mjs +7 -3
  114. package/scripts/loop/detect-internal-only-pr.mjs +8 -2
  115. package/scripts/loop/detect-issue-refinement-artifact.mjs +6 -3
  116. package/scripts/loop/detect-pr-gate-coordination-state.mjs +184 -69
  117. package/scripts/loop/detect-reviewer-loop-state.mjs +12 -2
  118. package/scripts/loop/detect-tracker-first-loop-state.mjs +9 -1
  119. package/scripts/loop/detect-tracker-pr-state.mjs +10 -3
  120. package/scripts/loop/ensure-worktree.mjs +8 -3
  121. package/scripts/loop/info.mjs +12 -4
  122. package/scripts/loop/inspect-run-viewer/constants.mjs +4 -18
  123. package/scripts/loop/inspect-run-viewer/vendor/mermaid.min.js +3405 -0
  124. package/scripts/loop/inspect-run-viewer-ci-changes.mjs +18 -6
  125. package/scripts/loop/inspect-run-viewer.mjs +67 -4
  126. package/scripts/loop/inspect-run.mjs +8 -2
  127. package/scripts/loop/outer-loop.mjs +8 -4
  128. package/scripts/loop/pr-runner-coordination.mjs +2 -9
  129. package/scripts/loop/pre-commit-branch-guard.mjs +16 -10
  130. package/scripts/loop/pre-flight-gate.mjs +9 -9
  131. package/scripts/loop/pre-pr-ready-gate.mjs +8 -4
  132. package/scripts/loop/pre-write-remote-freshness-guard.mjs +13 -4
  133. package/scripts/loop/provision-worktree.mjs +74 -3
  134. package/scripts/loop/resolve-dev-loop-startup.mjs +216 -10
  135. package/scripts/loop/resolve-gate-dispatch.mjs +134 -0
  136. package/scripts/loop/resolve-pr-conflicts.mjs +14 -7
  137. package/scripts/loop/run-conductor-cycle.mjs +8 -2
  138. package/scripts/loop/run-queue.mjs +18 -9
  139. package/scripts/loop/run-refinement-audit.mjs +8 -9
  140. package/scripts/loop/run-watch-cycle.mjs +2 -9
  141. package/scripts/loop/sanctioned-commands.mjs +106 -0
  142. package/scripts/loop/steer-loop.mjs +29 -16
  143. package/scripts/loop/validate-pr-body-spec.mjs +223 -0
  144. package/scripts/loop/watch-initial-copilot-pr.mjs +8 -3
  145. package/scripts/pages/build-site.mjs +59 -8
  146. package/scripts/pages/build-state-atlas.mjs +443 -0
  147. package/scripts/projects/_resolve-project.mjs +1 -0
  148. package/scripts/projects/add-queue-item.mjs +60 -54
  149. package/scripts/projects/archive-done-items.mjs +49 -84
  150. package/scripts/projects/ensure-queue-board.mjs +10 -36
  151. package/scripts/projects/list-queue-items.mjs +59 -382
  152. package/scripts/projects/move-queue-item.mjs +21 -449
  153. package/scripts/projects/reconcile-queue.mjs +253 -0
  154. package/scripts/projects/reorder-queue-item.mjs +43 -68
  155. package/scripts/projects/resolve-active-board-item.mjs +108 -46
  156. package/scripts/projects/sync-item-status.mjs +15 -10
  157. package/scripts/refine/_refine-helpers.mjs +21 -5
  158. package/scripts/refine/exit-spike.mjs +18 -8
  159. package/scripts/refine/promote-plan.mjs +22 -16
  160. package/scripts/refine/prose-linkage-detector.mjs +1 -1
  161. package/scripts/refine/refine-plan-file.mjs +13 -4
  162. package/scripts/refine/refinement-completeness-checker.mjs +1 -1
  163. package/scripts/refine/scaffold-spike-file.mjs +4 -8
  164. package/scripts/refine/scope-boundary-cross-checker.mjs +1 -1
  165. package/scripts/refine/tree-integrity-validator.mjs +1 -1
  166. package/scripts/refine/validate-plan-file.mjs +1 -1
  167. package/scripts/refine/validate-spike-file.mjs +1 -1
  168. package/scripts/refine/verify.mjs +11 -6
  169. package/scripts/release/assert-core-dependency-version.mjs +123 -0
  170. package/scripts/release/extract-changelog-section.mjs +16 -2
  171. package/skills/copilot-pr-followup/SKILL.md +60 -34
  172. package/skills/dev-loop/SKILL.md +11 -7
  173. package/skills/docs/acceptance-criteria-verification.md +8 -3
  174. package/skills/docs/anti-patterns.md +5 -3
  175. package/skills/docs/artifact-authority-contract.md +30 -11
  176. package/skills/docs/confirmation-rules.md +1 -0
  177. package/skills/docs/contract-style-guide.md +37 -0
  178. package/skills/docs/copilot-loop-operations.md +19 -15
  179. package/skills/docs/cross-harness-regression-contract.md +60 -0
  180. package/skills/docs/debt-remediation-contract.md +1 -1
  181. package/skills/docs/epic-tree-refinement-procedure.md +25 -22
  182. package/skills/docs/issue-intake-procedure.md +26 -19
  183. package/skills/docs/local-planning-flow.md +1 -1
  184. package/skills/docs/local-planning-worked-example.md +1 -1
  185. package/skills/docs/merge-preconditions.md +30 -12
  186. package/skills/docs/plan-file-contract.md +1 -1
  187. package/skills/docs/pr-lifecycle-contract.md +44 -35
  188. package/skills/docs/public-dev-loop-contract.md +60 -44
  189. package/skills/docs/required-rules.json +149 -0
  190. package/skills/docs/retrospective-checkpoint-contract.md +106 -79
  191. package/skills/docs/spike-mode-contract.md +14 -7
  192. package/skills/docs/stop-conditions.md +30 -15
  193. package/skills/docs/tracker-first-loop-state.md +13 -8
  194. package/skills/docs/ui-e2e-scoping-step.md +32 -0
  195. package/skills/docs/validation-policy.md +4 -5
  196. package/skills/docs/workflow-handoff-contract.md +39 -0
  197. package/skills/local-implementation/SKILL.md +62 -145
  198. package/skills/loop-grill/SKILL.md +165 -0
  199. package/.claude/commands/continue.md +0 -15
  200. package/scripts/docs/validate-no-duplicate-rules.mjs +0 -250
  201. package/scripts/loop/conductor.mjs +0 -233
  202. package/scripts/loop/detect-stale-runner.mjs +0 -265
  203. package/scripts/loop/pre-push-main-guard.mjs +0 -117
@@ -38,14 +38,31 @@ doing manually; it is not a general conflict-resolution engine.
38
38
 
39
39
  ## Required before merge
40
40
 
41
+ <!-- rule: MERGE-PRECOND-REQUIRED -->
41
42
  1. ✅ Conflict-free with base (`mergeable: MERGEABLE`; not `CONFLICTING`/`DIRTY`/`BEHIND`/`UNKNOWN`)
42
- 1. ✅ CI green on current head (or crediblyGreen via `--local-validation-head-sha`)
43
- 2. ✅ Draft gate satisfied (clean verdict)
44
- 3. ✅ Pre-approval gate satisfied (clean verdict, current head)
45
- 4. ✅ All review threads resolved
46
- 5. ✅ Explicit merge authorization from operator
47
- 6. ✅ PR body contains `Closes #N` or `Fixes #N`
48
- 7. ✅ PR **title** free of merge-blocking markers — `WIP`, `[WIP]`, `DRAFT`, `DO NOT MERGE`, `🚧` (case-insensitive)
43
+ 2. ✅ CI green on current head (or crediblyGreen via `--local-validation-head-sha`)
44
+ 3. ✅ Draft gate satisfied clean `draft_gate` verdict per `GATE-COMMENT-VERDICT-VALUES` ([Checkpoint Verdict Comment Contract](../../docs/gate-review-comment-contract.md))
45
+ 4. ✅ Pre-approval gate satisfied clean `pre_approval_gate` verdict on the current head, same rule
46
+ 5. ✅ All review threads resolved
47
+ 6. ✅ Explicit merge authorization from operator
48
+ 7. ✅ Issue-backed work: PR body contains `Closes #N` or `Fixes #N`; for an issue-less lightweight PR the closing reference is instead absent by design (owned by `ARTIFACT-LIGHTWEIGHT-BODY-INVARIANTS` in [Artifact Authority Contract](artifact-authority-contract.md))
49
+ 8. ✅ PR **title** free of merge-blocking markers — `WIP`, `[WIP]`, `DRAFT`, `DO NOT MERGE`, `🚧` (case-insensitive)
50
+
51
+ > Runner-coordination lock: the pre-merge evidence check fails closed on a stale/foreign runner claim for the PR. A completing run releases its claim best-effort at every terminal stop (including the human approval checkpoint), so a merge re-dispatch normally proceeds. If a lock held by a completed/dead run still blocks the merge, take it over explicitly with `node <resolved-skill-scripts>/loop/pr-runner-coordination.mjs takeover --repo <owner/name> --pr <number>`. Never take over a genuinely active (non-stale) run — that fail-closed block is intentional.
52
+
53
+ ### Evidence writes and `gh pr merge` MUST be separate tool calls (#1172)
54
+
55
+ The PreToolUse Bash gate evaluates `gh pr merge` **before** the Bash tool call executes. A compound
56
+ command that both writes gate evidence (the findings-log ledger, `upsert-checkpoint-verdict`) and
57
+ merges in the same call is blocked at hook-evaluation time — the write never runs. This can look
58
+ like the ledger "vanished" between writing and merging; it was never written. The block message
59
+ names this when it detects an evidence-writing invocation in the same command string.
60
+
61
+ Documented pattern — **write, verify, then merge alone**:
62
+
63
+ 1. Write the gate evidence (findings-log ledger / checkpoint verdict) in its own Bash call.
64
+ 2. Verify it landed (e.g. `ls tmp/gate-findings/<slug>/pr-<n>/`) in a separate call.
65
+ 3. Run `gh pr merge` alone, with no other command chained via `&&`/`;`/newline.
49
66
 
50
67
  ## Title markers
51
68
 
@@ -89,7 +106,7 @@ explicit instruction can unlock.
89
106
  When a repo sets `approval.humanHandoff.enabled: true` in `.devloops`, the loop
90
107
  does not just park silently at the human-merge stop — at the
91
108
  `pre_approval_gate` / `waiting_for_merge_authorization` boundary it **offers**
92
- to route the PR to a named human (pairs with `autonomy.humanMergeOnly`: when
109
+ to route the PR to a contributor (pairs with `autonomy.humanMergeOnly`: when
93
110
  human-merge is enforced, the handoff names who should take it). Disabled by
94
111
  default; no candidate sourcing when disabled.
95
112
 
@@ -124,10 +141,8 @@ human(s).
124
141
 
125
142
  ## Post-merge
126
143
 
127
- - Remove merged worktree (canonical): `node scripts/loop/cleanup-worktree.mjs --repo-root <main> (--issue <n> | --pr <n>)`.
128
- It resolves the namespaced path, runs `git worktree remove --force <path> && git worktree prune` (the underlying
129
- mechanism) from the main checkout, and refuses any path not under `tmp/worktrees/dev-loops/`. See
130
- [worktree guidance](../../docs/worktree-guidance.md).
144
+ - Remove merged worktree (canonical, `WORKTREE-CLEANUP`): `node scripts/loop/cleanup-worktree.mjs --repo-root <main> (--issue <n> | --pr <n>)`.
145
+ See [Worktree usage guidance](../../docs/worktree-guidance.md#post-merge-cleanup).
131
146
  - Archive long-done queue items (operator-induced, NOT a cron): `node scripts/projects/archive-done-items.mjs --repo <owner/name> || true`.
132
147
  Runs as part of this post-merge hook. It applies the configured `queue.archiveOlderThanDays` (default `7d`) and archives
133
148
  board items whose issue/PR has been closed at least that long. Best-effort: run it as a standard post-merge step but ignore
@@ -141,3 +156,6 @@ human(s).
141
156
  - [Confirmation rules](confirmation-rules.md)
142
157
  - [Validation policy](validation-policy.md)
143
158
  - [Stop conditions](stop-conditions.md)
159
+ - [PR Lifecycle Contract](pr-lifecycle-contract.md)
160
+ - [Checkpoint Verdict Comment Contract](../../docs/gate-review-comment-contract.md) — `GATE-COMMENT-VERDICT-VALUES`
161
+ - [Contract style guide](contract-style-guide.md)
@@ -4,7 +4,7 @@ A plan file is the persisted markdown artifact that drives work in local-plannin
4
4
 
5
5
  ## Format
6
6
 
7
- A plan file is a markdown document whose sections are level-2 (`##`) headings. It follows the same shape as the phase docs already committed under `docs/phases/`. The directory that holds plan files is `localPlanning.plansDir`, which defaults to `docs/phases/`.
7
+ A plan file is a markdown document whose sections are level-2 (`##`) headings. It follows the same shape as the phase docs already committed under `docs/phases/`, which is also the directory that holds plan files.
8
8
 
9
9
  ## Base authoring sections
10
10
 
@@ -1,6 +1,7 @@
1
1
  # PR lifecycle contract
2
2
 
3
- This document defines the deterministic **family-local PR lifecycle contract** for the GitHub/Copilot workflow family in `dev-loops`.
3
+ Canonical owner for **PR state vocabulary** rules for the GitHub/Copilot workflow family
4
+ in `dev-loops` — the deterministic family-local PR lifecycle contract.
4
5
 
5
6
  The canonical contract lives in the shipped `skills/docs/` surface because installed skill/runtime consumers reliably own the skills subtree.
6
7
 
@@ -38,23 +39,27 @@ It does not redefine helper transport mechanics, reviewer-loop internals, conduc
38
39
 
39
40
  ## Core rules
40
41
 
41
- - Exactly **one current lifecycle state** must apply at a time.
42
- - The lifecycle must fail closed when required evidence is missing, stale, ambiguous, or unparsable.
42
+ <!-- rule: LIFECYCLE-ONE-STATE -->
43
+ `LIFECYCLE-ONE-STATE`: Exactly **one current lifecycle state** MUST apply at a time.
44
+
45
+ - The lifecycle MUST fail closed when required evidence is missing, stale, ambiguous, or unparsable (see [Fail-closed rules](#fail-closed-rules), `LIFECYCLE-FAIL-CLOSED`).
43
46
  - Every gate-crossing decision is for the **current PR head SHA**.
44
47
  - Draft existence alone is **not** draft-gate readiness.
45
- - A PR must clear the draft-stage gate for the current head before Copilot review may be requested.
48
+ - A PR MUST clear the draft-stage gate for the current head before Copilot review may be requested.
46
49
  - Ready -> draft resets the lifecycle back into draft-stage gating.
47
50
  - A merge-blocking marker in the PR **title** (`WIP`/`[WIP]`/`DRAFT`/`DO NOT MERGE`/`🚧`, case-insensitive) blocks the draft -> ready transition and, for non-draft PRs, blocks entry to the pre-approval gate and final approval (`title_marker_blocked`). Markers are permitted only while the PR remains draft. See [Merge preconditions](merge-preconditions.md#title-markers).
48
51
  - Human approval / merge are explicit external waits, not hidden remediation states.
49
52
 
50
53
  ## Two required local gates
51
54
 
52
- Each gate runs an independent review chain with its own disposition ledger, review angles,
53
- and exit conditions. The chains are not interchangeable; see [Checkpoint Review Chain Contract](../../docs/gate-review-sub-loop-contract.md).
55
+ Each gate runs an independent review chain (`GATE-EXEC-SEPARATE-CHAINS`); see
56
+ [Checkpoint Review Chain Contract](../../docs/gate-review-sub-loop-contract.md). Every gate
57
+ pass writes a durable disposition ledger (`GATE-EXEC-DISPOSITION-LEDGER`) before the
58
+ visible comment defined by [Gate Review Comment Contract](../../docs/gate-review-comment-contract.md).
54
59
 
55
60
  ### 1. `draft_gate`
56
61
 
57
- Applies while the PR is draft.
62
+ <!-- term: gate:draft_gate --> Applies while the PR is draft.
58
63
 
59
64
  Purpose:
60
65
  - decide whether the current draft head is materially reviewable
@@ -64,8 +69,6 @@ Purpose:
64
69
  Boundary note:
65
70
  - `draft_gate` governs only the draft -> ready-for-review boundary for the reviewed head
66
71
  - a clean verdict requires no findings at any severity in the gate's `blockCleanOnFindingSeverities` (resolved from config via `resolveGateConfig(config, "draft").blockCleanOnFindingSeverities`)
67
- - every gate pass writes a durable disposition ledger via `write-gate-findings-log.mjs` under `tmp/gate-findings/`
68
- - visible comment schema/evidence rules stay in [Gate Review Comment Contract](../../docs/gate-review-comment-contract.md)
69
72
  - `gates.draft.requireCi=false` does **not** relax `pre_approval_gate`; final approval and merge readiness still require green current-head CI
70
73
 
71
74
  ### 2. `pre_approval_gate`
@@ -77,33 +80,31 @@ This gate uses review angles resolved from config (`resolveGateAngles(config, "p
77
80
  Boundary note:
78
81
  - `pre_approval_gate` governs only final approval readiness for the reviewed head
79
82
  - a clean verdict requires no findings at any severity in the gate's `blockCleanOnFindingSeverities` (resolved from config via `resolveGateConfig(config, "preApproval").blockCleanOnFindingSeverities`)
80
- - every gate pass writes a durable disposition ledger via `write-gate-findings-log.mjs` under `tmp/gate-findings/`
81
83
  - non-draft PRs do not need visible `draft_gate` evidence to enter the post-draft review / `pre_approval_gate` lifecycle; only the draft -> ready transition depends on `draft_gate`
82
- - visible comment schema/evidence rules stay in [Gate Review Comment Contract](../../docs/gate-review-comment-contract.md)
83
84
 
84
85
  ## Lifecycle states
85
86
 
86
- The family-local lifecycle should be modeled in this vocabulary. These state identifiers are part of the stable contract surface for this lifecycle, even if adjacent helper implementations evolve around them:
87
+ The family-local lifecycle SHOULD be modeled in this vocabulary. These state identifiers are part of the stable contract surface for this lifecycle, even if adjacent helper implementations evolve around them:
87
88
 
88
89
  | State | Meaning |
89
90
  |---|---|
90
- | `draft_local_review_gate` | draft PR is at the local draft-stage gate boundary |
91
- | `draft_local_remediation` | draft-stage findings require more local remediation while the PR remains draft |
92
- | `ready_state_needs_copilot_request` | draft gate is clear for the current head; Copilot request is the next legal step |
91
+ | <!-- term: state:draft_local_review_gate --> `draft_local_review_gate` | draft PR is at the local draft-stage gate boundary |
92
+ | <!-- term: state:draft_local_remediation --> `draft_local_remediation` | draft-stage findings require more local remediation while the PR remains draft |
93
+ | <!-- term: state:ready_state_needs_copilot_request --> `ready_state_needs_copilot_request` | draft gate is clear for the current head; Copilot request is the next legal step |
93
94
  | `waiting_for_copilot_review` | Copilot request/re-review is observably in progress for the current head |
94
- | `copilot_feedback_remediation` | unresolved Copilot feedback exists; fixes are the next active step |
95
- | `copilot_reply_resolve_pending` | fixes were applied, but GitHub thread reply/resolve work still remains |
96
- | `merge_conflict_resolution` | current PR head conflicts with base or local reconcile is in progress; resolve conflicts before any further gate progression |
97
- | `final_local_preapproval_gate` | current-head post-Copilot convergence is ready for the final local gate |
98
- | `final_gate_remediation` | Pre-approval gate findings require more remediation after the final gate |
99
- | `waiting_for_human_pr_approval` | local gates are satisfied; waiting for explicit human approval |
100
- | `waiting_for_merge` | approval exists; waiting for merge / merge-triggering external action |
101
- | `terminal_slice_complete` | merged/closed and no further owned step remains |
102
- | `stopped_needs_user_decision` | blocked/ambiguous state requiring explicit human decision |
95
+ | <!-- term: state:copilot_feedback_remediation --> `copilot_feedback_remediation` | unresolved Copilot feedback exists; fixes are the next active step |
96
+ | <!-- term: state:copilot_reply_resolve_pending --> `copilot_reply_resolve_pending` | fixes were applied, but GitHub thread reply/resolve work still remains |
97
+ | <!-- term: state:merge_conflict_resolution --> `merge_conflict_resolution` | current PR head conflicts with base or local reconcile is in progress; resolve conflicts before any further gate progression |
98
+ | <!-- term: state:final_local_preapproval_gate --> `final_local_preapproval_gate` | current-head post-Copilot convergence is ready for the final local gate |
99
+ | <!-- term: state:final_gate_remediation --> `final_gate_remediation` | Pre-approval gate findings require more remediation after the final gate |
100
+ | <!-- term: state:waiting_for_human_pr_approval --> `waiting_for_human_pr_approval` | local gates are satisfied; waiting for explicit human approval |
101
+ | <!-- term: state:waiting_for_merge --> `waiting_for_merge` | approval exists; waiting for merge / merge-triggering external action |
102
+ | <!-- term: state:terminal_slice_complete --> `terminal_slice_complete` | merged/closed and no further owned step remains |
103
+ | <!-- term: state:stopped_needs_user_decision --> `stopped_needs_user_decision` | blocked/ambiguous state requiring explicit human decision |
103
104
 
104
105
  ## Required transitions
105
106
 
106
- At minimum, the lifecycle must enforce these transitions:
107
+ At minimum, the lifecycle MUST enforce these transitions:
107
108
 
108
109
  - `draft_local_review_gate` -> `draft_local_remediation`
109
110
  - blocking `draft_gate` findings
@@ -133,6 +134,8 @@ At minimum, the lifecycle must enforce these transitions:
133
134
  - pre-approval gate findings require changes
134
135
  - `final_local_preapproval_gate` -> `waiting_for_human_pr_approval`
135
136
  - clean current-head `pre_approval_gate` evidence exists
137
+ - `final_gate_remediation` -> `final_local_preapproval_gate`
138
+ - fixes pushed after pre-approval gate findings
136
139
  - `waiting_for_human_pr_approval` -> `waiting_for_merge`
137
140
  - approval arrives
138
141
  - `waiting_for_human_pr_approval` -> `draft_local_review_gate`
@@ -145,17 +148,17 @@ At minimum, the lifecycle must enforce these transitions:
145
148
  - no Copilot request before clean current-head `draft_gate` evidence
146
149
  - no direct skip from fix-applied to Copilot re-request while reply/resolve remains incomplete
147
150
  - no reuse of ready-side or gate evidence after ready -> draft
148
- - a conflicted PR must not be treated as `waiting_for_human_pr_approval`, `waiting_for_merge`, or merge-ready, even if older gate comments and CI were previously green
151
+ - <!-- rule: LIFECYCLE-CONFLICT-BLOCKS-PROGRESS --> `LIFECYCLE-CONFLICT-BLOCKS-PROGRESS`: a conflicted PR MUST NOT be treated as `waiting_for_human_pr_approval`, `waiting_for_merge`, or merge-ready, even if older gate comments and CI were previously green
149
152
  - no implicit fallthrough from approval/merge waits into remediation without a triggering event
150
153
 
151
154
  ## Remediation ownership boundary
152
155
 
153
- The lifecycle must keep the next action class explicit:
156
+ The lifecycle MUST keep the next action class explicit:
154
157
  - draft-stage local findings route to `draft_local_remediation`
155
158
  - unresolved Copilot feedback routes to `copilot_feedback_remediation`
156
159
  - fixes applied but unresolved GitHub reply/resolve work remains route to `copilot_reply_resolve_pending`
157
160
  - pre-approval gate findings route to `final_gate_remediation`
158
- - merge conflicts route to `merge_conflict_resolution` and must be reconciled locally on the PR branch before lifecycle re-entry
161
+ - merge conflicts route to `merge_conflict_resolution` and MUST be reconciled locally on the PR branch before lifecycle re-entry
159
162
  - human approval / merge remain explicit external waits
160
163
 
161
164
  Reviewer-loop reminder:
@@ -164,7 +167,7 @@ Reviewer-loop reminder:
164
167
 
165
168
  ## Required evidence classes
166
169
 
167
- The lifecycle distinguishes two evidence classes:
170
+ The lifecycle distinguishes three evidence classes:
168
171
 
169
172
  1. **observable GitHub state**
170
173
  - PR draft/non-draft/merged/closed state
@@ -176,10 +179,8 @@ The lifecycle distinguishes two evidence classes:
176
179
  - current-head `draft_gate` evidence when draft-gate clearance is required
177
180
  - current-head `pre_approval_gate` evidence when final approval readiness is required
178
181
 
179
- 3. **durable disposition ledger**
180
- - every gate pass logs findings and dispositions under `tmp/gate-findings/<repo-slug>/pr-<N>/`
181
- - the ledger is the durable record of what each gate found and what was decided
182
- - the visible PR comment is a summary; the disposition ledger is the complete record
182
+ 3. **durable disposition ledger** — owned by `GATE-EXEC-DISPOSITION-LEDGER`
183
+ (see [Checkpoint Review Chain Contract](../../docs/gate-review-sub-loop-contract.md#disposition-ledger-and-durable-logging))
183
184
 
184
185
  ### Precedence rules
185
186
 
@@ -189,7 +190,8 @@ The lifecycle distinguishes two evidence classes:
189
190
 
190
191
  ## Fail-closed rules
191
192
 
192
- The lifecycle must stop or reconcile rather than advance when:
193
+ <!-- rule: LIFECYCLE-FAIL-CLOSED -->
194
+ `LIFECYCLE-FAIL-CLOSED`: The lifecycle MUST stop or reconcile rather than advance when:
193
195
  - current head SHA cannot be determined
194
196
  - required current-head `draft_gate` evidence is missing
195
197
  - required current-head `pre_approval_gate` evidence is missing
@@ -202,9 +204,16 @@ The lifecycle must stop or reconcile rather than advance when:
202
204
  - a boundary that is already CI/validation-dependent cannot confirm current-head freshness because the relevant status is pending, none, unknown, or stale
203
205
  - a required visible gate comment could not be confirmed posted
204
206
 
205
- In those cases the workflow must not:
207
+ In those cases the workflow MUST NOT:
206
208
  - leave draft
207
209
  - request or re-request Copilot review
208
210
  - declare final approval readiness
209
211
  - silently fall through to a more permissive state
210
212
 
213
+ ## Cross-references
214
+
215
+ - [Checkpoint Review Chain Contract](../../docs/gate-review-sub-loop-contract.md) — `GATE-EXEC-*` execution-shape rules
216
+ - [Gate Review Comment Contract](../../docs/gate-review-comment-contract.md) — `GATE-COMMENT-*` PR-comment field rules
217
+ - [Merge preconditions](merge-preconditions.md)
218
+ - [Contract style guide](contract-style-guide.md)
219
+
@@ -1,10 +1,10 @@
1
1
  # Public dev-loop contract
2
2
 
3
- This document is the canonical authority for the public `dev-loop` entrypoint, its routed semantics, accepted shorthand, and the rule that internal strategy names stay behind that public façade.
3
+ Canonical owner for the public `dev-loop` entrypoint: routed semantics, accepted shorthand, and the rule that internal strategy names stay behind the façade.
4
4
 
5
5
  This canonical owner lives in the shipped `skills/docs/` surface because installed skill/runtime consumers reliably own the skills subtree. In installed layouts, read the same contract via [Public Dev Loop Contract](../docs/public-dev-loop-contract.md) from the installed skill directory.
6
6
 
7
- Other repo docs may summarize or link this contract, but they should not redefine it.
7
+ Other repo docs MAY summarize or link this contract; they MUST NOT redefine it.
8
8
 
9
9
  ## Public surface
10
10
 
@@ -12,7 +12,7 @@ The single public entrypoint is:
12
12
 
13
13
  - `dev-loop`
14
14
 
15
- It should be callable from the user-facing workflow surfaces, including:
15
+ `dev-loop` MUST be callable from the user-facing workflow surfaces, including:
16
16
 
17
17
  - `subagent dev-loop`
18
18
  - `/skill:dev-loop`
@@ -28,8 +28,6 @@ Day-one user-intent forms:
28
28
  - auto dev loop on issue `<n>`
29
29
  - what state is the dev loop in?
30
30
 
31
- Users should not have to choose `dev-loop` vs internal seam names up front.
32
-
33
31
  ## Issue-based shorthand auto trigger contract
34
32
 
35
33
  This shorthand form is explicitly accepted and resolves to the same bounded public `dev-loop` intent:
@@ -44,7 +42,7 @@ Canonical mapping:
44
42
 
45
43
  Stop-boundary contract for this shorthand:
46
44
 
47
- 1. continue through the normal GitHub/Copilot loop (assignment, PR watch, draft review/fix, Copilot review/fix, and final pre-approval work) unless a genuine stop condition is reached
45
+ 1. continue through the normal GitHub/Copilot loop (assignment, PR watch, draft/Copilot review-fix, final pre-approval) unless a genuine stop condition is reached
48
46
  2. stop at the final human approval decision by default
49
47
  3. after formal approval, stop again in `waiting_for_merge_authorization` unless merge authorization is explicitly granted for the active issue/PR scope
50
48
  4. merge only after explicit merge authorization for the active issue/PR scope
@@ -76,7 +74,8 @@ Use this taxonomy consistently across docs, discovery surfaces, and tests:
76
74
 
77
75
  Any remaining specialized Copilot behavior stays internal-only behind `dev-loop`.
78
76
 
79
- Regression tests must fail if this taxonomy drifts in wording or surfaced entrypoint assets.
77
+ <!-- rule: FACADE-TAXONOMY-DRIFT-TEST -->
78
+ `FACADE-TAXONOMY-DRIFT-TEST`: Regression tests MUST fail if this taxonomy drifts in wording or surfaced entrypoint assets.
80
79
 
81
80
  ## Canonical current state
82
81
 
@@ -90,17 +89,7 @@ The public router consumes one canonical current state with these top-level dime
90
89
  | `status` | `active` \| `waiting` \| `blocked` \| `approval_ready` \| `merge_ready` \| `done` |
91
90
  | `authorization` | `authorized` \| `needs_confirmation` \| `not_authorized` |
92
91
 
93
- The authoritative first-slice evaluator is:
94
-
95
- - `packages/core/src/loop/public-dev-loop-routing.mjs`
96
-
97
- Authoritative status-report helper:
98
-
99
- - `resolveAuthoritativeDevLoopStatus()` in `packages/core/src/loop/public-dev-loop-routing.mjs`
100
-
101
- Authoritative startup/resume bundle helper:
102
-
103
- - `resolveAuthoritativeStartupResumeBundle()` in `packages/core/src/loop/public-dev-loop-routing.mjs`
92
+ The authoritative first-slice evaluator, status-report helper (`resolveAuthoritativeDevLoopStatus()`), and startup/resume bundle helper (`resolveAuthoritativeStartupResumeBundle()`) all live in `packages/core/src/loop/public-dev-loop-routing.mjs`.
104
93
 
105
94
  Its tests are:
106
95
 
@@ -118,7 +107,8 @@ Before answering status/progress/readiness/merge-state/next-step questions, cons
118
107
 
119
108
  Prior chat context is only a hint, never state authority.
120
109
 
121
- If authoritative identity/state (including issue↔PR linkage when relevant) cannot be resolved confidently, fail closed to reconcile/unknown instead of guessing.
110
+ <!-- rule: FACADE-STATUS-AUTHORITATIVE-FAIL-CLOSED -->
111
+ `FACADE-STATUS-AUTHORITATIVE-FAIL-CLOSED`: If authoritative identity/state (including issue↔PR linkage when relevant) cannot be resolved confidently, consumers MUST fail closed to reconcile/unknown instead of guessing.
122
112
  For async/durable-auto flows, do not claim that `dev-loop` has started or is running unless a visible Pi-managed async run id has also been resolved.
123
113
 
124
114
  When the routed next step requires confirmation for a mutation, the status/startup next action should name that concrete pending mutation (for example issue assignment to `copilot-swe-agent`) instead of generic "approval gate" wording.
@@ -140,10 +130,8 @@ Required authoritative inputs:
140
130
  - `auto_continue_current` always resolves to `durable_auto`
141
131
  - `issueLinkageResolution` (`resolved_linked_pr` \| `resolved_no_open_pr` \| `not_applicable`)
142
132
  - required when `currentState.target.kind === issue`
143
- - `issueReadiness` (`ready` \| `needs_clarification` \| `not_applicable`)
144
- - required for Copilot-first issue targets with `issueLinkageResolution=resolved_no_open_pr`
145
- - `issueAssignmentState` (`unassigned` \| `assigned_to_copilot` \| `not_applicable`)
146
- - required for Copilot-first issue targets with `issueLinkageResolution=resolved_no_open_pr`
133
+ - `issueReadiness` (`ready` \| `needs_clarification` \| `not_applicable`) and `issueAssignmentState` (`unassigned` \| `assigned_to_copilot` \| `not_applicable`)
134
+ - both required for Copilot-first issue targets with `issueLinkageResolution=resolved_no_open_pr`
147
135
  - `artifactState` (`open` \| `closed` \| `merged` \| `not_applicable`)
148
136
  - explicit resolved `loopState` (`unknown` is not authoritative input)
149
137
  - required for async/durable-auto startup or status paths: `asyncRun`
@@ -151,8 +139,8 @@ Required authoritative inputs:
151
139
  - durable-auto success requires `kind=pi_managed_run`, a non-empty visible `runId`, and `visible=true`
152
140
  - when `inspectionState` is provided as `hidden`, `stale`, or `uninspectable`, durable-auto must fail closed with that state surfaced in diagnostics
153
141
  - detached local processes are diagnostic-only evidence and must fail closed instead of being treated as a successful async start
154
- - when refreshed loop state is `linked_pr_ready_for_followup` for an issue target with a resolved linked PR, startup/resume and status resolution must promote stale bootstrap waiting to the linked PR follow-up path (or fail closed if the linked-PR facts are incomplete/contradictory) instead of preserving the old bootstrap wait route
155
- - when refreshed loop state is `prior_linked_pr_closed_unmerged` for a Copilot-owned issue target with `issueLinkageResolution=resolved_no_open_pr`, startup/resume and status resolution must fail closed to reconcile instead of treating the issue as a healthy bootstrap wait or fresh issue-intake path
142
+ - refreshed `linked_pr_ready_for_followup` for an issue target with a resolved linked PR: promote stale bootstrap waiting to the linked PR follow-up path, or fail closed if the linked-PR facts are incomplete/contradictory, instead of preserving the old bootstrap wait route
143
+ - refreshed `prior_linked_pr_closed_unmerged` for a Copilot-owned issue target with `issueLinkageResolution=resolved_no_open_pr`: fail closed to reconcile instead of treating the issue as a healthy bootstrap wait or fresh issue-intake path
156
144
 
157
145
  Resolved bundle output shape:
158
146
 
@@ -222,8 +210,8 @@ Resolved bundle output shape:
222
210
 
223
211
  Dev-mode observability requirement:
224
212
 
225
- - saved artifacts must preserve the `contractTrace` decision, wait strategy, state-refresh boundary, and stop classification so a fresh session can explain why a healthy wait re-attached, stopped, or failed closed without replaying the whole run
226
- - wait/watch artifacts must record the effective timeout budget in force and whether the seam ran as `persistent_watch` or `one_shot_probe`; when a surface does not own a poll interval directly it may record `effectivePollIntervalMs=null` rather than inventing a value
213
+ - saved artifacts MUST preserve the `contractTrace` decision, wait strategy, state-refresh boundary, and stop classification so a fresh session can explain a re-attach, stop, or fail-closed without replaying the run
214
+ - wait/watch artifacts MUST record the effective timeout budget and whether the seam ran as `persistent_watch` or `one_shot_probe`; a surface without a poll interval MAY record `effectivePollIntervalMs=null` instead of inventing one
227
215
 
228
216
  Fail-closed semantics:
229
217
 
@@ -271,7 +259,7 @@ Internal strategy naming is implementation detail; normal orchestration always s
271
259
 
272
260
  Tracker-backed local implementation is an input-source addition to the existing `local_implementation` strategy. It does **not** create a new routing mode, strategy family, or public workflow entrypoint.
273
261
 
274
- For tracker-backed local sessions, the tracker issue is canonical. `docs/phases/phase-<n>.md` must not exist for that same session, and local execution must not maintain a second durable phase-doc copy of the same spec.
262
+ For tracker-backed local sessions, the tracker issue is canonical; the no-duplicate-phase-doc rule is owned by `ARTIFACT-TRACKER-FIRST-NO-DUP` in [Artifact Authority Contract](artifact-authority-contract.md).
275
263
 
276
264
  Deterministic GitHub-backed spec resolution:
277
265
 
@@ -284,13 +272,13 @@ Deterministic GitHub-backed spec resolution:
284
272
  State-sync expectations for this slice:
285
273
 
286
274
  - local branch state and `tmp/` artifacts remain local execution state
287
- - durable scope / acceptance / status changes discovered during local execution should sync back to the tracker issue, because the tracker issue remains the canonical spec source for tracker-backed sessions
275
+ - durable scope / acceptance / status changes discovered during local execution SHOULD sync back to the tracker issue
288
276
  - this slice does **not** introduce full bidirectional tracker sync or tracker-provider adapters beyond the bounded GitHub-backed helper path above
289
277
 
290
278
  Non-duplication rule:
291
279
 
292
280
  - do not create, read, or update `docs/phases/phase-<n>.md` for the same tracker-backed session
293
- - if a duplicate local phase doc already exists for the same tracker-backed session, reconcile that conflict explicitly before continuing; do not silently keep two durable spec surfaces alive
281
+ - if a duplicate local phase doc already exists, reconcile explicitly before continuing rather than keeping two durable spec surfaces alive
294
282
 
295
283
  ## Copilot-first issue-assignment seam (unassigned issues)
296
284
 
@@ -330,7 +318,7 @@ For issue targets, authoritative issue↔PR linkage resolution remains part of s
330
318
 
331
319
  - when canonical issue state includes `linkedPr`, route selection first uses that linked PR as the authoritative routable artifact
332
320
  - when canonical issue state does **not** include `linkedPr`, status/reporting consumers must still require explicit authoritative linkage resolution before asserting there is no open linked PR
333
- - when authoritative linkage resolves an already-open linked PR, that PR is the only canonical active artifact for the issue during follow-up; startup/status/follow-up must reuse it and fail closed against opening another PR until the prior state is explicitly reconciled
321
+ - <!-- rule: FACADE-LINKED-PR-SINGLE-ARTIFACT --> `FACADE-LINKED-PR-SINGLE-ARTIFACT`: when authoritative linkage resolves an already-open linked PR, that PR is the only canonical active artifact for the issue during follow-up; startup/status/follow-up MUST reuse it and MUST fail closed against opening another PR until the prior state is explicitly reconciled
334
322
 
335
323
  ## Deterministic routing order
336
324
 
@@ -349,6 +337,28 @@ First-match-wins routing posture:
349
337
  11. PR owned by Copilot -> `copilot_pr_followup`
350
338
  12. anything else -> fail closed to `needs_reconcile`
351
339
 
340
+ ## Required transitions
341
+
342
+ The gate graph (`DEV_LOOP_GATE` / `PUBLIC_DEV_LOOP_GATE_CONTRACT` in
343
+ `public-dev-loop-routing.mjs`) is stateless per cycle: each `evaluatePublicDevLoopRouting`
344
+ call re-derives one gate from fresh authoritative state, so every non-terminal (route/wait)
345
+ gate can be followed, on the next cycle, by any of the gates.
346
+
347
+ - `final_approval` -> any dev-loop gate
348
+ - `wait_watch` -> any dev-loop gate
349
+ - `local_implementation` -> any dev-loop gate
350
+ - `issue_intake` -> any dev-loop gate
351
+ - `external_pr_followup` -> any dev-loop gate
352
+ - `reviewer_fixer` -> any dev-loop gate
353
+ - `copilot_pr_followup` -> any dev-loop gate
354
+
355
+ Terminal gates (`stop_blocked_or_not_authorized`, `stop_done_terminal`,
356
+ `waiting_for_merge_authorization`, `fail_closed_reconcile`) have no outgoing transitions —
357
+ reaching one ends the current evaluation cycle. Their route-kind classification
358
+ (`stop` / `needs_reconcile`) is the authoritative terminal marker; the route/wait gates above
359
+ are the authoritative non-terminal set. This machine is wired into the L2/L3 state-machine
360
+ conformance harness (`validate-state-machine-conformance.mjs`).
361
+
352
362
  ## Conflict reconciliation path (`CONFLICTING` / `DIRTY`)
353
363
 
354
364
  When an open linked PR reports merge conflict against `main`, treat this as an explicit bounded local-agent reconciliation path, not as a blind merge/update step:
@@ -360,27 +370,33 @@ When an open linked PR reports merge conflict against `main`, treat this as an e
360
370
  - issue/PR scope and acceptance criteria
361
371
  - current-head gate evidence and relevant unresolved review feedback
362
372
  - local validation surface for the touched conflict slice
363
- 3. if required authoritative context is missing, stale for the current head, or contradictory, fail closed to reconcile
373
+ 3. <!-- rule: FACADE-CONFLICT-CONTEXT-FAIL-CLOSED --> `FACADE-CONFLICT-CONTEXT-FAIL-CLOSED`: if required authoritative context is missing, stale for the current head, or contradictory, orchestration MUST fail closed to reconcile
364
374
  4. only when that context is complete for one current head, resolve the conflict locally on the PR branch
365
- 5. after conflict resolution, rerun required local validation, gate checks, and required CI checks for the new head before approval/merge evaluation
375
+ 5. <!-- rule: FACADE-CONFLICT-REVALIDATE-NEW-HEAD --> `FACADE-CONFLICT-REVALIDATE-NEW-HEAD`: after conflict resolution, orchestration MUST rerun required local validation, gate checks, and required CI checks for the new head before approval/merge evaluation
366
376
 
367
377
  ## `auto dev loop` durable auto contract
368
378
 
369
- When the public intent is `auto dev loop`, the router must:
379
+ When the public intent is `auto dev loop`, the router MUST:
370
380
 
371
381
  1. require canonical current state resolution first
372
382
  2. route to the same detected internal strategy as normal state-based routing
373
383
  3. mark execution mode as durable auto ownership (`durable_auto`)
374
384
  4. keep waiting/watch states in healthy-wait semantics (`auto_healthy_wait`)
375
385
 
376
- In healthy waiting states, quiet watcher observations (for example `timeout` or `idle`) are observational only and must not be surfaced as attention by themselves. Escalation is still expected for true blocked/authorization/reconcile states.
386
+ In healthy waiting states, quiet watcher observations (for example `timeout` or `idle`) are observational only and MUST NOT be surfaced as attention by themselves. Escalation is still expected for true blocked/authorization/reconcile states.
377
387
 
378
- For the Copilot-first bootstrap seam (`waiting_for_initial_copilot_implementation`), durable-auto ownership must route to the dedicated `watch-initial-copilot-pr.mjs` watcher with its default 1-hour watch budget. Quiet/no-activity observations alone do not eject durable ownership while refreshed authoritative state still resolves `waiting_for_initial_copilot_implementation`; inspect/status intents may still summarize that state and exit normally. This seam has a bootstrap-only exception to the general blocked escalation rule: when the linked PR is still bootstrap-only, approval-gated Actions/Copilot runs in `action_required` (GitHub Actions run conclusion, not a lifecycle state term) are treated as non-blocking observational signals (surfacing as concluded session activity) and do not by themselves force stop/escalation.
379
- When refreshed authoritative bootstrap state instead resolves `prior_linked_pr_closed_unmerged`, that is not a healthy wait seam: the routed outcome must fail closed to reconcile so status/startup answers surface the prior closed-unmerged PR decision rather than implying normal watch continuity.
388
+ Bootstrap-only exception to the general blocked-escalation rule for `waiting_for_initial_copilot_implementation`:
380
389
 
381
- When that refreshed seam state advances to `linked_pr_ready_for_followup`, durable-auto continuation must re-enter the same linked PR follow-up path. If the follow-up handoff carries `conductorRouting.handoffEnvelope.requiresLocalIsolation=true`, orchestration should continue through an isolated checkout/worktree transition instead of treating that boundary as final completion.
390
+ | Rule ID | Condition | Outcome |
391
+ |---|---|---|
392
+ | <!-- rule: FACADE-BOOTSTRAP-WATCH-ROUTE --> `FACADE-BOOTSTRAP-WATCH-ROUTE` | durable-auto ownership of this seam | ownership MUST route to the dedicated `watch-initial-copilot-pr.mjs` watcher with its default 1-hour watch budget |
393
+ | <!-- rule: FACADE-BOOTSTRAP-QUIET-NO-EJECT --> `FACADE-BOOTSTRAP-QUIET-NO-EJECT` | quiet/no-activity observation while refreshed state still resolves this seam | durable ownership MUST NOT be ejected; inspect/status intents MAY still summarize that state and exit normally |
394
+ | <!-- rule: FACADE-BOOTSTRAP-ACTION-REQUIRED-NONBLOCKING --> `FACADE-BOOTSTRAP-ACTION-REQUIRED-NONBLOCKING` | bootstrap-only linked PR; approval-gated Actions/Copilot run reports `action_required` (a run conclusion, not a lifecycle state) | treated as a non-blocking observational signal (concluded session activity); MUST NOT by itself force stop/escalation |
395
+ | <!-- rule: FACADE-BOOTSTRAP-CLOSED-UNMERGED-RECONCILE --> `FACADE-BOOTSTRAP-CLOSED-UNMERGED-RECONCILE` | refreshed bootstrap state resolves `prior_linked_pr_closed_unmerged` | MUST fail closed to reconcile so status/startup surfaces the prior closed-unmerged decision instead of normal watch continuity |
396
+ | <!-- rule: FACADE-BOOTSTRAP-FOLLOWUP-REENTRY --> `FACADE-BOOTSTRAP-FOLLOWUP-REENTRY` | refreshed seam state advances to `linked_pr_ready_for_followup` | durable-auto continuation MUST re-enter the same linked PR follow-up path |
397
+ | <!-- rule: FACADE-BOOTSTRAP-ISOLATED-WORKTREE-CONTINUATION --> `FACADE-BOOTSTRAP-ISOLATED-WORKTREE-CONTINUATION` | follow-up handoff carries `conductorRouting.handoffEnvelope.requiresLocalIsolation=true` | orchestration SHOULD continue through an isolated checkout/worktree transition rather than treat that boundary as final completion (the runtime surfaces the flag; it does not enforce re-entry) |
382
398
 
383
- Main conductor orchestration must treat non-terminal follow-up/wait states (for example `waiting_for_copilot_review`) as continuation boundaries rather than clean completion. If an async child exits before the requested stop boundary and continuation is feasible, re-dispatch via the main session driver (the subagent exits on external wait; the main session re-dispatches); otherwise surface the concrete blocker.
399
+ Main conductor orchestration MUST treat non-terminal follow-up/wait states (for example `waiting_for_copilot_review`) as continuation boundaries rather than clean completion. If an async child exits before the requested stop boundary and continuation is feasible, re-dispatch via the main session driver (the subagent exits on external wait; the main session re-dispatches); otherwise surface the concrete blocker.
384
400
 
385
401
  ## Internal / external model
386
402
 
@@ -413,9 +429,9 @@ flowchart TD
413
429
 
414
430
  - `dev-loop` is the only intended public workflow entrypoint.
415
431
  - any remaining specialized Copilot behavior is internal-only and non-user-invocable behind the canonical internal route-pack surface (`issue-intake`, `copilot-pr-followup`, `local-implementation`, `final-approval`).
416
- - Documentation and examples should lead with `dev-loop` and explain routed behavior.
417
- - Almost all workflow branching should converge into deterministic state-machine/tooling surfaces behind `dev-loop`.
418
- - User-visible variation should be expressed through the external `dev-loop` API / bounded parameters or settings, not by preserving multiple public workflow names or legacy compatibility seams.
432
+ - Documentation and examples SHOULD lead with `dev-loop` and explain routed behavior.
433
+ - Workflow branching SHOULD converge into deterministic state-machine/tooling surfaces behind `dev-loop`.
434
+ - User-visible variation SHOULD be expressed through the `dev-loop` API/parameters or settings, not multiple public workflow names or legacy compatibility seams.
419
435
 
420
436
  ## Bounded variation parameter contract
421
437
 
@@ -437,7 +453,7 @@ Any conflict that would materially change artifact identity, ownership truth, or
437
453
  | `mode` | `bounded_handoff` (default) \| `durable_auto` | Steers execution mode; `durable_auto` uses the same durable-auto execution-mode semantics as `auto_continue_current`, without replacing the selected intent |
438
454
  | `watch` | boolean | Explicitly request wait/watch semantics; fails closed for otherwise-successful non-wait routed results, while preserving authoritative `stop` and `needs_reconcile` outcomes |
439
455
  | `intent` | any existing public `dev-loop` intent | Disambiguates the supported public intent; maps to existing contract values |
440
- | `targetPreference` | `prefer_github_first` (default) \| `prefer_local` | Steers routing preference; must not override authoritative linked-PR or active-artifact truth |
456
+ | `targetPreference` | `prefer_local` (default) \| `prefer_github_first` | Steers routing preference; must not override authoritative linked-PR or active-artifact truth |
441
457
 
442
458
  The bounded allow-list is exported from `packages/core/src/loop/public-dev-loop-routing.mjs` as `DEV_LOOP_VARIATION_PARAMETER_CONTRACT`.
443
459
 
@@ -461,7 +477,7 @@ The following parameter/state combinations fail closed to `needs_reconcile` inst
461
477
  | `mode=bounded_handoff` + `intent=auto_continue_current` | `auto_continue_current` always requires durable auto execution mode |
462
478
  | Unrecognized `mode` value | Value not on the bounded allow-list |
463
479
  | Unrecognized `targetPreference` value | Value not on the bounded allow-list |
464
- | `watch=true` when an otherwise-successful routed result is not wait/watch-eligible | Watch semantics require a routed wait result (`routeKind=wait`), not just `selectedGate=wait_watch`; existing `stop` and `needs_reconcile` outcomes stay authoritative |
480
+ | `watch=true` when an otherwise-successful routed result is not wait/watch-eligible | Watch semantics require a routed wait result (`routeKind=wait`), not just `selectedGate=wait_watch`; `stop`/`needs_reconcile` outcomes stay authoritative |
465
481
  | Non-boolean `watch` value | Value is outside the bounded boolean allow-list and must fail closed |
466
482
  | `targetPreference=prefer_local` when authoritative state has a linked PR or active PR artifact | Preference must not override authoritative PR/linked-PR active artifact truth |
467
483
  | `mode=durable_auto` without authoritative current state | Durable auto requires authoritative current state to route from |