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,10 +1,10 @@
|
|
|
1
1
|
# Public dev-loop contract
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Canonical owner for the public `dev-loop` entrypoint: routed semantics, accepted shorthand, and the rule that internal strategy names stay behind the façade.
|
|
4
4
|
|
|
5
5
|
This canonical owner lives in the shipped `skills/docs/` surface because installed skill/runtime consumers reliably own the skills subtree. In installed layouts, read the same contract via [Public Dev Loop Contract](../docs/public-dev-loop-contract.md) from the installed skill directory.
|
|
6
6
|
|
|
7
|
-
Other repo docs
|
|
7
|
+
Other repo docs MAY summarize or link this contract; they MUST NOT redefine it.
|
|
8
8
|
|
|
9
9
|
## Public surface
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ The single public entrypoint is:
|
|
|
12
12
|
|
|
13
13
|
- `dev-loop`
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
`dev-loop` MUST be callable from the user-facing workflow surfaces, including:
|
|
16
16
|
|
|
17
17
|
- `subagent dev-loop`
|
|
18
18
|
- `/skill:dev-loop`
|
|
@@ -28,8 +28,6 @@ Day-one user-intent forms:
|
|
|
28
28
|
- auto dev loop on issue `<n>`
|
|
29
29
|
- what state is the dev loop in?
|
|
30
30
|
|
|
31
|
-
Users should not have to choose `dev-loop` vs internal seam names up front.
|
|
32
|
-
|
|
33
31
|
## Issue-based shorthand auto trigger contract
|
|
34
32
|
|
|
35
33
|
This shorthand form is explicitly accepted and resolves to the same bounded public `dev-loop` intent:
|
|
@@ -44,7 +42,7 @@ Canonical mapping:
|
|
|
44
42
|
|
|
45
43
|
Stop-boundary contract for this shorthand:
|
|
46
44
|
|
|
47
|
-
1. continue through the normal GitHub/Copilot loop (assignment, PR watch, draft
|
|
45
|
+
1. continue through the normal GitHub/Copilot loop (assignment, PR watch, draft/Copilot review-fix, final pre-approval) unless a genuine stop condition is reached
|
|
48
46
|
2. stop at the final human approval decision by default
|
|
49
47
|
3. after formal approval, stop again in `waiting_for_merge_authorization` unless merge authorization is explicitly granted for the active issue/PR scope
|
|
50
48
|
4. merge only after explicit merge authorization for the active issue/PR scope
|
|
@@ -74,9 +72,11 @@ Use this taxonomy consistently across docs, discovery surfaces, and tests:
|
|
|
74
72
|
| Internal routed strategy modules | `issue-intake`, `copilot-pr-followup`, `local-implementation`, `final-approval` | keep internal-only behind `dev-loop`; do not expose as executable peer workflow entrypoints |
|
|
75
73
|
| Reusable role agents | `developer`, `docs`, `review`, `fixer`, `quality`, `refiner` | keep framed as reusable building blocks, not peer public workflow entrypoints |
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
<!-- rule: FACADE-COPILOT-INTERNAL-ONLY -->
|
|
76
|
+
`FACADE-COPILOT-INTERNAL-ONLY`: Any remaining specialized Copilot behavior stays internal-only behind `dev-loop`.
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
<!-- rule: FACADE-TAXONOMY-DRIFT-TEST -->
|
|
79
|
+
`FACADE-TAXONOMY-DRIFT-TEST`: Regression tests MUST fail if this taxonomy drifts in wording or surfaced entrypoint assets.
|
|
80
80
|
|
|
81
81
|
## Canonical current state
|
|
82
82
|
|
|
@@ -90,17 +90,7 @@ The public router consumes one canonical current state with these top-level dime
|
|
|
90
90
|
| `status` | `active` \| `waiting` \| `blocked` \| `approval_ready` \| `merge_ready` \| `done` |
|
|
91
91
|
| `authorization` | `authorized` \| `needs_confirmation` \| `not_authorized` |
|
|
92
92
|
|
|
93
|
-
The authoritative first-slice evaluator
|
|
94
|
-
|
|
95
|
-
- `packages/core/src/loop/public-dev-loop-routing.mjs`
|
|
96
|
-
|
|
97
|
-
Authoritative status-report helper:
|
|
98
|
-
|
|
99
|
-
- `resolveAuthoritativeDevLoopStatus()` in `packages/core/src/loop/public-dev-loop-routing.mjs`
|
|
100
|
-
|
|
101
|
-
Authoritative startup/resume bundle helper:
|
|
102
|
-
|
|
103
|
-
- `resolveAuthoritativeStartupResumeBundle()` in `packages/core/src/loop/public-dev-loop-routing.mjs`
|
|
93
|
+
The authoritative first-slice evaluator, status-report helper (`resolveAuthoritativeDevLoopStatus()`), and startup/resume bundle helper (`resolveAuthoritativeStartupResumeBundle()`) all live in `packages/core/src/loop/public-dev-loop-routing.mjs`.
|
|
104
94
|
|
|
105
95
|
Its tests are:
|
|
106
96
|
|
|
@@ -118,7 +108,8 @@ Before answering status/progress/readiness/merge-state/next-step questions, cons
|
|
|
118
108
|
|
|
119
109
|
Prior chat context is only a hint, never state authority.
|
|
120
110
|
|
|
121
|
-
|
|
111
|
+
<!-- rule: FACADE-STATUS-AUTHORITATIVE-FAIL-CLOSED -->
|
|
112
|
+
`FACADE-STATUS-AUTHORITATIVE-FAIL-CLOSED`: If authoritative identity/state (including issue↔PR linkage when relevant) cannot be resolved confidently, consumers MUST fail closed to reconcile/unknown instead of guessing.
|
|
122
113
|
For async/durable-auto flows, do not claim that `dev-loop` has started or is running unless a visible Pi-managed async run id has also been resolved.
|
|
123
114
|
|
|
124
115
|
When the routed next step requires confirmation for a mutation, the status/startup next action should name that concrete pending mutation (for example issue assignment to `copilot-swe-agent`) instead of generic "approval gate" wording.
|
|
@@ -140,10 +131,8 @@ Required authoritative inputs:
|
|
|
140
131
|
- `auto_continue_current` always resolves to `durable_auto`
|
|
141
132
|
- `issueLinkageResolution` (`resolved_linked_pr` \| `resolved_no_open_pr` \| `not_applicable`)
|
|
142
133
|
- required when `currentState.target.kind === issue`
|
|
143
|
-
- `issueReadiness` (`ready` \| `needs_clarification` \| `not_applicable`)
|
|
144
|
-
- required for Copilot-first issue targets with `issueLinkageResolution=resolved_no_open_pr`
|
|
145
|
-
- `issueAssignmentState` (`unassigned` \| `assigned_to_copilot` \| `not_applicable`)
|
|
146
|
-
- required for Copilot-first issue targets with `issueLinkageResolution=resolved_no_open_pr`
|
|
134
|
+
- `issueReadiness` (`ready` \| `needs_clarification` \| `not_applicable`) and `issueAssignmentState` (`unassigned` \| `assigned_to_copilot` \| `not_applicable`)
|
|
135
|
+
- both required for Copilot-first issue targets with `issueLinkageResolution=resolved_no_open_pr`
|
|
147
136
|
- `artifactState` (`open` \| `closed` \| `merged` \| `not_applicable`)
|
|
148
137
|
- explicit resolved `loopState` (`unknown` is not authoritative input)
|
|
149
138
|
- required for async/durable-auto startup or status paths: `asyncRun`
|
|
@@ -151,8 +140,8 @@ Required authoritative inputs:
|
|
|
151
140
|
- durable-auto success requires `kind=pi_managed_run`, a non-empty visible `runId`, and `visible=true`
|
|
152
141
|
- when `inspectionState` is provided as `hidden`, `stale`, or `uninspectable`, durable-auto must fail closed with that state surfaced in diagnostics
|
|
153
142
|
- detached local processes are diagnostic-only evidence and must fail closed instead of being treated as a successful async start
|
|
154
|
-
-
|
|
155
|
-
-
|
|
143
|
+
- refreshed `linked_pr_ready_for_followup` for an issue target with a resolved linked PR: promote stale bootstrap waiting to the linked PR follow-up path, or fail closed if the linked-PR facts are incomplete/contradictory, instead of preserving the old bootstrap wait route
|
|
144
|
+
- refreshed `prior_linked_pr_closed_unmerged` for a Copilot-owned issue target with `issueLinkageResolution=resolved_no_open_pr`: fail closed to reconcile instead of treating the issue as a healthy bootstrap wait or fresh issue-intake path
|
|
156
145
|
|
|
157
146
|
Resolved bundle output shape:
|
|
158
147
|
|
|
@@ -222,8 +211,8 @@ Resolved bundle output shape:
|
|
|
222
211
|
|
|
223
212
|
Dev-mode observability requirement:
|
|
224
213
|
|
|
225
|
-
- saved artifacts
|
|
226
|
-
- wait/watch artifacts
|
|
214
|
+
- saved artifacts MUST preserve the `contractTrace` decision, wait strategy, state-refresh boundary, and stop classification so a fresh session can explain a re-attach, stop, or fail-closed without replaying the run
|
|
215
|
+
- wait/watch artifacts MUST record the effective timeout budget and whether the seam ran as `persistent_watch` or `one_shot_probe`; a surface without a poll interval MAY record `effectivePollIntervalMs=null` instead of inventing one
|
|
227
216
|
|
|
228
217
|
Fail-closed semantics:
|
|
229
218
|
|
|
@@ -271,7 +260,7 @@ Internal strategy naming is implementation detail; normal orchestration always s
|
|
|
271
260
|
|
|
272
261
|
Tracker-backed local implementation is an input-source addition to the existing `local_implementation` strategy. It does **not** create a new routing mode, strategy family, or public workflow entrypoint.
|
|
273
262
|
|
|
274
|
-
For tracker-backed local sessions, the tracker issue is canonical
|
|
263
|
+
For tracker-backed local sessions, the tracker issue is canonical; the no-duplicate-phase-doc rule is owned by `ARTIFACT-TRACKER-FIRST-NO-DUP` in [Artifact Authority Contract](artifact-authority-contract.md).
|
|
275
264
|
|
|
276
265
|
Deterministic GitHub-backed spec resolution:
|
|
277
266
|
|
|
@@ -284,13 +273,13 @@ Deterministic GitHub-backed spec resolution:
|
|
|
284
273
|
State-sync expectations for this slice:
|
|
285
274
|
|
|
286
275
|
- local branch state and `tmp/` artifacts remain local execution state
|
|
287
|
-
- durable scope / acceptance / status changes discovered during local execution
|
|
276
|
+
- durable scope / acceptance / status changes discovered during local execution SHOULD sync back to the tracker issue
|
|
288
277
|
- this slice does **not** introduce full bidirectional tracker sync or tracker-provider adapters beyond the bounded GitHub-backed helper path above
|
|
289
278
|
|
|
290
279
|
Non-duplication rule:
|
|
291
280
|
|
|
292
281
|
- do not create, read, or update `docs/phases/phase-<n>.md` for the same tracker-backed session
|
|
293
|
-
- if a duplicate local phase doc already exists
|
|
282
|
+
- if a duplicate local phase doc already exists, reconcile explicitly before continuing rather than keeping two durable spec surfaces alive
|
|
294
283
|
|
|
295
284
|
## Copilot-first issue-assignment seam (unassigned issues)
|
|
296
285
|
|
|
@@ -330,7 +319,7 @@ For issue targets, authoritative issue↔PR linkage resolution remains part of s
|
|
|
330
319
|
|
|
331
320
|
- when canonical issue state includes `linkedPr`, route selection first uses that linked PR as the authoritative routable artifact
|
|
332
321
|
- when canonical issue state does **not** include `linkedPr`, status/reporting consumers must still require explicit authoritative linkage resolution before asserting there is no open linked PR
|
|
333
|
-
- when authoritative linkage resolves an already-open linked PR, that PR is the only canonical active artifact for the issue during follow-up; startup/status/follow-up
|
|
322
|
+
- <!-- rule: FACADE-LINKED-PR-SINGLE-ARTIFACT --> `FACADE-LINKED-PR-SINGLE-ARTIFACT`: when authoritative linkage resolves an already-open linked PR, that PR is the only canonical active artifact for the issue during follow-up; startup/status/follow-up MUST reuse it and MUST fail closed against opening another PR until the prior state is explicitly reconciled
|
|
334
323
|
|
|
335
324
|
## Deterministic routing order
|
|
336
325
|
|
|
@@ -349,6 +338,28 @@ First-match-wins routing posture:
|
|
|
349
338
|
11. PR owned by Copilot -> `copilot_pr_followup`
|
|
350
339
|
12. anything else -> fail closed to `needs_reconcile`
|
|
351
340
|
|
|
341
|
+
## Required transitions
|
|
342
|
+
|
|
343
|
+
The gate graph (`DEV_LOOP_GATE` / `PUBLIC_DEV_LOOP_GATE_CONTRACT` in
|
|
344
|
+
`public-dev-loop-routing.mjs`) is stateless per cycle: each `evaluatePublicDevLoopRouting`
|
|
345
|
+
call re-derives one gate from fresh authoritative state, so every non-terminal (route/wait)
|
|
346
|
+
gate can be followed, on the next cycle, by any of the gates.
|
|
347
|
+
|
|
348
|
+
- `final_approval` -> any dev-loop gate
|
|
349
|
+
- `wait_watch` -> any dev-loop gate
|
|
350
|
+
- `local_implementation` -> any dev-loop gate
|
|
351
|
+
- `issue_intake` -> any dev-loop gate
|
|
352
|
+
- `external_pr_followup` -> any dev-loop gate
|
|
353
|
+
- `reviewer_fixer` -> any dev-loop gate
|
|
354
|
+
- `copilot_pr_followup` -> any dev-loop gate
|
|
355
|
+
|
|
356
|
+
Terminal gates (`stop_blocked_or_not_authorized`, `stop_done_terminal`,
|
|
357
|
+
`waiting_for_merge_authorization`, `fail_closed_reconcile`) have no outgoing transitions —
|
|
358
|
+
reaching one ends the current evaluation cycle. Their route-kind classification
|
|
359
|
+
(`stop` / `needs_reconcile`) is the authoritative terminal marker; the route/wait gates above
|
|
360
|
+
are the authoritative non-terminal set. This machine is wired into the L2/L3 state-machine
|
|
361
|
+
conformance harness (`validate-state-machine-conformance.mjs`).
|
|
362
|
+
|
|
352
363
|
## Conflict reconciliation path (`CONFLICTING` / `DIRTY`)
|
|
353
364
|
|
|
354
365
|
When an open linked PR reports merge conflict against `main`, treat this as an explicit bounded local-agent reconciliation path, not as a blind merge/update step:
|
|
@@ -360,27 +371,33 @@ When an open linked PR reports merge conflict against `main`, treat this as an e
|
|
|
360
371
|
- issue/PR scope and acceptance criteria
|
|
361
372
|
- current-head gate evidence and relevant unresolved review feedback
|
|
362
373
|
- local validation surface for the touched conflict slice
|
|
363
|
-
3. if required authoritative context is missing, stale for the current head, or contradictory, fail closed to reconcile
|
|
374
|
+
3. <!-- rule: FACADE-CONFLICT-CONTEXT-FAIL-CLOSED --> `FACADE-CONFLICT-CONTEXT-FAIL-CLOSED`: if required authoritative context is missing, stale for the current head, or contradictory, orchestration MUST fail closed to reconcile
|
|
364
375
|
4. only when that context is complete for one current head, resolve the conflict locally on the PR branch
|
|
365
|
-
5. after conflict resolution, rerun required local validation, gate checks, and required CI checks for the new head before approval/merge evaluation
|
|
376
|
+
5. <!-- rule: FACADE-CONFLICT-REVALIDATE-NEW-HEAD --> `FACADE-CONFLICT-REVALIDATE-NEW-HEAD`: after conflict resolution, orchestration MUST rerun required local validation, gate checks, and required CI checks for the new head before approval/merge evaluation
|
|
366
377
|
|
|
367
378
|
## `auto dev loop` durable auto contract
|
|
368
379
|
|
|
369
|
-
When the public intent is `auto dev loop`, the router
|
|
380
|
+
When the public intent is `auto dev loop`, the router MUST:
|
|
370
381
|
|
|
371
382
|
1. require canonical current state resolution first
|
|
372
383
|
2. route to the same detected internal strategy as normal state-based routing
|
|
373
384
|
3. mark execution mode as durable auto ownership (`durable_auto`)
|
|
374
385
|
4. keep waiting/watch states in healthy-wait semantics (`auto_healthy_wait`)
|
|
375
386
|
|
|
376
|
-
In healthy waiting states, quiet watcher observations (for example `timeout` or `idle`) are observational only and
|
|
387
|
+
In healthy waiting states, quiet watcher observations (for example `timeout` or `idle`) are observational only and MUST NOT be surfaced as attention by themselves. Escalation is still expected for true blocked/authorization/reconcile states.
|
|
377
388
|
|
|
378
|
-
|
|
379
|
-
When refreshed authoritative bootstrap state instead resolves `prior_linked_pr_closed_unmerged`, that is not a healthy wait seam: the routed outcome must fail closed to reconcile so status/startup answers surface the prior closed-unmerged PR decision rather than implying normal watch continuity.
|
|
389
|
+
Bootstrap-only exception to the general blocked-escalation rule for `waiting_for_initial_copilot_implementation`:
|
|
380
390
|
|
|
381
|
-
|
|
391
|
+
| Rule ID | Condition | Outcome |
|
|
392
|
+
|---|---|---|
|
|
393
|
+
| <!-- rule: FACADE-BOOTSTRAP-WATCH-ROUTE --> `FACADE-BOOTSTRAP-WATCH-ROUTE` | durable-auto ownership of this seam | ownership MUST route to the dedicated `watch-initial-copilot-pr.mjs` watcher with its default 1-hour watch budget |
|
|
394
|
+
| <!-- rule: FACADE-BOOTSTRAP-QUIET-NO-EJECT --> `FACADE-BOOTSTRAP-QUIET-NO-EJECT` | quiet/no-activity observation while refreshed state still resolves this seam | durable ownership MUST NOT be ejected; inspect/status intents MAY still summarize that state and exit normally |
|
|
395
|
+
| <!-- rule: FACADE-BOOTSTRAP-ACTION-REQUIRED-NONBLOCKING --> `FACADE-BOOTSTRAP-ACTION-REQUIRED-NONBLOCKING` | bootstrap-only linked PR; approval-gated Actions/Copilot run reports `action_required` (a run conclusion, not a lifecycle state) | treated as a non-blocking observational signal (concluded session activity); MUST NOT by itself force stop/escalation |
|
|
396
|
+
| <!-- rule: FACADE-BOOTSTRAP-CLOSED-UNMERGED-RECONCILE --> `FACADE-BOOTSTRAP-CLOSED-UNMERGED-RECONCILE` | refreshed bootstrap state resolves `prior_linked_pr_closed_unmerged` | MUST fail closed to reconcile so status/startup surfaces the prior closed-unmerged decision instead of normal watch continuity |
|
|
397
|
+
| <!-- rule: FACADE-BOOTSTRAP-FOLLOWUP-REENTRY --> `FACADE-BOOTSTRAP-FOLLOWUP-REENTRY` | refreshed seam state advances to `linked_pr_ready_for_followup` | durable-auto continuation MUST re-enter the same linked PR follow-up path |
|
|
398
|
+
| <!-- rule: FACADE-BOOTSTRAP-ISOLATED-WORKTREE-CONTINUATION --> `FACADE-BOOTSTRAP-ISOLATED-WORKTREE-CONTINUATION` | follow-up handoff carries `conductorRouting.handoffEnvelope.requiresLocalIsolation=true` | orchestration SHOULD continue through an isolated checkout/worktree transition rather than treat that boundary as final completion (the runtime surfaces the flag; it does not enforce re-entry) |
|
|
382
399
|
|
|
383
|
-
Main conductor orchestration
|
|
400
|
+
Main conductor orchestration MUST treat non-terminal follow-up/wait states (for example `waiting_for_copilot_review`) as continuation boundaries rather than clean completion. If an async child exits before the requested stop boundary and continuation is feasible, re-dispatch via the main session driver (the subagent exits on external wait; the main session re-dispatches); otherwise surface the concrete blocker.
|
|
384
401
|
|
|
385
402
|
## Internal / external model
|
|
386
403
|
|
|
@@ -413,9 +430,9 @@ flowchart TD
|
|
|
413
430
|
|
|
414
431
|
- `dev-loop` is the only intended public workflow entrypoint.
|
|
415
432
|
- any remaining specialized Copilot behavior is internal-only and non-user-invocable behind the canonical internal route-pack surface (`issue-intake`, `copilot-pr-followup`, `local-implementation`, `final-approval`).
|
|
416
|
-
- Documentation and examples
|
|
417
|
-
-
|
|
418
|
-
- User-visible variation
|
|
433
|
+
- Documentation and examples SHOULD lead with `dev-loop` and explain routed behavior.
|
|
434
|
+
- Workflow branching SHOULD converge into deterministic state-machine/tooling surfaces behind `dev-loop`.
|
|
435
|
+
- User-visible variation SHOULD be expressed through the `dev-loop` API/parameters or settings, not multiple public workflow names or legacy compatibility seams.
|
|
419
436
|
|
|
420
437
|
## Bounded variation parameter contract
|
|
421
438
|
|
|
@@ -461,7 +478,7 @@ The following parameter/state combinations fail closed to `needs_reconcile` inst
|
|
|
461
478
|
| `mode=bounded_handoff` + `intent=auto_continue_current` | `auto_continue_current` always requires durable auto execution mode |
|
|
462
479
|
| Unrecognized `mode` value | Value not on the bounded allow-list |
|
|
463
480
|
| Unrecognized `targetPreference` value | Value not on the bounded allow-list |
|
|
464
|
-
| `watch=true` when an otherwise-successful routed result is not wait/watch-eligible | Watch semantics require a routed wait result (`routeKind=wait`), not just `selectedGate=wait_watch`;
|
|
481
|
+
| `watch=true` when an otherwise-successful routed result is not wait/watch-eligible | Watch semantics require a routed wait result (`routeKind=wait`), not just `selectedGate=wait_watch`; `stop`/`needs_reconcile` outcomes stay authoritative |
|
|
465
482
|
| Non-boolean `watch` value | Value is outside the bounded boolean allow-list and must fail closed |
|
|
466
483
|
| `targetPreference=prefer_local` when authoritative state has a linked PR or active PR artifact | Preference must not override authoritative PR/linked-PR active artifact truth |
|
|
467
484
|
| `mode=durable_auto` without authoritative current state | Durable auto requires authoritative current state to route from |
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Retrospective checkpoint contract
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Canonical owner for the enforcement seam of the post-run behavioral retrospective checkpoint after qualifying async `dev-loop` completions in this repository.
|
|
4
|
+
|
|
5
|
+
<!-- rule: RETRO-ENFORCEMENT-CONFIG-GATED -->
|
|
6
|
+
Whether a missing checkpoint blocks the next qualifying start/resume MUST be controlled by `.devloops` at repo root `workflow.requireRetrospective`; shipped defaults remain permissive and this repo opts in.
|
|
4
7
|
|
|
5
8
|
## Relationship to formal dev mode
|
|
6
9
|
|
|
@@ -85,21 +88,24 @@ Callers have two supported integration options:
|
|
|
85
88
|
4. Call `evaluateRetrospectiveGate({ checkpointState, proposedRouting })`.
|
|
86
89
|
5. Use the gate result (not the raw routing result) as the effective routing decision when enforcement is enabled; otherwise keep the raw routing result and treat the checkpoint artifact as advisory context only.
|
|
87
90
|
|
|
88
|
-
|
|
91
|
+
<!-- rule: RETRO-GATE-FAIL-CLOSED -->
|
|
92
|
+
If the gate result is `needs_reconcile`, the caller MUST NOT proceed with the proposed routing. The `nextAction` field instructs the operator to complete or explicitly skip the retrospective.
|
|
89
93
|
|
|
90
94
|
## Advisory findings — never a merge gate (issue #1077, Reading B)
|
|
91
95
|
|
|
96
|
+
<!-- rule: RETRO-ADVISORY-NEVER-GATE -->
|
|
92
97
|
The retrospective is **advisory**: it runs, records flagged raw-call / discipline
|
|
93
98
|
observations honestly, and passes them back to the conductor (main agent) to
|
|
94
|
-
**decide** what to do with them — but it
|
|
95
|
-
transition
|
|
99
|
+
**decide** what to do with them — but it MUST NOT block a merge or any PR-lifecycle
|
|
100
|
+
transition of the current run. The pre-merge retrospective gate (`evaluateRetrospectiveMergeApproval`
|
|
96
101
|
and the `requireRetrospectiveGate` / `requireRetrospectiveInternalTooling` config
|
|
97
102
|
keys) has been **removed**. There is no `retrospective_gate_pending` / `blocked`
|
|
98
103
|
disposition on account of the internal-tooling raw-call record.
|
|
99
104
|
|
|
100
105
|
### How findings travel (Reading B)
|
|
101
106
|
|
|
102
|
-
|
|
107
|
+
<!-- rule: RETRO-FINDINGS-ENVELOPE-CARRY -->
|
|
108
|
+
1. **Deterministic return contract.** The loop subagent's handoff envelope MUST carry
|
|
103
109
|
the retrospective findings as a structured `retrospectiveFindings` field — the
|
|
104
110
|
`check-retro-tooling.mjs` JSON output (`{ internalToolingOnly, rawCallViolations,
|
|
105
111
|
allowedWriteOps }`), not prose. The conductor reads that field. This is a hard
|
|
@@ -129,10 +135,20 @@ scripts legitimately call `gh`/GraphQL internally; that is the tooling. The rule
|
|
|
129
135
|
targets the agent's own top-level shell calls, not a script's internals.
|
|
130
136
|
|
|
131
137
|
**Write-op allowlist (verifier only):** `gh pr merge`, `gh pr ready`,
|
|
132
|
-
`gh issue create
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
138
|
+
`gh issue create` have no internal wrapper today. `gh issue edit` now has one
|
|
139
|
+
(`scripts/github/edit-issue.mjs`) and stays as a belt-and-suspenders entry — like
|
|
140
|
+
`gh label create` (`scripts/github/create-label.mjs`) — so a bare invocation
|
|
141
|
+
surfaced from the wrapper's own subprocess is not miscounted as a breach. The
|
|
142
|
+
deterministic verifier records all of these as `allowedWriteOps` rather than
|
|
143
|
+
violations so they are surfaced distinctly, not as breaches. Close the gap with a
|
|
144
|
+
wrapper to remove or reframe a no-wrapper entry. None of these block anything.
|
|
145
|
+
|
|
146
|
+
**Inline-interpreter check item:** the raw-call scan below mechanically catches
|
|
147
|
+
`node -e`/`python3 -c`/heredoc calls as a `rawCallViolations` entry — the same
|
|
148
|
+
class barred by `OPS-NO-INLINE-INTERPRETER` in
|
|
149
|
+
[Copilot loop operations](copilot-loop-operations.md). This is an addition to
|
|
150
|
+
what the retrospective records, not a new gate: `RETRO-ADVISORY-NEVER-GATE`
|
|
151
|
+
semantics are unchanged.
|
|
136
152
|
|
|
137
153
|
### Deterministic verifier (findings-producer)
|
|
138
154
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Spike-mode contract
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Canonical owner for spike mode: the time-boxed, exploratory dev-loop run started from a local question with no GitHub issue. Its deliverable is a findings document. When the exploration reaches a recommendation, the operator concludes it with one of two exits: **discard** (drop it with zero tracker artifacts) or **graduate** (emit a #947-style local-first plan file that enters the existing plan→PR promotion path).
|
|
4
4
|
|
|
5
5
|
This doc is the canonical operator sequence for spike mode and carries a worked example showing both exits. The spike artifact lives outside the tracker; it is exempt from the production-gate ceremony at entry and runs under a relaxed gate profile (`gates.spike`). The [Artifact Authority Contract](artifact-authority-contract.md) owns the local-planning model a graduated spike feeds into.
|
|
6
6
|
|
|
@@ -53,7 +53,10 @@ Hand the artifact to startup with `--spike` (mutually exclusive with `--issue`,
|
|
|
53
53
|
node scripts/loop/resolve-dev-loop-startup.mjs --spike <spike.md>
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
`buildSpikeInput` (`scripts/loop/resolve-dev-loop-startup.mjs`) reads the file read-only — no tracker mutation, no GitHub call, no issue or PR number.
|
|
56
|
+
`buildSpikeInput` (`scripts/loop/resolve-dev-loop-startup.mjs`) reads the file read-only — no tracker mutation, no GitHub call, no issue or PR number.
|
|
57
|
+
|
|
58
|
+
<!-- rule: SPIKE-STARTUP-SCAFFOLD-GATE -->
|
|
59
|
+
Startup MUST require the exploration scaffold: a missing/unreadable file, or one failing `validateSpikeExplorationSections`, MUST throw, and startup MUST fail closed (exit 1, no readiness bundle). On success it builds a `local_phase` startup input with the resolved spike path as the target `phase` and threads `spikeIntakeState` onto the output. A spike with no Recommendation reports `spike_in_progress`. The spike path is exempt from the worktree-isolation guard because there is no issue to key a worktree on (`planFileExempt: true`).
|
|
57
60
|
|
|
58
61
|
### 3. Run under the relaxed gate profile
|
|
59
62
|
|
|
@@ -67,7 +70,8 @@ When the exploration concludes, fill in `## Recommendation`. The intake state is
|
|
|
67
70
|
node scripts/refine/exit-spike.mjs --spike-file <spike.md> --disposition <discard|graduate> [--plan-file <path>] [--json]
|
|
68
71
|
```
|
|
69
72
|
|
|
70
|
-
|
|
73
|
+
<!-- rule: SPIKE-EXIT-ELIGIBILITY -->
|
|
74
|
+
`evaluateSpikeExit` (`packages/core/src/loop/spike-exit-contract.mjs`) MUST be eligible only from `spike_ready_for_exit`: from any other state it MUST fail closed with `not_ready_for_exit`, and an unrecognized disposition MUST fail closed with `unknown_disposition`. On a fail-closed path the CLI MUST make zero tracker mutation, write no plan file, and exit 1.
|
|
71
75
|
|
|
72
76
|
## Exit dispositions
|
|
73
77
|
|
|
@@ -75,22 +79,25 @@ The two dispositions are `SPIKE_EXIT_DISPOSITION.DISCARD` (`"discard"`) and `SPI
|
|
|
75
79
|
|
|
76
80
|
### discard
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
<!-- rule: SPIKE-DISCARD-ZERO-MUTATION -->
|
|
83
|
+
The recommendation is "don't pursue". Discard MUST drop the spike with zero tracker artifacts — the findings document on disk is the whole record. The CLI MUST write nothing and MUST create no GitHub artifact. `--plan-file` is irrelevant for a discard.
|
|
79
84
|
|
|
80
85
|
### graduate
|
|
81
86
|
|
|
82
|
-
|
|
87
|
+
<!-- rule: SPIKE-GRADUATE-PLAN-FILE-REQUIRED -->
|
|
88
|
+
The recommendation is "pursue this". `buildGraduatedPlanBody` builds a #947-consumable plan-file body from the spike's `Question`, `Approach`, `Findings`, and `Recommendation`, and `exit-spike.mjs` writes it to the required `--plan-file` path — `--plan-file` MUST be present for a graduate exit; the CLI MUST NOT guess an output path. The mapping:
|
|
83
89
|
|
|
84
90
|
- `Question` + `Approach` become the Objective's context.
|
|
85
91
|
- `Recommendation` becomes the In-scope work.
|
|
86
92
|
- `Findings` are recorded as supporting evidence.
|
|
87
93
|
- A fixed Explicit non-goals block keeps the plan from re-opening the concluded exploration.
|
|
88
94
|
|
|
89
|
-
The emitted body carries the four plan-file base sections (`## Status`, `## Objective`, `## In scope`, `## Explicit non-goals` — see [Plan-file Contract](plan-file-contract.md)), so it passes `validatePlanFile` and enters the local-first plan→PR promotion path (#952) unchanged: refine it, hold the local human-review checkpoint, then `promote-plan.mjs`. Graduation is idempotent — `buildGraduatedPlanBody` is pure, so re-running reproduces the same plan file
|
|
95
|
+
The emitted body carries the four plan-file base sections (`## Status`, `## Objective`, `## In scope`, `## Explicit non-goals` — see [Plan-file Contract](plan-file-contract.md)), so it passes `validatePlanFile` and enters the local-first plan→PR promotion path (#952) unchanged: refine it, hold the local human-review checkpoint, then `promote-plan.mjs`. Graduation is idempotent — `buildGraduatedPlanBody` is pure, so re-running reproduces the same plan file, and it fails closed (throws) on an empty required section, so a graduate exit cannot emit a plan the validator would reject.
|
|
90
96
|
|
|
91
97
|
## Relaxed gate profile
|
|
92
98
|
|
|
93
|
-
|
|
99
|
+
<!-- rule: SPIKE-RELAXED-GATE-PROFILE -->
|
|
100
|
+
A spike's deliverable is a findings doc, so it MUST NOT carry the full production draft → pre-approval → Copilot gate set; it runs under `gates.spike`, a relaxed profile shipped in `packages/core/src/config/extension-defaults.yaml`:
|
|
94
101
|
|
|
95
102
|
```yaml
|
|
96
103
|
gates:
|
|
@@ -2,29 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
Canonical owner for agent stop / wait / block conditions across all workflow families.
|
|
4
4
|
|
|
5
|
+
## Terms
|
|
6
|
+
|
|
7
|
+
| Term | Definition |
|
|
8
|
+
|---|---|
|
|
9
|
+
| <!-- term: state:blocked --> `blocked` | Lifecycle state requiring a human decision before the loop continues. |
|
|
10
|
+
| <!-- term: state:done --> `done` | Terminal lifecycle state. |
|
|
11
|
+
| <!-- term: state:approval_ready --> `approval_ready` | Lifecycle state where approval evidence is ready but merge authorization is not implied. |
|
|
12
|
+
| <!-- term: state:merge_ready --> `merge_ready` | Lifecycle state where merge preconditions are ready to evaluate. |
|
|
13
|
+
| <!-- term: state:waiting --> `waiting` | Lifecycle state for healthy external waits. |
|
|
14
|
+
| <!-- term: state:waiting_for_initial_copilot_implementation --> `waiting_for_initial_copilot_implementation` | Bootstrap wait state for the first Copilot PR. |
|
|
15
|
+
| <!-- term: state:waiting_for_copilot_review --> `waiting_for_copilot_review` | Copilot review-settle wait state for the current head. |
|
|
16
|
+
| <!-- term: state:waiting_for_merge_authorization --> `waiting_for_merge_authorization` | Stop state for merge-ready work without explicit merge authorization. |
|
|
17
|
+
| <!-- term: reason:needs_reconcile --> `needs_reconcile` | Reconcile reason for ambiguous, contradictory, or unsupported state. |
|
|
18
|
+
|
|
5
19
|
## Genuine stop conditions
|
|
6
20
|
|
|
7
|
-
| Condition | Strategy | Behavior |
|
|
8
|
-
|
|
9
|
-
| `blocked` lifecycle state | all |
|
|
10
|
-
| `done` lifecycle state | all |
|
|
11
|
-
| `approval_ready` without explicit merge
|
|
12
|
-
| `merge_ready` without explicit merge
|
|
13
|
-
| `autonomy.humanMergeOnly: true` | all |
|
|
14
|
-
| Ambiguous
|
|
15
|
-
| Missing authoritative startup inputs | `dev-loop` |
|
|
21
|
+
| Rule ID | Condition | Strategy | Behavior |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| <!-- rule: STOP-BLOCKED-001 --> `STOP-BLOCKED-001` | `blocked` lifecycle state | all | The loop MUST stop for a human decision. |
|
|
24
|
+
| <!-- rule: STOP-DONE-001 --> `STOP-DONE-001` | `done` lifecycle state | all | The loop MUST treat the state as terminal. |
|
|
25
|
+
| <!-- rule: STOP-APPROVAL-001 --> `STOP-APPROVAL-001` | `approval_ready` without explicit merge authorization | `final_approval` | The loop MUST stop at the approval gate. |
|
|
26
|
+
| <!-- rule: STOP-MERGE-AUTH-001 --> `STOP-MERGE-AUTH-001` | `merge_ready` without explicit merge authorization | all | The loop MUST stop at `waiting_for_merge_authorization`. |
|
|
27
|
+
| <!-- rule: STOP-HUMAN-MERGE-001 --> `STOP-HUMAN-MERGE-001` | `autonomy.humanMergeOnly: true` | all | The loop MUST stop at merge for human action even with explicit merge authorization; the agent MUST NOT run `gh pr merge` (see [Merge preconditions](merge-preconditions.md)). |
|
|
28
|
+
| <!-- rule: STOP-RECONCILE-001 --> `STOP-RECONCILE-001` | Ambiguous or contradictory state | all | The loop MUST fail closed to `needs_reconcile`. |
|
|
29
|
+
| <!-- rule: STOP-STARTUP-INPUTS-001 --> `STOP-STARTUP-INPUTS-001` | Missing authoritative startup inputs | `dev-loop` | The loop MUST fail closed. |
|
|
16
30
|
|
|
17
31
|
## Non-stop conditions
|
|
18
32
|
|
|
19
|
-
| Condition | Strategy | Behavior |
|
|
20
|
-
|
|
21
|
-
| `waiting` lifecycle state | `wait_watch` |
|
|
22
|
-
| `waiting_for_initial_copilot_implementation` | `issue_intake` |
|
|
23
|
-
| `waiting_for_copilot_review` | `copilot_pr_followup` |
|
|
24
|
-
| Quiet watcher observations | `wait_watch` |
|
|
33
|
+
| Rule ID | Condition | Strategy | Behavior |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| <!-- rule: STOP-WAIT-001 --> `STOP-WAIT-001` | `waiting` lifecycle state | `wait_watch` | The loop MUST treat this as a healthy wait and re-dispatch from the main session. |
|
|
36
|
+
| <!-- rule: STOP-INITIAL-COPILOT-001 --> `STOP-INITIAL-COPILOT-001` | `waiting_for_initial_copilot_implementation` | `issue_intake` | The loop MUST use the bootstrap wait with a one-hour watch budget. |
|
|
37
|
+
| <!-- rule: STOP-COPILOT-REVIEW-001 --> `STOP-COPILOT-REVIEW-001` | `waiting_for_copilot_review` | `copilot_pr_followup` | The loop MUST treat this as a continuation boundary, not completion. |
|
|
38
|
+
| <!-- rule: STOP-QUIET-WATCHER-001 --> `STOP-QUIET-WATCHER-001` | Quiet watcher observations | `wait_watch` | The loop MUST treat quiet observations as observational only and MUST NOT surface them as stops by themselves. |
|
|
25
39
|
|
|
26
40
|
## Cross-references
|
|
27
41
|
|
|
28
42
|
- [Confirmation rules](confirmation-rules.md)
|
|
29
43
|
- [Merge preconditions](merge-preconditions.md)
|
|
30
44
|
- [Public Dev Loop Contract](public-dev-loop-contract.md)
|
|
45
|
+
- [Contract style guide](contract-style-guide.md)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Tracker-First Story-to-PR Contract
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
story-to-PR workflow in `dev-loops
|
|
3
|
+
Canonical owner for the adapter-agnostic MVP contract for the tracker-first
|
|
4
|
+
story-to-PR workflow in `dev-loops`, and for the tracker-first loop state
|
|
5
|
+
machine (#449).
|
|
5
6
|
|
|
6
7
|
**MVP invariant: one tracker work item → one GitHub PR.**
|
|
7
8
|
|
|
@@ -30,7 +31,8 @@ Implementation for each:
|
|
|
30
31
|
| Epic / PRD reference | Optional linked metadata only; no roll-up or automation in this slice |
|
|
31
32
|
| ADR / RFC reference | Optional linked metadata only; no decision-sync in this slice |
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
<!-- rule: TRACKER-ONE-ACTIVE-PR -->
|
|
35
|
+
For any single tracker work item in scope, there MUST be at most
|
|
34
36
|
one active GitHub PR at a time. Multi-PR workflows and roll-up automation
|
|
35
37
|
are out of scope for this slice.
|
|
36
38
|
|
|
@@ -57,6 +59,9 @@ already-correct PR leaves it unchanged.
|
|
|
57
59
|
|
|
58
60
|
### 3.1 Required PR Metadata
|
|
59
61
|
|
|
62
|
+
<!-- rule: TRACKER-PROJECTION-REQUIRED-METADATA -->
|
|
63
|
+
Every projected PR MUST carry the following fields:
|
|
64
|
+
|
|
60
65
|
| Field | Rule |
|
|
61
66
|
|---|---|
|
|
62
67
|
| PR title | `[{TRACKER_ID}] {tracker item title}` — bracketed tracker identifier followed by the item title verbatim |
|
|
@@ -64,7 +69,7 @@ already-correct PR leaves it unchanged.
|
|
|
64
69
|
| PR body — Summary section | Required. Brief description of the change implemented in this PR. |
|
|
65
70
|
| PR body — Acceptance Criteria section | Required. Copied or linked from the tracker item's acceptance criteria. |
|
|
66
71
|
| Labels | Required: `tracker:{TRACKER_ID}`. Optional reference labels: `epic:{EPIC_ID}`, `prd:{PRD_ID}` when references are present. |
|
|
67
|
-
| Draft state | PR
|
|
72
|
+
| Draft state | PR MUST start as a draft. It MUST NOT be marked ready-for-review until development work is complete. |
|
|
68
73
|
|
|
69
74
|
### 3.2 Optional Reference Metadata
|
|
70
75
|
|
|
@@ -85,9 +90,9 @@ They are read-only metadata in this slice and do not trigger any automation:
|
|
|
85
90
|
2. **On tracker item field change**: Re-apply projection rules to PR title,
|
|
86
91
|
body, and labels. Leave any sections not covered by projection rules
|
|
87
92
|
(e.g. reviewer-added review comments) intact.
|
|
88
|
-
3. **Idempotent regeneration**:
|
|
89
|
-
sections, and labels
|
|
90
|
-
|
|
93
|
+
3. <!-- rule: TRACKER-PROJECTION-IDEMPOTENT --> **Idempotent regeneration**: Projection MUST be a no-op when the PR already has the correct
|
|
94
|
+
title, body sections, and labels — re-applying the rules to an already-correct PR MUST NOT
|
|
95
|
+
mutate it.
|
|
91
96
|
|
|
92
97
|
### 3.4 PR Body Template
|
|
93
98
|
|
|
@@ -120,7 +125,7 @@ implementations map canonical action names to tracker-native field updates.
|
|
|
120
125
|
| `pr_merged` — PR merged | `set_done` | Tracker moves to done/completed terminal state |
|
|
121
126
|
| `pr_closed_unmerged` — PR closed without merge | `none` | No automatic terminal transition; human decision required |
|
|
122
127
|
| `no_tracker_item` | `none` | No tracker item to update |
|
|
123
|
-
| `blocked_needs_user_decision` | `none` |
|
|
128
|
+
| <!-- rule: TRACKER-BLOCKED-FAIL-CLOSED --> `blocked_needs_user_decision` | `none` | An unexpected or contradictory snapshot MUST stop and report; the helper MUST NOT apply an automatic tracker update |
|
|
124
129
|
|
|
125
130
|
### 4.2 Event Triggers
|
|
126
131
|
|
|
@@ -4,9 +4,8 @@ Canonical owner for validation requirements across all workflow families.
|
|
|
4
4
|
|
|
5
5
|
## Default validation
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
- At minimum: `npm test && npm run test:dev-loop`
|
|
7
|
+
<!-- rule: VALIDATE-VERIFY-BEFORE-GATE -->
|
|
8
|
+
`VALIDATE-VERIFY-BEFORE-GATE`: `npm run verify` is the default repo-level local validation path and MUST pass before PR creation, gate entry, and merge; at minimum this means `npm test && npm run test:dev-loop`.
|
|
10
9
|
|
|
11
10
|
## Gate-specific requirements
|
|
12
11
|
|
|
@@ -17,8 +16,8 @@ Canonical owner for validation requirements across all workflow families.
|
|
|
17
16
|
|
|
18
17
|
## Coverage requirements
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
-
|
|
19
|
+
<!-- rule: VALIDATE-COVERAGE-THRESHOLD -->
|
|
20
|
+
`VALIDATE-COVERAGE-THRESHOLD`: Changed files SHOULD maintain ≥90% coverage for lines, statements, functions, and branches (not enforced by the shipped verify config; treat it as the working target), and non-trivial logic MUST be test-first.
|
|
22
21
|
|
|
23
22
|
## Cross-references
|
|
24
23
|
|