dev-loops 0.7.1 → 0.8.0

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 (107) hide show
  1. package/.claude/.claude-plugin/plugin.json +1 -1
  2. package/.claude/agents/dev-loop.md +7 -7
  3. package/.claude/agents/fixer.md +1 -0
  4. package/.claude/agents/refiner.md +4 -4
  5. package/.claude/agents/review.md +10 -13
  6. package/.claude/commands/loop-continue.md +2 -1
  7. package/.claude/commands/loop-enqueue.md +9 -2
  8. package/.claude/commands/loop-info.md +1 -1
  9. package/.claude/commands/loop-start-spike.md +1 -1
  10. package/.claude/hooks/_bash-command-classify.mjs +7 -6
  11. package/.claude/hooks/_hook-decisions.mjs +5 -4
  12. package/.claude/skills/copilot-pr-followup/SKILL.md +42 -28
  13. package/.claude/skills/dev-loop/SKILL.md +8 -8
  14. package/.claude/skills/docs/acceptance-criteria-verification.md +13 -4
  15. package/.claude/skills/docs/anti-patterns.md +6 -5
  16. package/.claude/skills/docs/artifact-authority-contract.md +17 -14
  17. package/.claude/skills/docs/confirmation-rules.md +2 -1
  18. package/.claude/skills/docs/contract-style-guide.md +37 -0
  19. package/.claude/skills/docs/copilot-loop-operations.md +21 -15
  20. package/.claude/skills/docs/cross-harness-regression-contract.md +2 -2
  21. package/.claude/skills/docs/debt-remediation-contract.md +1 -1
  22. package/.claude/skills/docs/epic-tree-refinement-procedure.md +25 -22
  23. package/.claude/skills/docs/issue-intake-procedure.md +37 -22
  24. package/.claude/skills/docs/merge-preconditions.md +17 -13
  25. package/.claude/skills/docs/pr-lifecycle-contract.md +45 -36
  26. package/.claude/skills/docs/public-dev-loop-contract.md +61 -44
  27. package/.claude/skills/docs/retrospective-checkpoint-contract.md +25 -9
  28. package/.claude/skills/docs/spike-mode-contract.md +14 -7
  29. package/.claude/skills/docs/stop-conditions.md +30 -15
  30. package/.claude/skills/docs/tracker-first-loop-state.md +13 -8
  31. package/.claude/skills/docs/validation-policy.md +4 -5
  32. package/.claude/skills/local-implementation/SKILL.md +49 -143
  33. package/.claude/skills/loop-grill/SKILL.md +34 -14
  34. package/AGENTS.md +1 -1
  35. package/CHANGELOG.md +36 -0
  36. package/README.md +95 -189
  37. package/agents/dev-loop.agent.md +8 -8
  38. package/agents/fixer.agent.md +1 -0
  39. package/agents/refiner.agent.md +4 -4
  40. package/agents/review.agent.md +10 -13
  41. package/extension/README.md +5 -4
  42. package/package.json +7 -5
  43. package/scripts/_core-helpers.mjs +2 -0
  44. package/scripts/claude/headless-dev-loop.mjs +1 -1
  45. package/scripts/docs/validate-rule-ownership.mjs +442 -0
  46. package/scripts/docs/validate-state-machine-conformance.mjs +1169 -0
  47. package/scripts/github/_gate-names.mjs +5 -0
  48. package/scripts/github/_review-thread-mutations.mjs +5 -2
  49. package/scripts/github/capture-review-threads.mjs +2 -2
  50. package/scripts/github/create-pr.mjs +119 -10
  51. package/scripts/github/detect-checkpoint-evidence.mjs +109 -24
  52. package/scripts/github/edit-issue.mjs +259 -0
  53. package/scripts/github/list-review-threads.mjs +277 -0
  54. package/scripts/github/post-gate-findings.mjs +6 -3
  55. package/scripts/github/probe-ci-status.mjs +18 -0
  56. package/scripts/github/probe-copilot-review.mjs +24 -3
  57. package/scripts/github/reconcile-draft-gate.mjs +13 -13
  58. package/scripts/github/request-copilot-review.mjs +109 -42
  59. package/scripts/github/upsert-checkpoint-verdict.mjs +98 -27
  60. package/scripts/github/verify-briefing-prefixes.mjs +382 -0
  61. package/scripts/github/verify-fresh-review-context.mjs +78 -3
  62. package/scripts/github/wait-pr-checks.mjs +171 -0
  63. package/scripts/github/write-gate-context.mjs +220 -10
  64. package/scripts/github/write-gate-findings-log.mjs +54 -2
  65. package/scripts/loop/_post-convergence-change.mjs +2 -2
  66. package/scripts/loop/_pr-runner-coordination.mjs +112 -13
  67. package/scripts/loop/check-retro-tooling.mjs +14 -9
  68. package/scripts/loop/copilot-pr-handoff.mjs +47 -16
  69. package/scripts/loop/detect-change-scope.mjs +2 -2
  70. package/scripts/loop/detect-copilot-loop-state.mjs +34 -14
  71. package/scripts/loop/detect-internal-only-pr.mjs +6 -6
  72. package/scripts/loop/detect-pr-gate-coordination-state.mjs +152 -18
  73. package/scripts/loop/detect-refinement-grill-state.mjs +136 -0
  74. package/scripts/loop/resolve-dev-loop-startup.mjs +145 -8
  75. package/scripts/loop/run-watch-cycle.mjs +42 -7
  76. package/scripts/loop/sanctioned-commands.mjs +3 -0
  77. package/scripts/loop/validate-pr-body-spec.mjs +21 -5
  78. package/scripts/pages/build-state-atlas.mjs +65 -48
  79. package/scripts/projects/_resolve-project.mjs +1 -148
  80. package/scripts/projects/add-queue-item.mjs +87 -4
  81. package/scripts/projects/list-queue-items.mjs +3 -377
  82. package/scripts/projects/move-queue-item.mjs +3 -410
  83. package/scripts/projects/reorder-queue-item.mjs +3 -22
  84. package/skills/copilot-pr-followup/SKILL.md +42 -28
  85. package/skills/dev-loop/SKILL.md +3 -3
  86. package/skills/docs/acceptance-criteria-verification.md +13 -4
  87. package/skills/docs/anti-patterns.md +6 -5
  88. package/skills/docs/artifact-authority-contract.md +17 -14
  89. package/skills/docs/confirmation-rules.md +2 -1
  90. package/skills/docs/contract-style-guide.md +37 -0
  91. package/skills/docs/copilot-loop-operations.md +21 -15
  92. package/skills/docs/cross-harness-regression-contract.md +2 -2
  93. package/skills/docs/debt-remediation-contract.md +1 -1
  94. package/skills/docs/epic-tree-refinement-procedure.md +25 -22
  95. package/skills/docs/issue-intake-procedure.md +37 -22
  96. package/skills/docs/merge-preconditions.md +17 -13
  97. package/skills/docs/pr-lifecycle-contract.md +45 -36
  98. package/skills/docs/public-dev-loop-contract.md +61 -44
  99. package/skills/docs/required-rules.json +165 -0
  100. package/skills/docs/retrospective-checkpoint-contract.md +25 -9
  101. package/skills/docs/spike-mode-contract.md +14 -7
  102. package/skills/docs/stop-conditions.md +30 -15
  103. package/skills/docs/tracker-first-loop-state.md +13 -8
  104. package/skills/docs/validation-policy.md +4 -5
  105. package/skills/local-implementation/SKILL.md +49 -143
  106. package/skills/loop-grill/SKILL.md +38 -17
  107. package/scripts/docs/validate-no-duplicate-rules.mjs +0 -250
