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.
- package/.claude/.claude-plugin/plugin.json +1 -1
- package/.claude/agents/dev-loop.md +7 -7
- package/.claude/agents/fixer.md +1 -0
- package/.claude/agents/refiner.md +4 -4
- package/.claude/agents/review.md +10 -13
- package/.claude/commands/loop-continue.md +2 -1
- package/.claude/commands/loop-enqueue.md +9 -2
- package/.claude/commands/loop-info.md +1 -1
- package/.claude/commands/loop-start-spike.md +1 -1
- package/.claude/hooks/_bash-command-classify.mjs +7 -6
- package/.claude/hooks/_hook-decisions.mjs +5 -4
- package/.claude/skills/copilot-pr-followup/SKILL.md +42 -28
- package/.claude/skills/dev-loop/SKILL.md +8 -8
- package/.claude/skills/docs/acceptance-criteria-verification.md +13 -4
- package/.claude/skills/docs/anti-patterns.md +6 -5
- package/.claude/skills/docs/artifact-authority-contract.md +17 -14
- package/.claude/skills/docs/confirmation-rules.md +2 -1
- package/.claude/skills/docs/contract-style-guide.md +37 -0
- package/.claude/skills/docs/copilot-loop-operations.md +21 -15
- package/.claude/skills/docs/cross-harness-regression-contract.md +2 -2
- package/.claude/skills/docs/debt-remediation-contract.md +1 -1
- package/.claude/skills/docs/epic-tree-refinement-procedure.md +25 -22
- package/.claude/skills/docs/issue-intake-procedure.md +37 -22
- package/.claude/skills/docs/merge-preconditions.md +17 -13
- package/.claude/skills/docs/pr-lifecycle-contract.md +45 -36
- package/.claude/skills/docs/public-dev-loop-contract.md +61 -44
- package/.claude/skills/docs/retrospective-checkpoint-contract.md +25 -9
- package/.claude/skills/docs/spike-mode-contract.md +14 -7
- package/.claude/skills/docs/stop-conditions.md +30 -15
- package/.claude/skills/docs/tracker-first-loop-state.md +13 -8
- package/.claude/skills/docs/validation-policy.md +4 -5
- package/.claude/skills/local-implementation/SKILL.md +49 -143
- package/.claude/skills/loop-grill/SKILL.md +34 -14
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +36 -0
- package/README.md +95 -189
- package/agents/dev-loop.agent.md +8 -8
- package/agents/fixer.agent.md +1 -0
- package/agents/refiner.agent.md +4 -4
- package/agents/review.agent.md +10 -13
- package/extension/README.md +5 -4
- package/package.json +7 -5
- package/scripts/_core-helpers.mjs +2 -0
- package/scripts/claude/headless-dev-loop.mjs +1 -1
- package/scripts/docs/validate-rule-ownership.mjs +442 -0
- package/scripts/docs/validate-state-machine-conformance.mjs +1169 -0
- package/scripts/github/_gate-names.mjs +5 -0
- package/scripts/github/_review-thread-mutations.mjs +5 -2
- package/scripts/github/capture-review-threads.mjs +2 -2
- package/scripts/github/create-pr.mjs +119 -10
- package/scripts/github/detect-checkpoint-evidence.mjs +109 -24
- package/scripts/github/edit-issue.mjs +259 -0
- package/scripts/github/list-review-threads.mjs +277 -0
- package/scripts/github/post-gate-findings.mjs +6 -3
- package/scripts/github/probe-ci-status.mjs +18 -0
- package/scripts/github/probe-copilot-review.mjs +24 -3
- package/scripts/github/reconcile-draft-gate.mjs +13 -13
- package/scripts/github/request-copilot-review.mjs +109 -42
- package/scripts/github/upsert-checkpoint-verdict.mjs +98 -27
- package/scripts/github/verify-briefing-prefixes.mjs +382 -0
- package/scripts/github/verify-fresh-review-context.mjs +78 -3
- package/scripts/github/wait-pr-checks.mjs +171 -0
- package/scripts/github/write-gate-context.mjs +220 -10
- package/scripts/github/write-gate-findings-log.mjs +54 -2
- package/scripts/loop/_post-convergence-change.mjs +2 -2
- package/scripts/loop/_pr-runner-coordination.mjs +112 -13
- package/scripts/loop/check-retro-tooling.mjs +14 -9
- package/scripts/loop/copilot-pr-handoff.mjs +47 -16
- package/scripts/loop/detect-change-scope.mjs +2 -2
- package/scripts/loop/detect-copilot-loop-state.mjs +34 -14
- package/scripts/loop/detect-internal-only-pr.mjs +6 -6
- package/scripts/loop/detect-pr-gate-coordination-state.mjs +152 -18
- package/scripts/loop/detect-refinement-grill-state.mjs +136 -0
- package/scripts/loop/resolve-dev-loop-startup.mjs +145 -8
- package/scripts/loop/run-watch-cycle.mjs +42 -7
- package/scripts/loop/sanctioned-commands.mjs +3 -0
- package/scripts/loop/validate-pr-body-spec.mjs +21 -5
- package/scripts/pages/build-state-atlas.mjs +65 -48
- package/scripts/projects/_resolve-project.mjs +1 -148
- package/scripts/projects/add-queue-item.mjs +87 -4
- package/scripts/projects/list-queue-items.mjs +3 -377
- package/scripts/projects/move-queue-item.mjs +3 -410
- package/scripts/projects/reorder-queue-item.mjs +3 -22
- package/skills/copilot-pr-followup/SKILL.md +42 -28
- package/skills/dev-loop/SKILL.md +3 -3
- package/skills/docs/acceptance-criteria-verification.md +13 -4
- package/skills/docs/anti-patterns.md +6 -5
- package/skills/docs/artifact-authority-contract.md +17 -14
- package/skills/docs/confirmation-rules.md +2 -1
- package/skills/docs/contract-style-guide.md +37 -0
- package/skills/docs/copilot-loop-operations.md +21 -15
- package/skills/docs/cross-harness-regression-contract.md +2 -2
- package/skills/docs/debt-remediation-contract.md +1 -1
- package/skills/docs/epic-tree-refinement-procedure.md +25 -22
- package/skills/docs/issue-intake-procedure.md +37 -22
- package/skills/docs/merge-preconditions.md +17 -13
- package/skills/docs/pr-lifecycle-contract.md +45 -36
- package/skills/docs/public-dev-loop-contract.md +61 -44
- package/skills/docs/required-rules.json +165 -0
- package/skills/docs/retrospective-checkpoint-contract.md +25 -9
- package/skills/docs/spike-mode-contract.md +14 -7
- package/skills/docs/stop-conditions.md +30 -15
- package/skills/docs/tracker-first-loop-state.md +13 -8
- package/skills/docs/validation-policy.md +4 -5
- package/skills/local-implementation/SKILL.md +49 -143
- package/skills/loop-grill/SKILL.md +38 -17
- package/scripts/docs/validate-no-duplicate-rules.mjs +0 -250
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# Issue intake procedure
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
54
|
-
If the
|
|
55
|
-
If the intake state machine stops at `
|
|
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`,
|
|
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
|
-
-
|
|
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,
|
|
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
|
-
-
|
|
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
|
|
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
|
-
|
|
203
|
-
|
|
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
|
-
|
|
237
|
-
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
-
-
|
|
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
|
|
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
|
|
53
|
-
|
|
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
|
-
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
+
|