@@ -1,6 +1,6 @@
1
1
  # Copilot loop operations
2
2
 
3
- This document is the canonical operational reference for the deterministic Copilot PR follow-up state machine used by the routed `copilot_pr_followup`, `wait_watch`, `reviewer_fixer`, and `final_approval` paths behind `dev-loop`.
3
+ Canonical owner for operating the deterministic Copilot PR follow-up state machine the operational reference for the routed `copilot_pr_followup`, `wait_watch`, `reviewer_fixer`, and `final_approval` paths behind `dev-loop`. The machine's states and transitions are defined by [Copilot Loop State Graph](../../docs/copilot-loop-state-graph.md).
4
4
 
5
5
  Use it together with:
6
6
  - [Copilot PR Follow-up Skill](../copilot-pr-followup/SKILL.md)
@@ -25,18 +25,17 @@ Use the machines to answer:
25
25
  - what the next required action is
26
26
  - when to stop instead of guessing
27
27
 
28
- Each machine captures an observable snapshot from GitHub facts (plus explicit bounded local loop
29
- metadata when required) and interprets it into exactly one current state plus allowed next
30
- transitions. In the `dev-loops` source repository, the supporting source-authority references are [Copilot Loop State Graph](../../docs/copilot-loop-state-graph.md) and [Reviewer Loop State Graph](../../docs/reviewer-loop-state-graph.md) under `../../docs/` relative to `skills/copilot-pr-followup/SKILL.md`. Treat those links as source-repo references, not bundled installed-skill docs.
28
+ Each machine's snapshot-to-state mapping is defined in its owner doc (see the Overview of
29
+ [Copilot Loop State Graph](../../docs/copilot-loop-state-graph.md) and
30
+ [Reviewer Loop State Graph](../../docs/reviewer-loop-state-graph.md)), under `../../docs/`
31
+ relative to `skills/copilot-pr-followup/SKILL.md` in the `dev-loops` source repository. Treat
32
+ those links as source-repo references, not bundled installed-skill docs.
31
33
 
32
34
  For tracker-first MVP `story -> PR -> tracker sync` work, the source-repo reference is [Tracker-First Story-to-PR Contract](../../docs/tracker-story-pr-contract.md). That source doc inherits source-of-truth ownership, the required work item <-> PR link, and reverse-sync semantics from `#21`; it only adds the mutually exclusive workflow-family states and post-merge sync-verification states for this narrower MVP slice.
33
35
 
34
36
  ## Key guarantees from the state machine
35
37
 
36
- - `unresolvedThreadCount > 0` always routes to fix/reply-resolve never to a wait/watch state
37
- - `snapshot.copilotReviewRequestStatus === "unavailable"` or `snapshot.copilotReviewRequestStatus === "failed"` routes to a terminal stop state — never to sleep or watch
38
- - `agentFixStatus === "applied"` with unresolved threads routes to `already_fixed_needs_reply_resolve` — reply/resolve on GitHub is required before re-requesting review
39
- - Copilot being in `requested_reviewers` (`"requested"` or `"already-requested"`) routes to `waiting_for_copilot_review`
38
+ These routing guarantees are owned by [Copilot Loop State Graph](../../docs/copilot-loop-state-graph.md); see `COPILOT-STATE-UNRESOLVED-PRIORITY`, `COPILOT-STATE-TERMINAL-STOP`, `COPILOT-STATE-REPLY-BEFORE-REREQUEST`, and `COPILOT-STATE-ACTIVE-REQUEST-WAIT` there for the routing rules driving `unresolvedThreadCount`, `copilotReviewRequestStatus`, and `agentFixStatus`.
40
39
 
41
40
  ## How to use the state machine in practice
42
41
 
@@ -51,7 +50,7 @@ For tracker-first MVP `story -> PR -> tracker sync` work, the source-repo refere
51
50
 
52
51
  4. Branch on the detector output instead of inventing a polling loop:
53
52
  - `state=waiting_for_copilot_review` with `snapshot.copilotReviewOnCurrentHead=false`: do **not** poll manually; either run `node <resolved-skill-scripts>/loop/run-watch-cycle.mjs --repo <owner/name> --pr <number>` for persistent async waiting or report the wait state and resume later after the single detector call
54
- - `state=waiting_for_ci` with `snapshot.ciStatus` in `{ "pending", "none" }`: do **not** poll manually by default; use `dev-loops loop watch-ci --repo <owner/name> --pr <number>` to block-wait on the combined check/status state (provider-agnostic — CircleCI, GitHub Actions, and any external commit-status / check-run). `gh run watch <run-id>` is an Actions-only fallback when the current-head run id is already known and you know the gating checks are GitHub Actions. Either way, on `timeout`/`changed` report pending CI and resume later after the single detector refresh. Bounded exception: if GitHub created zero current-head check suites/statuses, the previous head rollup was green, and local `npm run verify` already passed for the same current head, rerun `detect-copilot-loop-state.mjs` with `--local-validation-head-sha <current-head-sha>` so the detector can promote that exact zero-suite case to `snapshot.ciStatus="crediblyGreen"` instead of waiting forever on raw `none`.
53
+ - `state=waiting_for_ci` with `snapshot.ciStatus` in `{ "pending", "none" }`: do **not** poll manually by default; use `dev-loops loop watch-ci --repo <owner/name> --pr <number>` or `node <resolved-skill-scripts>/github/wait-pr-checks.mjs --repo <owner/name> --pr <number>` (settle-blocking with a 0/1/2 exit contract) to block-wait on the combined check/status state (provider-agnostic — CircleCI, GitHub Actions, and any external commit-status / check-run). `gh run watch <run-id>` is an Actions-only fallback when the current-head run id is already known and you know the gating checks are GitHub Actions. Either way, on `timeout`/`changed` report pending CI and resume later after the single detector refresh. Bounded exception: if GitHub created zero current-head check suites/statuses, the previous head rollup was green, and local `npm run verify` already passed for the same current head, rerun `detect-copilot-loop-state.mjs` with `--local-validation-head-sha <current-head-sha>` so the detector can promote that exact zero-suite case to `snapshot.ciStatus="crediblyGreen"` instead of waiting forever on raw `none`.
55
54
  - `snapshot.ciStatus="failure"` remains a stop/fix state, never a wait loop
56
55
 
57
56
  5. For reviewer-side draft-review work, run `node <resolved-skill-scripts>/loop/detect-reviewer-loop-state.mjs --repo <owner/name> --pr <number> [--reviewer-login <login>] [--local-state <path>]`.
@@ -64,10 +63,7 @@ For tracker-first MVP `story -> PR -> tracker sync` work, the source-repo refere
64
63
 
65
64
  ## Judgment calls that remain in the agent layer
66
65
 
67
- - Whether a comment should be accepted, deferred, or disagreed with
68
- - Whether the code change is already sufficient (→ sets `agentFixStatus: "applied"`)
69
- - What the narrowest valid fix is
70
- - Whether another Copilot pass is desired (→ triggers re-request or selects `done`)
66
+ See [Copilot Loop State Graph](../../docs/copilot-loop-state-graph.md)'s "Agent judgment boundary" for the bounded list of decisions the state machine leaves to the agent.
71
67
 
72
68
  ## Workflow overview
73
69
 
@@ -102,7 +98,7 @@ Useful checks:
102
98
 
103
99
  If the user asks for status/progress/readiness/merge-state/next-step (including “what is next”):
104
100
  - resolve authoritative active artifact identity first (issue/PR, plus branch/head SHA when useful)
105
- - for issue targets, do not assert "no open PR" until authoritative issue↔PR linkage is resolved via the startup resolver (`dev-loops loop startup --issue <number>`, run inside the `dev-loop` async subagent) do not run `detect-linked-issue-pr.mjs` manually
101
+ - for issue targets, resolve authoritative issue↔PR linkage via the startup resolver (`dev-loops loop startup --issue <number>`, run inside the `dev-loop` async subagent) rather than running `detect-linked-issue-pr.mjs` manually; the fail-closed-until-resolved requirement is owned by `FACADE-STATUS-AUTHORITATIVE-FAIL-CLOSED` in [Public Dev Loop Contract](./public-dev-loop-contract.md)
106
102
  - resolve artifact state (`open`/`closed`/`merged`/`not_applicable`)
107
103
  - resolve current loop state and next action from deterministic helper/state output
108
104
  - include explicit resolved artifact identity in the answer
@@ -166,11 +162,14 @@ When you do hand work to Copilot:
166
162
 
167
163
  ## PR description contract
168
164
 
165
+ This section governs tracker-backed (Copilot-handoff) PRs; issue-less/plan-file-backed PRs are governed by merge precondition 7 in merge-preconditions.md instead.
166
+
169
167
  Follow the PR description contract (see [Agent Instructions](../../AGENTS.md) if present; otherwise use the structure below): detailed structured descriptions, not thin placeholders. At minimum include change summary, scope/context, explicit acceptance criteria, explicit definition of done, and explicit non-goals, and `Closes #N` (or `Fixes #N`) for the linked issue so GitHub auto-closes it on merge.
170
168
 
171
169
  Checkbox rule: acceptance criteria, definition-of-done items, and any task list must be rendered as real GitHub markdown checkboxes inside list items (`- [ ]` / `- [x]`, also `* [ ]` / `* [x]`). Do not wrap checkbox markers (e.g. `[x]`) in backticks. Do not place checkbox markers inside table cells — task lists are not interactive there even with a leading `- `.
172
170
 
173
- New PRs in this workflow must be opened as **draft** PRs first when the repository enables `.devloops` at repo root `workflow.requireDraftFirst`. The built-in shipped default remains permissive; this repo opts in. Do not create a fresh PR directly in ready-for-review state unless the user explicitly overrides that policy for the current PR scope. The draft gate inspection is a real workflow boundary, so a new PR must exist in draft before `gh pr ready` is even eligible.
171
+ <!-- rule: OPS-DRAFT-FIRST-PR -->
172
+ `OPS-DRAFT-FIRST-PR`: New PRs in this workflow MUST always be opened as **draft** PRs — mechanically enforced by the `create-pr.mjs` wrapper below, which is unconditionally draft-only and rejects `--ready`. Agents MUST NOT create a fresh PR directly in ready-for-review state; `gh pr ready` (via the `ready-for-review.mjs` wrapper) is the only path out of draft, gated on clean draft-gate evidence. This rule owns the draft-first mechanism itself; [TRACKER-PROJECTION-REQUIRED-METADATA](./tracker-first-loop-state.md#31-required-pr-metadata) owns the tracker-facing "PR MUST start as a draft" metadata expectation. The draft gate inspection is a real workflow boundary, so a new PR must exist in draft before `gh pr ready` is even eligible.
174
173
 
175
174
  Only use `node <resolved-skill-scripts>/github/create-pr.mjs` when authoritative issue↔PR resolution says there is no already-open linked PR. If a PR already exists, reuse/update that canonical PR instead of opening another one. This wrapper preserves the underlying `gh pr create` output contract while enforcing draft-first mechanically and self-assigning the PR by default (`--assignee @me`).
176
175
 
@@ -230,4 +229,11 @@ Helper-owned sleep inside `run-watch-cycle.mjs`, `probe-copilot-review.mjs`, or
230
229
 
231
230
  A watcher sleeping between polls is expected behavior, not a blocker.
232
231
 
232
+ ## Hard rule: no inline interpreters
233
+
234
+ <!-- rule: OPS-NO-INLINE-INTERPRETER -->
235
+ `OPS-NO-INLINE-INTERPRETER`: Coordinator and agent flows MUST NOT invoke an inline interpreter (`node -e`/`node --eval`, `python3 -c`, `python3 - <<EOF` heredocs, or equivalent) to (a) parse any dev-loops tool output, or (b) mutate repository files. Sanctioned paths: a tool's `--jq`/`--silent` output flags (or `gh ... --jq`) for (a); the editor/patch tools, or `gh ... --body-file` composed from a `--jq` read, for (b). This rule applies to ALL repos using the dev-loop workflow, not just the source repo.
236
+
237
+ Post-watch read pattern: after a probe/watch settles, do not parse its output — re-read state via `detect-copilot-loop-state.mjs --repo <owner/name> --pr <number>` and, for thread bodies/ids, `list-review-threads.mjs --repo <owner/name> --pr <number> --unresolved-only` (see [Copilot PR Follow-up Skill](../copilot-pr-followup/SKILL.md) Step 6).
238
+
233
239
  If the polling interval is 1 minute, do not treat silence shorter than one full poll interval as suspicious, and do not configure needs-attention thresholds close to a few seconds for this loop.
@@ -32,13 +32,13 @@ Definitions:
32
32
 
33
33
  ## Claude-Code-path test inventory
34
34
 
35
- When a change targets a Claude-Code-specific seam, the following suites are the baseline that MUST stay green, and are the first place to add coverage for a Pi-originated change that must not regress Claude Code:
35
+ When a change targets a Claude-Code-specific seam, the following suites are the baseline that MUST stay green, and are the first place to add coverage for a Pi-originated change that MUST NOT regress Claude Code:
36
36
 
37
37
  - `npm run test:assets` — runs `test/contracts/*.test.mjs`, including `test/contracts/claude-assets-reproducible.test.mjs`, `test/contracts/claude-headless-smoke.test.mjs`, `test/contracts/claude-plugin-manifest.test.mjs`, `test/contracts/claude-plugin-marketplace.test.mjs`, `test/contracts/claude-hooks-settings.test.mjs`, and `test/contracts/cli-harness-agnostic.test.mjs`
38
38
  - `npm run smoke:headless` — runs `scripts/claude/headless-info-smoke.mjs`; this is a manual/local-only check, not part of `npm test` or `npm run verify` and not run by CI — run it directly when a change touches Claude Code headless-info behavior
39
39
  - `npm run test:core` — runs `packages/core/test/*.test.mjs`, including `packages/core/test/claude-headless-entry.test.mjs`, `packages/core/test/claude-hook-decisions.test.mjs`, `packages/core/test/run-context.test.mjs`, `packages/core/test/async-start-contract.test.mjs`
40
40
 
41
- Symmetrically, for a change targeting the Claude-Code-specific seam that must not regress Pi, `npm run test:extension` (which runs `test/extension-*.test.mjs`, including `test/extension-pi-adapter.test.mjs`, the Pi-side adapter inventory) is the baseline suite to check and extend.
41
+ Symmetrically, for a change targeting the Claude-Code-specific seam that MUST NOT regress Pi, `npm run test:extension` (which runs `test/extension-*.test.mjs`, including `test/extension-pi-adapter.test.mjs`, the Pi-side adapter inventory) is the baseline suite to check and extend.
42
42
 
43
43
  ## How to add coverage
44
44
 
@@ -1,6 +1,6 @@
1
1
  # Debt remediation contract
2
2
 
3
- Canonical authority for the debt remediation pipeline and its integration with the `dev-loop` execution path.
3
+ Canonical owner for the debt remediation pipeline and its integration with the `dev-loop` execution path.
4
4
 
5
5
  ## Pipeline
6
6
 
@@ -1,7 +1,7 @@
1
1
  # Epic tree refinement procedure
2
2
 
3
- This document is the canonical procedure for depth-first, top-down-then-bottom-up refinement of
4
- an existing GitHub sub-issue tree (parent → children → grandchildren).
3
+ Canonical owner for depth-first, top-down-then-bottom-up refinement of an existing GitHub
4
+ sub-issue tree (parent → children → grandchildren).
5
5
 
6
6
  Use it together with:
7
7
  - [Issue Intake Procedure](./issue-intake-procedure.md) — Phase 3b calls this procedure for epic decomposition
@@ -67,7 +67,8 @@ For the root issue:
67
67
  9. Show the diff and obtain confirmation before mutating GitHub
68
68
  10. Apply: `gh issue edit <root> --repo <repo> --body-file tmp/issues/<root>/refinement/root-body.md`
69
69
 
70
- **Gate:** Phase B must not start until Phase A is complete and the root body is updated on GitHub.
70
+ <!-- rule: EPIC-REFINEMENT-SERIAL-PHASE-GATE -->
71
+ **Gate:** Phase B MUST NOT start until Phase A is complete and the root body is updated on GitHub. The same serial-gate discipline applies at every phase boundary below: a level/phase MUST fully complete (siblings may run in parallel within it) before the next one starts.
71
72
 
72
73
  ---
73
74
 
@@ -96,7 +97,7 @@ parent's updated body, not each other's output.
96
97
  **Parallelism rule:** All siblings at the same level can be refined concurrently. No child needs
97
98
  another child's output; each child only reads the parent's contract and its own current body.
98
99
 
99
- **Serial gate between levels:** All children at level N must complete before descending to level N+1.
100
+ **Serial gate between levels** ([EPIC-REFINEMENT-SERIAL-PHASE-GATE](#phase-a--root-refinement-serial)): all children at level N must complete before descending to level N+1.
100
101
 
101
102
  Repeat Phase B until all leaves are refined.
102
103
 
@@ -122,7 +123,7 @@ updated bodies, not sibling parents).
122
123
  6. Show the diff and obtain confirmation before mutating
123
124
  7. Apply: `gh issue edit <parent> --repo <repo> --body-file tmp/issues/<parent>/refinement/parent-reconciled-body.md`
124
125
 
125
- **Serial gate between levels:** All parents at depth N must complete reconciliation before ascending to depth N-1.
126
+ **Serial gate between levels** ([EPIC-REFINEMENT-SERIAL-PHASE-GATE](#phase-a--root-refinement-serial)): all parents at depth N must complete reconciliation before ascending to depth N-1.
126
127
 
127
128
  ---
128
129
 
@@ -146,21 +147,28 @@ After all immediate children of the root have been reconciled:
146
147
  --repo <repo> --issue <root> --expected <n1,n2,...> --ordered
147
148
  ```
148
149
 
149
- **Gate:** Root final reconcile completes the procedure. All issues in the tree must now have:
150
- - AC checklist, DoD checklist, AC/DoD matrix, non-goals, explicit scope boundary
150
+ **Gate:** Root final reconcile completes the procedure. Every issue in the tree must now satisfy
151
+ [EPIC-REFINEMENT-REQUIRED-CONTRACTS](#rules).
151
152
 
152
153
  ---
153
154
 
154
155
  ## Rules
155
156
 
156
- - **No implementation, no PRs, no Copilot assignment** — this procedure is refinement-only
157
- - **Use `gh issue edit`** to apply changes directly do not create new issues or PRs
158
- - **No prose parent/child links in bodies**GitHub sub-issues API handles hierarchy
159
- - **Each issue must have:** AC checklist, DoD checklist, non-goals, AC/DoD matrix, scope boundary
160
- - **Scope boundary format:** `"This issue owns X. It does NOT own Y (#NNN) or Z (#MMM)."`
161
- - **Show the diff** and get confirmation before each `gh issue edit` mutation (unless unattended with explicit authorization)
162
- - **Write tmp artifacts** under `tmp/issues/<number>/refinement/` before applying
163
- - **Do not duplicate** the child list in parent bodies the sub-issue tree API owns hierarchy
157
+ <!-- rule: EPIC-REFINEMENT-SCOPE-BOUNDARY -->
158
+ This procedure MUST stay refinement-only: no implementation, no PRs, no Copilot assignment.
159
+ Apply changes directly with `gh issue edit`never create new issues or PRs. Hierarchy MUST
160
+ stay in the GitHub sub-issues API, not prose parent/child links or a duplicated child-list
161
+ checklist in parent bodies.
162
+
163
+ <!-- rule: EPIC-REFINEMENT-REQUIRED-CONTRACTS -->
164
+ Each issue in the tree MUST carry: an AC checklist, a DoD checklist, a non-goals section, an
165
+ AC/DoD matrix, and an explicit scope boundary in the format
166
+ `"This issue owns X. It does NOT own Y (#NNN) or Z (#MMM)."`
167
+
168
+ <!-- rule: EPIC-REFINEMENT-CONFIRM-BEFORE-MUTATE -->
169
+ `EPIC-REFINEMENT-CONFIRM-BEFORE-MUTATE`: The procedure MUST write the refined body to
170
+ `tmp/issues/<number>/refinement/` first and MUST show the diff and get confirmation before
171
+ each `gh issue edit` mutation, unless running unattended with explicit authorization.
164
172
 
165
173
  ---
166
174
 
@@ -179,18 +187,13 @@ Phase D: [root] serial (1 step)
179
187
 
180
188
  Total serial steps for a tree with depth D: `1 + (D-1) + (D-1) + 1 = 2D`
181
189
 
182
- **Fan-out rule:** At any level, when a parent is refined, ALL its children can be refined in parallel.
183
-
184
- **Serial gates:**
185
- - Root refinement must complete before any child starts
186
- - A parent's reconciliation must wait for ALL its children to finish
187
- - Root reconciliation must wait for all immediate children to reconcile
190
+ **Fan-out rule:** At any level, when a parent is refined, ALL its children can be refined in parallel. Root/leaf/child ordering follows [EPIC-REFINEMENT-SERIAL-PHASE-GATE](#phase-a--root-refinement-serial) throughout.
188
191
 
189
192
  ---
190
193
 
191
194
  ## Completion criteria
192
195
 
193
- The procedure is complete when all issues in the tree satisfy:
196
+ The procedure is complete when all issues in the tree satisfy [EPIC-REFINEMENT-REQUIRED-CONTRACTS](#rules), verified as:
194
197
 
195
198
  | Check | How to verify |
196
199
  |---|---|
@@ -1,17 +1,20 @@
1
1
  # Issue intake procedure
2
2
 
3
- This document is the canonical owner of the routed `issue_intake` procedure behind the public `dev-loop` façade.
3
+ Canonical owner for the routed `issue_intake` procedure behind the public `dev-loop` façade: preflight, normalization, async refinement, epic decomposition, and Copilot handoff.
4
4
 
5
5
  Use it together with:
6
6
  - [Copilot PR Follow-up Skill](../copilot-pr-followup/SKILL.md)
7
- - [Public Dev Loop Contract](./public-dev-loop-contract.md)
7
+ - [Public Dev Loop Contract](./public-dev-loop-contract.md) — owner of `FACADE-LINKED-PR-SINGLE-ARTIFACT`, `FACADE-BOOTSTRAP-WATCH-ROUTE`, `FACADE-BOOTSTRAP-ISOLATED-WORKTREE-CONTINUATION`
8
8
  - [Retrospective Checkpoint Contract](./retrospective-checkpoint-contract.md) when the current step depends on async start/resume/status or retrospective enforcement
9
+ - [Stop Conditions](./stop-conditions.md) — owner of `STOP-INITIAL-COPILOT-001` and the other strategy-wide stop/wait rules this procedure operationalizes
10
+ - [Merge Preconditions](./merge-preconditions.md) — the merge gate this procedure defers to before `gh pr merge`
9
11
 
10
12
  When routed work is issue-first rather than already in active PR follow-up, use the procedure below before entering the shared post-PR loop. Treat this document as the issue-refinement specialist procedure for the routed `issue_intake` seam.
11
13
 
12
14
  ## New-idea safety layer (default contract in this repo)
13
15
 
14
- For **all new ideas** that are not already anchored to an existing issue (including abstract ideas such as plain-language requests without an issue number or plan-doc path), apply this procedure-owned intake contract before any GitHub mutation:
16
+ <!-- rule: INTAKE-NEW-IDEA-SAFETY -->
17
+ For **all new ideas** that are not already anchored to an existing issue (including abstract ideas such as plain-language requests without an issue number or plan-doc path), the procedure MUST apply this intake contract before any GitHub mutation:
15
18
 
16
19
  - procedure owns classification; human operator gates all mutations
17
20
  - run classification in fresh context by default
@@ -23,6 +26,15 @@ For **all new ideas** that are not already anchored to an existing issue (includ
23
26
  - after approval, run a second async mutation pass (dispatched via the procedure) instead of mutating directly from inherited context
24
27
  - verify post-mutation artifact state and record what actually changed
25
28
 
29
+ **Quick-capture exemption:** board quick-capture enqueue (the `/loop-enqueue` freeform
30
+ path — freeform text turned directly into a minimal issue, gated on explicit human
31
+ approval, then grilled inline and added to the board) MAY defer the up-front proposal
32
+ artifact, the async classification pass, the async fan-out/fan-in proposal generation, and
33
+ the second async mutation pass; its inline confirm→create→grill steps stand in for them,
34
+ with grilling supplying classification/refinement after creation. The human-gated-mutation
35
+ and create-new-only safeties still apply — it always creates a new issue and never
36
+ repurposes/overwrites an existing one.
37
+
26
38
  Deterministic intake + mutation-gate state machine:
27
39
 
28
40
  ```text
@@ -50,9 +62,11 @@ Proposal artifact contract:
50
62
  - machine-readable JSON snapshot
51
63
  - write temporary artifacts under `Proposal` (`tmp/new-idea-intake/<run-id>/proposal.md`) and `tmp/new-idea-intake/<run-id>/proposal.json`
52
64
 
53
- If the Phase 1 preflight verdict is `pause_for_clarification`, stop and ask.
54
- If the intake state machine stops at `stopped_overlap_needs_decision` or `stopped_low_confidence`, stop and ask.
55
- If the intake state machine stops at `stopped_explicit_reject`, stop and record that the proposal was rejected; do not mutate GitHub.
65
+ <!-- rule: INTAKE-STOP-STATES -->
66
+ If the Phase 1 preflight verdict is `pause_for_clarification`, the procedure MUST stop and ask.
67
+ If the intake state machine stops at `stopped_overlap_needs_decision` or `stopped_low_confidence`, the procedure MUST stop and ask.
68
+ If the intake state machine stops at `stopped_explicit_reject`, the procedure MUST stop and record that the proposal was rejected; it MUST NOT mutate GitHub.
69
+
56
70
  After approval, start a separate async mutation pass (dispatched via the procedure) that consumes the approved proposal and emits a post-mutation verification artifact. Emit a concise post-mutation verification artifact and record what the mutation pass actually changed and verify the resulting issue/artifact state.
57
71
 
58
72
  ## Unattended issue-first execution and automatic re-entry
@@ -67,7 +81,7 @@ Under that unattended execution contract:
67
81
  - If a PR already exists, classify the post-assignment seam before follow-up
68
82
  - `waiting_for_initial_copilot_implementation`: keep waiting
69
83
  - `linked_pr_ready_for_followup`: route to the existing PR follow-up path immediately; resume from that PR
70
- - when routing leaves bootstrap wait for `linked_pr_ready_for_followup`, do not stop only because local isolation is required; re-enter the same PR follow-up from a safe isolated checkout/worktree
84
+ - when routing leaves bootstrap wait for `linked_pr_ready_for_followup`, follow [FACADE-BOOTSTRAP-ISOLATED-WORKTREE-CONTINUATION](public-dev-loop-contract.md): re-enter the same PR follow-up from a safe isolated checkout/worktree instead of stopping solely because local isolation is required
71
85
  - When the draft PR appears, classify whether it is still the bootstrap-only Copilot draft before entering normal follow-up
72
86
  - if a child async run exits while the deterministic state is still non-terminal (for example `waiting_for_copilot_review`), automatically resume/restart follow-up when continuation is feasible instead of requiring manual operator restart
73
87
  - continue unattended until the human approval checkpoint unless a genuine stop condition is reached
@@ -107,10 +121,9 @@ Preflight verdicts:
107
121
  - detect an existing linked PR with the deterministic linked-PR helper:
108
122
  `node <resolved-skill-scripts>/github/detect-linked-issue-pr.mjs --repo <resolved-repo> --issue <number>`
109
123
  - treat the helper output as authoritative for linked-PR detection/selection
110
- - do not re-implement linked-event query behavior, pagination, repo filtering, or tie-break logic
111
- - do not rely only on PR title/body containing a literal issue number
124
+ - <!-- rule: INTAKE-LINKED-PR-HELPER-DELEGATION --> `INTAKE-LINKED-PR-HELPER-DELEGATION`: Agents MUST NOT re-implement linked-event query behavior, pagination, repo filtering, or tie-break logic, and MUST NOT rely only on PR title/body containing a literal issue number.
112
125
  - treat an open linked PR as the active implementation for this issue
113
- - once an open linked PR exists, that PR is the only canonical follow-up artifact for the issue; attach follow-up work to it and do not open another PR unless the prior PR was explicitly superseded and reconciled first
126
+ - once an open linked PR exists, attach follow-up work to it per `FACADE-LINKED-PR-SINGLE-ARTIFACT` (owned in [Public Dev Loop Contract](public-dev-loop-contract.md)) for the `issue_intake` strategy
114
127
  - **follow-up-capture rule:** when a follow-up is discovered while working a PR/loop, note it on the originating issue (or the PR body); file a standalone issue only if the follow-up is genuinely independent of the PR **and** outlives it (a real separate bug/feature that would be lost as a note on a soon-closed issue). Prefer noting PR-scoped follow-ups on the originating artifact over spinning up standalone tracker items for work that is part of the same effort or will be resolved imminently. See [Sub-Issue Tree Contract](../../docs/sub-issue-tree-contract.md).
115
128
  - if a PR already exists, classify bootstrap-wait versus follow-up:
116
129
  `node <resolved-skill-scripts>/loop/detect-initial-copilot-pr-state.mjs --repo <resolved-repo> --issue <number>`
@@ -118,20 +131,20 @@ Preflight verdicts:
118
131
  ```sh
119
132
  node <resolved-skill-scripts>/loop/watch-initial-copilot-pr.mjs --repo <resolved-repo> --issue <number>
120
133
  ```
121
- - must use the dedicated `watch-initial-copilot-pr.mjs` watcher and its default 1-hour watch budget
134
+ - durable-auto ownership of this seam (the dedicated watcher + its default 1-hour watch budget) is owned by [FACADE-BOOTSTRAP-WATCH-ROUTE](public-dev-loop-contract.md); this procedure does not restate that rule
122
135
  - quiet/no-activity watch observations alone are non-terminal
123
136
  - `ready_for_followup`: linked PR has become substantive; resume from that PR
124
137
  - `timed_out`: observational first; refresh authoritative state
125
138
  - if refreshed state is still `waiting_for_initial_copilot_implementation`, remain attached to the same durable wait seam and continue waiting
126
- - if the refreshed state exits this seam, route based on that refreshed state instead of surfacing timeout attention
127
- - when the refreshed state is `linked_pr_ready_for_followup`, re-enter normal PR follow-up; if the follow-up handoff carries `conductorRouting.handoffEnvelope.requiresLocalIsolation=true`, perform the expected isolated-checkout/worktree handoff and continue
128
- - only surface timeout attention when the seam's durable watch budget is actually exhausted
139
+ - <!-- rule: INTAKE-TIMEOUT-ROUTE-ON-SEAM-EXIT --> `INTAKE-TIMEOUT-ROUTE-ON-SEAM-EXIT`: if the refreshed state exits this seam, route based on that refreshed state instead of surfacing timeout attention
140
+ - when the refreshed state is `linked_pr_ready_for_followup`, re-enter normal PR follow-up per [FACADE-BOOTSTRAP-ISOLATED-WORKTREE-CONTINUATION](public-dev-loop-contract.md): if the follow-up handoff carries `conductorRouting.handoffEnvelope.requiresLocalIsolation=true`, perform the expected isolated-checkout/worktree handoff and continue
141
+ - <!-- rule: INTAKE-TIMEOUT-SURFACE-BUDGET-EXHAUSTED --> `INTAKE-TIMEOUT-SURFACE-BUDGET-EXHAUSTED`: only surface timeout attention when the seam's durable watch budget is actually exhausted
129
142
  - for explicit inspect/status requests, report the still-waiting state and exit normally
130
143
  - carry that resolved repo slug through every later GitHub issue/PR command
131
144
 
132
145
  ### From a plan-doc path
133
146
 
134
- - Resolve the target repository slug for this work item before any GitHub search or mutation
147
+ - <!-- rule: INTAKE-REPO-SLUG-RESOLVE-FIRST --> `INTAKE-REPO-SLUG-RESOLVE-FIRST`: Resolve the target repository slug for this work item before any GitHub search or mutation
135
148
  - default to the current repository slug
136
149
  - if the plan-doc reference explicitly points at another GitHub repository, resolve `<resolved-repo>` first
137
150
  - search existing issues with:
@@ -199,8 +212,10 @@ node <resolved-skill-scripts>/github/manage-sub-issues.mjs list \
199
212
  --repo <resolved-repo> --issue <parent-number>
200
213
  ```
201
214
 
202
- Do **not** re-implement sub-issue management ad hoc or bypass `manage-sub-issues.mjs`.
203
- Do **not** maintain a body checklist that duplicates the sub-issue tree.
215
+ Ad-hoc bypass of `manage-sub-issues.mjs` and duplicating the tree in the parent body are owned
216
+ by `SUBISSUE-NO-ADHOC-BYPASS` and `SUBISSUE-LEAN-BODY-NO-DUPLICATE` in
217
+ [Sub-Issue Tree Contract](../../docs/sub-issue-tree-contract.md); this procedure does not
218
+ restate those rules.
204
219
 
205
220
  For the full `manage-sub-issues.mjs` contract, use [Sub-Issue Tree Contract](../../docs/sub-issue-tree-contract.md) when working in the `dev-loops` source repository. That contract is a source-repo reference, not part of the bundled installed skill-doc surface. For installed or normalized skill copies, inspect the target repository docs/source directly instead of assuming a bundled shared-doc copy exists.
206
221
 
@@ -232,9 +247,9 @@ The merge itself is gated, not implied by the lines above. Before any `gh pr mer
232
247
  gh pr merge <pr-number> --repo <resolved-repo> --squash --delete-branch
233
248
  ```
234
249
 
235
- Bootstrap-wait interpretation remains fail-closed and observational-first:
236
- - `ready_for_followup`: linked PR has become substantive; resume from that PR
237
- - `timed_out`: observational first; refresh authoritative state
238
- - if refreshed state is still `waiting_for_initial_copilot_implementation`, remain attached to the same durable wait seam and continue waiting
239
- - if refreshed state exits that seam, route based on refreshed state instead of surfacing timeout attention
250
+ Bootstrap-wait interpretation remains fail-closed and observational-first — same seam as Phase 2's `waiting_for_initial_copilot_implementation` handling above: `ready_for_followup` resumes from the now-substantive linked PR; `timed_out` is observational first; refresh authoritative state and re-apply the Phase 2 branching (still-waiting vs. seam-exit) rather than re-deriving it here.
251
+
252
+ ## Cross-references
253
+
254
+ See the "Use it together with" list at the top; additionally, [Epic Tree Refinement Procedure](./epic-tree-refinement-procedure.md) refines an existing sub-issue tree, while this procedure creates it (Phase 3b).
240
255
 
@@ -38,14 +38,17 @@ doing manually; it is not a general conflict-resolution engine.
38
38
 
39
39
  ## Required before merge
40
40
 
41
+ <!-- rule: MERGE-PRECOND-REQUIRED -->
42
+ Before merge, ALL of the following MUST hold:
43
+
41
44
  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)
45
+ 2. ✅ CI green on current head (or crediblyGreen via `--local-validation-head-sha`)
46
+ 3. ✅ Draft gate satisfied clean `draft_gate` verdict per `GATE-COMMENT-VERDICT-VALUES` ([Checkpoint Verdict Comment Contract](../../docs/gate-review-comment-contract.md))
47
+ 4. ✅ Pre-approval gate satisfied clean `pre_approval_gate` verdict on the current head, same rule
48
+ 5. ✅ All review threads resolved
49
+ 6. ✅ Explicit merge authorization from operator
50
+ 7. ✅ Closing-reference state matches artifact backing, each arm owned by a different contract: tracker-backed work — PR body contains `Closes #N` or `Fixes #N` (owned by the PR description contract in [copilot-loop-operations.md](copilot-loop-operations.md)); issue-less lightweight (PR-body-as-spec, no backing issue) — the closing reference is absent by design and `node scripts/loop/validate-pr-body-spec.mjs --repo <owner/name> --pr <number> --no-issue` passes clean (owned by `ARTIFACT-LIGHTWEIGHT-BODY-INVARIANTS` in [Artifact Authority Contract](artifact-authority-contract.md)); plan-file promotion (P4) — the PR body carries the committed plan-doc path as the spec-of-record and, being issue-less by design (`buildPromotionPrBody` neutralizes closing keywords), the closing reference MUST NOT be present
51
+ 8. ✅ PR **title** free of merge-blocking markers — `WIP`, `[WIP]`, `DRAFT`, `DO NOT MERGE`, `🚧` (case-insensitive)
49
52
 
50
53
  > 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.
51
54
 
@@ -79,9 +82,9 @@ A marker is allowed only while the PR is still in draft; it must be removed befo
79
82
 
80
83
  ## Merge authorization
81
84
 
82
- - Must be explicit for the active issue/PR scope
85
+ - Merge authorization MUST be explicit for the active issue/PR scope
83
86
  - `"Merge authorized if gates green"` is valid explicit authorization
84
- - Implied approval from prior turns is not sufficient
87
+ - Implied approval from prior turns MUST NOT be treated as sufficient
85
88
 
86
89
  ### `autonomy.humanMergeOnly` — fixed human-only merge (non-overridable)
87
90
 
@@ -140,10 +143,8 @@ human(s).
140
143
 
141
144
  ## Post-merge
142
145
 
143
- - Remove merged worktree (canonical): `node scripts/loop/cleanup-worktree.mjs --repo-root <main> (--issue <n> | --pr <n>)`.
144
- It resolves the namespaced path, runs `git worktree remove --force <path> && git worktree prune` (the underlying
145
- mechanism) from the main checkout, and refuses any path not under `tmp/worktrees/dev-loops/`. See
146
- [worktree guidance](../../docs/worktree-guidance.md).
146
+ - Remove merged worktree (canonical, `WORKTREE-CLEANUP`): `node scripts/loop/cleanup-worktree.mjs --repo-root <main> (--issue <n> | --pr <n>)`.
147
+ See [Worktree usage guidance](../../docs/worktree-guidance.md#post-merge-cleanup).
147
148
  - Archive long-done queue items (operator-induced, NOT a cron): `node scripts/projects/archive-done-items.mjs --repo <owner/name> || true`.
148
149
  Runs as part of this post-merge hook. It applies the configured `queue.archiveOlderThanDays` (default `7d`) and archives
149
150
  board items whose issue/PR has been closed at least that long. Best-effort: run it as a standard post-merge step but ignore
@@ -157,3 +158,6 @@ human(s).
157
158
  - [Confirmation rules](confirmation-rules.md)
158
159
  - [Validation policy](validation-policy.md)
159
160
  - [Stop conditions](stop-conditions.md)
161
+ - [PR Lifecycle Contract](pr-lifecycle-contract.md)
162
+ - [Checkpoint Verdict Comment Contract](../../docs/gate-review-comment-contract.md) — `GATE-COMMENT-VERDICT-VALUES`
163
+ - [Contract style guide](contract-style-guide.md)
@@ -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
- - 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
+ - non-draft PRs do not need *per-head* `draft_gate` evidence to enter the post-draft review / `pre_approval_gate` lifecycle — the one-time draft -> ready transition record still applies; a non-draft PR with no clean `draft_gate` evidence at all fails closed and must reconcile that missing evidence first (see the current-head `draft_gate` evidence bullet under [Fail-closed rules](#fail-closed-rules))
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
+