dev-loops 0.7.2 → 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 +1 -1
- package/.claude/agents/refiner.md +2 -2
- package/.claude/agents/review.md +9 -12
- package/.claude/commands/loop-continue.md +2 -1
- package/.claude/commands/loop-enqueue.md +8 -1
- package/.claude/commands/loop-info.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 +5 -5
- package/.claude/skills/dev-loop/SKILL.md +7 -7
- package/.claude/skills/docs/acceptance-criteria-verification.md +12 -4
- package/.claude/skills/docs/anti-patterns.md +3 -3
- package/.claude/skills/docs/artifact-authority-contract.md +6 -4
- package/.claude/skills/docs/confirmation-rules.md +1 -1
- package/.claude/skills/docs/copilot-loop-operations.md +4 -2
- package/.claude/skills/docs/issue-intake-procedure.md +12 -3
- package/.claude/skills/docs/merge-preconditions.md +5 -3
- package/.claude/skills/docs/pr-lifecycle-contract.md +1 -1
- package/.claude/skills/docs/public-dev-loop-contract.md +2 -1
- package/.claude/skills/docs/retrospective-checkpoint-contract.md +9 -6
- package/.claude/skills/docs/validation-policy.md +1 -1
- package/.claude/skills/local-implementation/SKILL.md +3 -3
- package/.claude/skills/loop-grill/SKILL.md +34 -14
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +30 -0
- package/README.md +95 -189
- package/agents/refiner.agent.md +2 -2
- package/agents/review.agent.md +9 -12
- package/extension/README.md +5 -4
- package/package.json +5 -4
- package/scripts/docs/validate-state-machine-conformance.mjs +78 -1
- package/scripts/github/_gate-names.mjs +5 -0
- package/scripts/github/capture-review-threads.mjs +2 -2
- package/scripts/github/detect-checkpoint-evidence.mjs +7 -7
- package/scripts/github/edit-issue.mjs +259 -0
- 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 +17 -16
- package/scripts/github/upsert-checkpoint-verdict.mjs +25 -23
- package/scripts/github/verify-briefing-prefixes.mjs +224 -33
- package/scripts/github/write-gate-context.mjs +8 -4
- 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 +18 -14
- package/scripts/loop/detect-copilot-loop-state.mjs +11 -11
- package/scripts/loop/detect-internal-only-pr.mjs +6 -6
- package/scripts/loop/detect-pr-gate-coordination-state.mjs +117 -15
- package/scripts/loop/detect-refinement-grill-state.mjs +136 -0
- package/scripts/loop/run-watch-cycle.mjs +42 -7
- package/scripts/loop/sanctioned-commands.mjs +1 -0
- package/scripts/pages/build-state-atlas.mjs +15 -0
- package/scripts/projects/add-queue-item.mjs +87 -4
- package/skills/copilot-pr-followup/SKILL.md +5 -5
- package/skills/dev-loop/SKILL.md +2 -2
- package/skills/docs/acceptance-criteria-verification.md +12 -4
- package/skills/docs/anti-patterns.md +3 -3
- package/skills/docs/artifact-authority-contract.md +6 -4
- package/skills/docs/confirmation-rules.md +1 -1
- package/skills/docs/copilot-loop-operations.md +4 -2
- package/skills/docs/issue-intake-procedure.md +12 -3
- package/skills/docs/merge-preconditions.md +5 -3
- package/skills/docs/pr-lifecycle-contract.md +1 -1
- package/skills/docs/public-dev-loop-contract.md +2 -1
- package/skills/docs/required-rules.json +17 -1
- package/skills/docs/retrospective-checkpoint-contract.md +9 -6
- package/skills/docs/validation-policy.md +1 -1
- package/skills/local-implementation/SKILL.md +3 -3
- package/skills/loop-grill/SKILL.md +38 -17
|
@@ -23,7 +23,7 @@ The envelope is the primary handoff artifact — it is derived from resolver out
|
|
|
23
23
|
|
|
24
24
|
**Construction sequence:**
|
|
25
25
|
|
|
26
|
-
1. Run the deterministic startup resolver to produce the authoritative state bundle: `npx dev-loops@0.
|
|
26
|
+
1. Run the deterministic startup resolver to produce the authoritative state bundle: `npx dev-loops@0.8.0 loop startup --issue <n>` for issues, or `npx dev-loops@0.8.0 loop startup --pr <n>` for PRs.
|
|
27
27
|
2. Pass the resolver output, resolved settings (merged from `.devloops` and `.pi/dev-loop/defaults.yaml`), and current gate state to `buildDevLoopHandoffEnvelope()`.
|
|
28
28
|
3. **Validate the envelope** with `validateHandoffEnvelope()` before consuming any field. If validation returns `ok: false`, reject the handoff with the structured error — do not load requiredReads, do not execute nextAction, do not delegate.
|
|
29
29
|
4. Read the envelope as the first artifact.
|
|
@@ -35,13 +35,13 @@ For the active phase, require and produce:
|
|
|
35
35
|
|
|
36
36
|
- use exact wording from the source issue(s); when the governing input is a phase doc or other spec instead of an issue, use that source wording exactly for every explicit item in the matrix
|
|
37
37
|
- include every explicit acceptance criterion, definition-of-done item, and non-goal; do not skip items
|
|
38
|
-
- if no explicit definition of done exists, add a `Proposed DoD` subsection before the matrix
|
|
38
|
+
- <!-- rule: REFINER-DOD-PROPOSED-SUBSECTION --> `REFINER-DOD-PROPOSED-SUBSECTION`: if no explicit definition of done exists, add a `Proposed DoD` subsection before the matrix
|
|
39
39
|
- explicit risks, watchpoints, and unresolved questions
|
|
40
40
|
- validation steps and tests to write first
|
|
41
41
|
- durable decisions that SHOULD be preserved in the phase doc
|
|
42
42
|
- when the phase includes a bounded audit or scan: prioritized findings, the highest-value follow-up candidates, and an explicit statement of what the current phase will not rewrite or broaden
|
|
43
43
|
- When an audit artifact is provided, treat it as a first-class planning input: summarize the audited scope, list prioritized findings, include the highest-value follow-up candidates, and classify each meaningful finding as exactly one of current-phase scope/AC, DoD expectation, explicit non-goal / defer, or risk/watchpoint
|
|
44
|
-
- Do not invent audit findings when no audit artifact was provided
|
|
44
|
+
- <!-- rule: REFINER-NO-INVENT-AUDIT-FINDINGS --> `REFINER-NO-INVENT-AUDIT-FINDINGS`: Do not invent audit findings when no audit artifact was provided
|
|
45
45
|
- when the phase includes watcher or predicate-driven behavior: explicit timeout semantics and negative-case expectations for non-target identities/events
|
|
46
46
|
- when the phase relies on package-first shared helpers inside a source-loaded workspace: explicit integration expectations about whether local callers use published package imports or a thin source/workspace adapter during development
|
|
47
47
|
- cross-check the phase's claims against the contracts and docs they reference (the autonomous docs-grill step, see ../docs/docs-grill-step.md): surface code-vs-doc drift, stale references, and contract-surface inaccuracies as refinement findings while the claims are still being verified
|
package/.claude/agents/review.md
CHANGED
|
@@ -26,18 +26,15 @@ You are a focused pull request review agent. You review an implementation for co
|
|
|
26
26
|
|
|
27
27
|
## Scoped angle-review mode
|
|
28
28
|
|
|
29
|
-
This agent has two modes. The default mode is the full-PR review described in the rest of this file.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- **Reason about ADJACENT related code from the bundle first:** the `adjacentCode` bundle already includes the changed files' callers, callees, and imports (1-hop). Read those entries before opening anything else. For each changed function, trace the real call paths a defect would flow through, and confirm that caller and callee contracts still match (argument shapes, return shapes, error/null conventions, units). If the bundle truncated or stripped a file you need (see its `truncated`/`stripped` manifest), open that file directly to widen.
|
|
39
|
-
- **Review ADVERSARIALLY — hunt concrete defects:** actively try to break the changed code. Hunt for edge cases, missing or wrong input validation, numeric coercion bugs (NaN, Infinity, floats where integers are assumed, negative values, string-to-number coercion), null/undefined handling, off-by-one and boundary conditions, mismatched caller/callee contracts, and dedup/identity bugs (wrong key, reference vs. value equality, unstable ordering). For every finding, give the concrete `file:line` plus the specific failing scenario or input that triggers the defect — not high-altitude "is there a test?" commentary.
|
|
40
|
-
- **Strictly read-only, but WIDEN SCOPE when needed:** never edit files, stage, commit, push, request reviews, resolve threads, or post PR comments. Findings are returned via the output artifact only; fixes are applied later by the fix cycle, not by this agent. Because you are read-only, you MAY open any additional repository files required to judge your angle (callers, callees, contracts, sibling modules, configs, tests) — widening to read adjacent code is expected and safe. Record every file/module you consulted beyond the briefing's `changedFiles`/`diffPath` in the optional `contextWidened` field on your output artifact.
|
|
29
|
+
This agent has two modes. The default mode is the full-PR review described in the rest of this file. In **scoped angle-review mode** you are one per-angle reviewer of the gate-review fan-out. You are in this mode when the invocation supplies a single review `<angle>` plus a gate-context artifact path (`tmp/gate-context/<repo-slug>/pr-<N>/<gate>-<headSha>.json`, written by `scripts/github/write-gate-context.mjs`).
|
|
30
|
+
|
|
31
|
+
Its full execution shape is owned elsewhere — read those owners before reviewing and do not re-derive their rules here:
|
|
32
|
+
|
|
33
|
+
- The build-once neutral bundle seeding, fresh-context guard (`verify-fresh-review-context.mjs`), no-worktree-isolation prohibition (#1135), single-angle read-only scope, and briefing composition are owned by the [Gate Review Sub-Loop Contract](../docs/gate-review-sub-loop-contract.md) (`GATE-EXEC-BUILD-ONCE-SEED`, `GATE-EXEC-BRIEFING-PREFIX`) — you receive only the neutral artifact + your angle, never the orchestrating agent's conversation, opinions, or state.
|
|
34
|
+
- The adversarial reviewing behavior is owned by `COPILOT-FOLLOWUP-ADVERSARIAL-BRIEFING` in the [Copilot PR Follow-up Skill](../skills/copilot-pr-followup/SKILL.md): read the FULL diff (from `scope.diffPath`, or reconstruct it with `git diff` against the change base when `scope.diffPath` is null/missing — never a hunk-only review) plus the bundled adjacent code rather than re-deriving them, then hunt concrete `file:line` defects (edge cases, input validation, numeric coercion incl. NaN/Infinity/floats/negatives, null/undefined, boundary conditions, mismatched caller/callee contracts, dedup/identity bugs) over process nits, recording any scope-widening in the optional `contextWidened` field on your findings artifact.
|
|
35
|
+
|
|
36
|
+
Follow those owners, then return your findings via the structured artifact below (this agent's canonical output contract):
|
|
37
|
+
|
|
41
38
|
- **Structured findings artifact:** return a single JSON object the fan-in consolidator (`@dev-loops/core/loop/gate-fanin`) can parse, written to the deterministic per-angle path `tmp/gate-reviews/<repo-slug>/pr-<N>/<gate>-<headSha>/<angle>.json`:
|
|
42
39
|
|
|
43
40
|
```json
|
|
@@ -8,7 +8,8 @@ Continue a dev loop. Two forms, both handed to the `dev-loop` skill — do NOT p
|
|
|
8
8
|
|
|
9
9
|
- With an argument (`$ARGUMENTS` is an issue or PR — `123`, `#123`, or a GitHub URL): run the `dev-loop` skill with the public intent `continue dev loop on $ARGUMENTS`. Resolve that artifact's authoritative state first, then route; ignore board position.
|
|
10
10
|
|
|
11
|
-
- Bare (no `$ARGUMENTS`): resolve the single continue target from the board
|
|
11
|
+
- Bare (no `$ARGUMENTS`): resolve the single continue target from the board, per
|
|
12
|
+
`QUEUE-LIVE-PICKUP-SOURCE` <!-- rule-ref: QUEUE-LIVE-PICKUP-SOURCE --> (owned by `docs/projects-queue-contract.md`). Resolve the board's repo and project the same way the queue commands do, then run `node scripts/projects/resolve-active-board-item.mjs --repo <owner/name> --project <number>`. It continues the single **In Progress** item; if there is none, it picks the **HEAD of Next Up by position**. It fails closed (idle) when Next Up is empty (`QUEUE-NEXTUP-EMPTY-FAIL-CLOSED` <!-- rule-ref: QUEUE-NEXTUP-EMPTY-FAIL-CLOSED -->), and still fails closed on multiple In-Progress items. It never pulls from Backlog.
|
|
12
13
|
- It returns `{ ok: true, target: { kind, number }, source }` (`source` is `"in-progress"` or `"next-up"`) → run the `dev-loop` skill with the public intent `continue dev loop on #<number>` (the resolved `target.number`), so the intent carries the concrete target instead of re-resolving board state.
|
|
13
14
|
- It returns `{ ok: false, reason }` when there are multiple in-progress items, or when there is nothing in progress **and** Next Up is empty → FAIL CLOSED: print the reason verbatim and instruct the user to run `/loop-continue #N` explicitly (or prioritize a Backlog item into Next Up). Do NOT guess, and never pick from Backlog.
|
|
14
15
|
|
|
@@ -14,8 +14,15 @@ Add work to the dev-loop queue. Parse `$ARGUMENTS` before acting. The project is
|
|
|
14
14
|
- Run `node scripts/projects/add-queue-item.mjs --repo <owner/repo> --item <n>`.
|
|
15
15
|
- The script is idempotent and returns `{ ok, item: { status, alreadyPresent } }`. Report the resulting Status column and whether it was already present, e.g. `#<n> is in "Backlog" (already on the board)` or `#<n> added to "Backlog"`.
|
|
16
16
|
- Exit `3` means the issue/PR was not found (`ITEM_NOT_FOUND` / `CONTENT_NOT_FOUND`): print `Error: issue/PR #<n> not found.` and stop. Do not retry with a guessed project.
|
|
17
|
+
- Exit `4` means the issue targets the pickup (`Next Up`) column without a refinement artifact (`MISSING_REFINEMENT_ARTIFACT`): print the error naming the missing sections and point at `/loop-grill <n> --auto`.
|
|
18
|
+
- **Headless / auto ordering (who grills):** the `add-queue-item.mjs` gate enforces and parks; it never grills. So in a headless/auto run, **first** run `/loop-grill <n> --auto` to synthesize AC/DoD, **then** enqueue with `--next-up`. Only if grilling cannot produce a usable artifact, pass `--auto` on the `add-queue-item.mjs` call so the issue parks in the non-pickup column with a recorded reason (from the JSON `refinement` field) rather than failing the run — surface that reason and leave the issue parked for a human to refine.
|
|
17
19
|
|
|
18
|
-
3. **Freeform path (quick-capture a new idea):** run these steps in order.
|
|
20
|
+
3. **Freeform path (quick-capture a new idea):** run these steps in order. This is the
|
|
21
|
+
quick-capture exemption from `INTAKE-NEW-IDEA-SAFETY`
|
|
22
|
+
([Issue intake procedure](../skills/docs/issue-intake-procedure.md)) — the up-front
|
|
23
|
+
proposal artifact, async classification, and second async mutation pass are deferred in
|
|
24
|
+
favor of the inline confirm→create→grill steps below (it always creates a new issue,
|
|
25
|
+
human-gated).
|
|
19
26
|
1. **Confirm first — no mutation before approval.** Print a one-line preview of the issue to be created (`About to create issue: "<concise title>"`) and STOP for approval. Do not create the issue, grill, or enqueue anything until the human approves.
|
|
20
27
|
2. **Create the issue.** After approval, create a minimal GitHub issue from the text. The repo has no dedicated create-issue wrapper under `scripts/github/`; the sanctioned create path in this codebase is `gh issue create --repo <owner/repo> --assignee @me --title "<concise title>" --body "<freeform text>"` (the same path used by `skills/docs/issue-intake-procedure.md` and permitted by `skills/docs/main-agent-contract.md`). Title = a concise summary of the text; body = the verbatim freeform text.
|
|
21
28
|
3. **Grill it.** Run `/loop-grill <n> --auto` (delegates to the `loop-grill` skill). The skill writes a `## Grill findings` section back into the issue body and flags any unresolved items there, so they are visible before pickup. Do not re-implement grilling.
|
|
@@ -4,4 +4,4 @@ argument-hint: "<issue|pr>"
|
|
|
4
4
|
---
|
|
5
5
|
<!-- GENERATED from commands/loop-info.command.md by scripts/claude/generate-claude-assets.mjs — do not edit; edit the source and regenerate. -->
|
|
6
6
|
|
|
7
|
-
Resolve the read-only dev-loop state for `$ARGUMENTS` via the `loop info` shortcut — no full dev-loop run. If `$ARGUMENTS` is an issue number, run `npx dev-loops@0.
|
|
7
|
+
Resolve the read-only dev-loop state for `$ARGUMENTS` via the `loop info` shortcut — no full dev-loop run. If `$ARGUMENTS` is an issue number, run `npx dev-loops@0.8.0 loop info --issue $ARGUMENTS`; if it is a PR number, run `npx dev-loops@0.8.0 loop info --pr $ARGUMENTS`. Report the strategy, route, linked PR / branch, CI, and next action. Do not start implementation.
|
|
@@ -235,18 +235,19 @@ function extractRepoFlagsFromGhSubcmdVerbSegments(command, subcmd, verb) {
|
|
|
235
235
|
|
|
236
236
|
/**
|
|
237
237
|
* The raw external-write verb forms that must be blocked when originating from a subagent:
|
|
238
|
-
* ad-hoc GitHub issue/PR creation and
|
|
239
|
-
* wrappers). Each entry is `[subcmd, verb]`.
|
|
238
|
+
* ad-hoc GitHub issue/PR creation, comments, and edits run directly via `gh` (not the sanctioned
|
|
239
|
+
* node wrappers). Each entry is `[subcmd, verb]`.
|
|
240
240
|
*/
|
|
241
241
|
const EXTERNAL_WRITE_VERB_FORMS = Object.freeze([
|
|
242
242
|
["issue", "create"],
|
|
243
243
|
["issue", "comment"],
|
|
244
|
+
["issue", "edit"],
|
|
244
245
|
["pr", "comment"],
|
|
245
246
|
]);
|
|
246
247
|
|
|
247
248
|
/**
|
|
248
|
-
* Whether `command` contains a raw `gh issue create`, `gh issue comment`,
|
|
249
|
-
* invocation in ANY shell segment (ignoring --help/-h). PreToolUse gate use only — the gate
|
|
249
|
+
* Whether `command` contains a raw `gh issue create`, `gh issue comment`, `gh issue edit`, or
|
|
250
|
+
* `gh pr comment` invocation in ANY shell segment (ignoring --help/-h). PreToolUse gate use only — the gate
|
|
250
251
|
* blocks these when they originate from a subagent context. Node-wrapper commands
|
|
251
252
|
* (`node scripts/github/comment-issue.mjs …`) never match (first token is `node`, not `gh`).
|
|
252
253
|
* @param {string} command @returns {boolean}
|
|
@@ -256,8 +257,8 @@ export function commandContainsRawExternalWrite(command) {
|
|
|
256
257
|
}
|
|
257
258
|
|
|
258
259
|
/**
|
|
259
|
-
* Return `{ segment, explicitRepo }` for every raw external-write segment across all
|
|
260
|
-
* forms (`gh issue create` / `gh issue comment` / `gh pr comment`). PreToolUse gate use only —
|
|
260
|
+
* Return `{ segment, explicitRepo }` for every raw external-write segment across all four verb
|
|
261
|
+
* forms (`gh issue create` / `gh issue comment` / `gh issue edit` / `gh pr comment`). PreToolUse gate use only —
|
|
261
262
|
* lets the gate decide in-scope-ness per segment so a leading out-of-scope write can't shield a
|
|
262
263
|
* later in-scope one. `explicitRepo` is the segment's `--repo`/`-R` value or null.
|
|
263
264
|
* @param {string} command @returns {{ segment: string, explicitRepo: string|null }[]}
|
|
@@ -62,7 +62,7 @@ export const DEV_LOOP_AGENT_TYPE = "dev-loop";
|
|
|
62
62
|
* clean current-head draft_gate + pre_approval_gate). The loop runs this check before merging;
|
|
63
63
|
* gating it here closes the hole where a hand-run `gh pr merge` skips the pre-approval gate
|
|
64
64
|
* entirely. Everything else passes through.
|
|
65
|
-
* - raw `gh issue create` / `gh issue comment` / `gh pr comment` — blocked ONLY when the call
|
|
65
|
+
* - raw `gh issue create` / `gh issue comment` / `gh issue edit` / `gh pr comment` — blocked ONLY when the call
|
|
66
66
|
* originates from a SUBAGENT context (`agentType` is a non-null string) and targets the repo.
|
|
67
67
|
* Sanctioned external writes flow through node wrappers (gate-verdict comments via
|
|
68
68
|
* `upsert-checkpoint-verdict.mjs`, review replies via `reply-resolve*.mjs`, board sync,
|
|
@@ -86,7 +86,7 @@ export function decideBashGate({ command, repoSlug = null, gatePassed = false, g
|
|
|
86
86
|
return ALLOW;
|
|
87
87
|
}
|
|
88
88
|
// Subagent-scoped external-write guard: block ad-hoc `gh issue create`/`gh issue comment`/
|
|
89
|
-
// `gh pr comment` on the target repo from a subagent, so external writes flow through the
|
|
89
|
+
// `gh issue edit`/`gh pr comment` on the target repo from a subagent, so external writes flow through the
|
|
90
90
|
// sanctioned node wrappers. The main-agent/operator path (agentType null) is unaffected (#1051).
|
|
91
91
|
if (typeof agentType === "string" && commandContainsRawExternalWrite(command)) {
|
|
92
92
|
const cwdTargets = (repoSlug ?? "").toLowerCase() === TARGET_REPO_SLUG.toLowerCase();
|
|
@@ -102,9 +102,10 @@ export function decideBashGate({ command, repoSlug = null, gatePassed = false, g
|
|
|
102
102
|
return {
|
|
103
103
|
decision: "deny",
|
|
104
104
|
reason:
|
|
105
|
-
"Ad-hoc GitHub issue/PR creation and
|
|
105
|
+
"Ad-hoc GitHub issue/PR creation, comments, and edits from a subagent are blocked. Use the sanctioned " +
|
|
106
106
|
"node wrappers instead — gate-verdict comments via scripts/github/upsert-checkpoint-verdict.mjs, " +
|
|
107
|
-
"review-thread replies via scripts/github/reply-resolve*.mjs, board sync,
|
|
107
|
+
"review-thread replies via scripts/github/reply-resolve*.mjs, board sync, issue comments via " +
|
|
108
|
+
"scripts/github/comment-issue.mjs, or issue-body edits via scripts/github/edit-issue.mjs. " +
|
|
108
109
|
"Direct `gh issue create` is reserved for the main agent / operator.",
|
|
109
110
|
};
|
|
110
111
|
}
|
|
@@ -9,7 +9,7 @@ user-invocable: false
|
|
|
9
9
|
|
|
10
10
|
# Copilot PR Follow-up
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Canonical owner for the internal `copilot_pr_followup` route behind the public `dev-loop` façade.
|
|
13
13
|
|
|
14
14
|
It is also the canonical internal owner of the shared post-PR mechanics used by this repo:
|
|
15
15
|
PR discovery and interpretation, async watch behavior, fix / reply-resolve / re-request flow,
|
|
@@ -225,12 +225,12 @@ When unresolved feedback exists, use a narrow follow-up loop:
|
|
|
225
225
|
- when the intent is GitHub linkability, keep commit SHAs and issue/PR refs as plain text (for example 3ee82fc and owner/repo#70) and do not wrap them in backticks
|
|
226
226
|
- keep backticks for actual code/path/CLI literals only
|
|
227
227
|
- if either helper was newly added or recently changed, smoke-check it against one real thread before assuming the rest of the loop can rely on it
|
|
228
|
-
9. before resolving an addressed review thread, run a post-fix verification checkpoint
|
|
228
|
+
9. <!-- rule: COPILOT-FOLLOWUP-VERIFY-BEFORE-RESOLVE --> `COPILOT-FOLLOWUP-VERIFY-BEFORE-RESOLVE`: before resolving an addressed review thread, run a post-fix verification checkpoint
|
|
229
229
|
- confirm the GitHub reply actually exists on the intended thread/comment, not only in local notes or helper stdout
|
|
230
230
|
- confirm the pushed current-head diff genuinely addresses the reviewer concern on the flagged lines or pattern; if the concern is only partially addressed, leave the thread open and explain what remains
|
|
231
231
|
- refresh the API-backed thread snapshot via `dev-loops gate capture-threads` and use that refreshed data — including the unresolved thread count — for follow-up decisions rather than prose assumptions
|
|
232
232
|
- if any verification check fails, do **not** resolve the thread; leave it open, add a short explanation when needed, and re-enter the fix/reply loop
|
|
233
|
-
10. resolve the addressed review thread only after the reply is attached successfully, the verification checkpoint passes, and the concern is genuinely addressed
|
|
233
|
+
10. <!-- rule: COPILOT-FOLLOWUP-RESOLVE-AFTER-REPLY --> `COPILOT-FOLLOWUP-RESOLVE-AFTER-REPLY`: resolve the addressed review thread only after the reply is attached successfully, the verification checkpoint passes, and the concern is genuinely addressed
|
|
234
234
|
- do not stop at a local fix if GitHub-side reply/resolve is authorized
|
|
235
235
|
11. after completing reply/resolve for a pass, verify zero unresolved threads remain via `dev-loops gate capture-threads` before proceeding
|
|
236
236
|
- if the refreshed snapshot reports unresolved threads, re-enter the reply/resolve loop for the missed threads
|
|
@@ -239,14 +239,14 @@ When unresolved feedback exists, use a narrow follow-up loop:
|
|
|
239
239
|
- for a light-dispatched PR, pass `--lightweight` on every round-cap-consuming helper invocation — `detect-copilot-loop-state.mjs`, `copilot-pr-handoff.mjs`, `detect-pr-gate-coordination-state.mjs`, `request-copilot-review.mjs`, and `upsert-checkpoint-verdict.mjs` — otherwise those tools resolve the full-PR cap and the composed lightweight cap is never enforced
|
|
240
240
|
- **Opt out entirely:** `maxCopilotRounds: 0` disables the external Copilot review gate for the repo — the loop runs `draft_gate → pre_approval_gate` with the local harness only, never requesting or waiting on Copilot. Use this when the repo has no Copilot reviewer configured or prefers local-harness-only review.
|
|
241
241
|
- use the completed Copilot review-round count from `detect-copilot-loop-state.mjs` / `copilot-pr-handoff.mjs` as the current PR's review-round count
|
|
242
|
-
- if completed review rounds have reached the
|
|
242
|
+
- if completed review rounds have reached the resolved round cap above, do **not** re-request Copilot review within that concluded cycle
|
|
243
243
|
- if the loop already converged and then significant post-convergence changes land on a newer head (new/changed product or test logic, not doc/message/comment-only edits), treat that as a NEW cycle and re-request Copilot review when regular rounds are already > 0 (the prior cycle's cap does not suppress this new-cycle request)
|
|
244
244
|
- when the round limit is reached **and** the refreshed thread snapshot proves zero unresolved threads **and** current-head CI is green or credibly green, treat that clean state as eligible for `pre_approval_gate` fallback instead of deadlocking on another Copilot rerequest
|
|
245
245
|
- when using that fallback, add a short round-exhaustion note to the visible `pre_approval_gate` gate evidence so the PR records why no further Copilot rerequest occurred
|
|
246
246
|
- if the round cap is reached before the PR is thread-clean or before CI is green/credibly green, reply-resolve any remaining intentionally deferred threads with a short `deferred to follow-up` note, then stop and report that the Copilot round limit was reached
|
|
247
247
|
- **Signal-gated re-request suppression:** the `detect-copilot-loop-state.mjs` state machine classifies review-thread comments by signal level (High/Mid/Low). High-signal (bugs, security, contract violations) always re-requests; Low-signal (cosmetic nits) never re-requests. When low-signal detection is enabled and thresholds are met, the machine returns a low-signal-converged terminal state routing to `pre_approval_gate` without further re-requests. See [Copilot Loop Operations](../docs/copilot-loop-operations.md) for full signal-level semantics.
|
|
248
248
|
- if that local validation is still known red, continue remediation instead of re-requesting Copilot
|
|
249
|
-
- after a fix push advances the PR head SHA, re-run `detect-copilot-loop-state.mjs` for the new head and apply the [Copilot CI Status Contract](../docs/copilot-ci-status-contract.md). Previous-head CI is stale; only current-head results unblock CI-dependent steps. if GitHub CI/checks for the updated head are known red for a fixable issue, continue remediation instead of re-requesting Copilot. only once the updated head is green or credibly green, explicitly re-request Copilot review for the new head. Always use `request-copilot-review.mjs` — never `gh api POST repos/.../requested_reviewers` directly.
|
|
249
|
+
- after a fix push advances the PR head SHA, re-run `detect-copilot-loop-state.mjs` for the new head and apply the [Copilot CI Status Contract](../docs/copilot-ci-status-contract.md). Previous-head CI is stale; only current-head results unblock CI-dependent steps. if GitHub CI/checks for the updated head are known red for a fixable issue, continue remediation instead of re-requesting Copilot. <!-- rule: COPILOT-FOLLOWUP-REREQUEST-GREEN-GATE --> `COPILOT-FOLLOWUP-REREQUEST-GREEN-GATE`: only once the updated head is green or credibly green, explicitly re-request Copilot review for the new head. Always use `request-copilot-review.mjs` — never `gh api POST repos/.../requested_reviewers` directly.
|
|
250
250
|
- only enter a wait/watch loop if the request result is confirmed as `requested` or `already-requested`
|
|
251
251
|
- for `requested` / `already-requested`, immediately re-baseline with `detect-copilot-loop-state.mjs`; if the returned state is `waiting_for_copilot_review`, use `dev-loops loop watch-cycle` or stop/resume later, and if the returned state is `waiting_for_ci`, use `dev-loops loop watch-ci` (provider-agnostic CI wait; `gh run watch` is an Actions-only fallback) or stop/resume later after that single detector refresh
|
|
252
252
|
- if the request result is `unavailable`, report that limitation and stop unless the user explicitly wants passive waiting anyway
|
|
@@ -25,7 +25,7 @@ Required installed runtime contract docs are shared bundled copies under `../doc
|
|
|
25
25
|
|
|
26
26
|
> Under the Claude Code harness the dev-loop runs as a single agent: run these steps directly — no read-only boundary and no separate async-subagent dispatch. See [Main Agent Contract](../docs/main-agent-contract.md).
|
|
27
27
|
|
|
28
|
-
Resolve authoritative state via the startup resolver (`npx dev-loops@0.
|
|
28
|
+
Resolve authoritative state via the startup resolver (`npx dev-loops@0.8.0 loop startup --issue <n>` for issues, `npx dev-loops@0.8.0 loop startup --pr <n>` for PRs), then immediately build the handoff envelope via `npx dev-loops@0.8.0 loop build-envelope --input <resolver-output.json>`. The envelope determines `requiredReads`, `nextAction`, `stopRules`, and `acceptance` — load only those files, execute only that bounded task. It is the first handoff artifact consumed before loading any route pack. See [Workflow Handoff Contract](../docs/workflow-handoff-contract.md) for the derivation contract.
|
|
29
29
|
|
|
30
30
|
**Retrospective checkpoint gate:** the resolver reads `.pi/dev-loop-retrospective-checkpoint.json` and injects the state. When the checkpoint is `missing` and the repo config `workflow.requireRetrospective` (set via `.devloops` at repo root) is `true`, the resolver returns `needs_reconcile`. Complete or explicitly skip the retrospective before starting.
|
|
31
31
|
|
|
@@ -99,10 +99,10 @@ When `@dev-loops/core` is available again, switch back to the full helper. The f
|
|
|
99
99
|
|
|
100
100
|
## Read-only info shortcut
|
|
101
101
|
|
|
102
|
-
Info/handoff requests can be served directly via `npx dev-loops@0.
|
|
103
|
-
- `npx dev-loops@0.
|
|
104
|
-
- `npx dev-loops@0.
|
|
105
|
-
- `npx dev-loops@0.
|
|
102
|
+
Info/handoff requests can be served directly via `npx dev-loops@0.8.0 loop info` (read-only; no full dev-loop run required):
|
|
103
|
+
- `npx dev-loops@0.8.0 loop info --issue <n>` — human-readable issue state summary (strategy, route, linked PR, next action)
|
|
104
|
+
- `npx dev-loops@0.8.0 loop info --pr <n>` — human-readable PR state summary (branch, CI, threads, rounds, action)
|
|
105
|
+
- `npx dev-loops@0.8.0 loop info --issue <n> --json` — machine-readable JSON output
|
|
106
106
|
|
|
107
107
|
## Reading tool output (token-economical convention)
|
|
108
108
|
|
|
@@ -130,9 +130,9 @@ When you need a fact from a dev-loops JSON-emitting script, climb this ladder an
|
|
|
130
130
|
|
|
131
131
|
**Inline-first rule:** Prefer inline commands over nested async delegation when managing a single PR. Use nested delegation only for parallel fan-out or when the parent needs to continue other work.
|
|
132
132
|
|
|
133
|
-
**Bounded async task contract:** Break work into discrete tasks with clear inputs, explicit outputs, bounded scope. No shell polling — use `run-watch-cycle.mjs` or `gh run watch`.
|
|
133
|
+
**Bounded async task contract:** Break work into discrete tasks with clear inputs, explicit outputs, bounded scope. No shell polling — use `run-watch-cycle.mjs` or `gh run watch`. Fan-out reviewer waits (gate sub-loops or any Agent-tool fan-out) follow `ANTIPATTERN-FANIN-WAIT` in [Anti-patterns](../docs/anti-patterns.md): await completion via the harness notification or the reviewer's findings artifact at its deterministic path and join via `consolidateFanin` — never transcript-tail, `node -e`/`python3`-parse tool JSON, or `sleep`-poll.
|
|
134
134
|
|
|
135
|
-
**Round-cap budget check (enforced):** After every watch cycle, fix pass, or reply-resolve, check whether completed Copilot review rounds have reached the
|
|
135
|
+
**Round-cap budget check (enforced):** After every watch cycle, fix pass, or reply-resolve, check whether completed Copilot review rounds have reached the resolved round cap (`refinement.maxCopilotRounds`, default 5; light-dispatched PRs resolve the lower `resolveEffectiveCopilotRoundCap`, default 1 — owned by `COPILOT-FOLLOWUP-ROUND-CAP`). Stop re-requesting Copilot review when the limit is reached **within that review cycle**. Exception: the post-convergence new-cycle re-request carve-out (a converged loop that later takes significant post-convergence changes on a newer head opens a new cycle even if the previous one hit the cap) is owned by `COPILOT-FOLLOWUP-ROUND-CAP`. Read these gate-cadence facts via the token-economical convention above (`run-watch-cycle.mjs --concise`, or `--jq`/`--silent` for a single field/predicate) — never `| python3` or `node -e`.
|
|
136
136
|
|
|
137
137
|
## Shorthand issue-based auto trigger contract
|
|
138
138
|
|
|
@@ -5,9 +5,17 @@ Canonical owner for the acceptance-criteria verification procedure run during th
|
|
|
5
5
|
## Procedure
|
|
6
6
|
|
|
7
7
|
<!-- rule: ACCEPT-CRITERIA-VERIFY-AND-REFLECT -->
|
|
8
|
-
`ACCEPT-CRITERIA-VERIFY-AND-REFLECT`: Before posting the `pre_approval_gate` comment, the agent MUST verify every acceptance criteria checklist item in the issue linked to this PR, and MUST reflect the verified items back into both the linked issue body and the PR body (exception:
|
|
9
|
-
|
|
10
|
-
> **
|
|
8
|
+
`ACCEPT-CRITERIA-VERIFY-AND-REFLECT`: Before posting the `pre_approval_gate` comment, the agent MUST verify every acceptance criteria checklist item in the issue linked to this PR, and MUST reflect the verified items back into both the linked issue body and the PR body (exception: when the linked issue body is not the spec-of-record — under a lightweight session (tracker-backed or issue-less; the PR body is the spec) or a plan-file promotion session (the committed plan doc the PR body points to is the spec) — the step 5 issue-body mirroring is skipped; see the fork below):
|
|
9
|
+
|
|
10
|
+
> **Non-tracker spec-source fork:** when the linked issue body is not the spec-of-record, the fork covers three arms — lightweight (the PR body itself is the spec; splits on whether a backing issue exists) and plan-file promotion (a distinct local-planning origin whose committed plan doc, pointed to from the PR body, is the spec). Handle each arm as below.
|
|
11
|
+
>
|
|
12
|
+
> **Tracker-backed lightweight** (`--issue --lightweight`): a linked issue exists, so keep the `Closes #N` linkage and all issue-level tracking, but the **PR body**, not the issue body, is the canonical spec-of-record read for AC/DoD. Still resolve the linked issue for tracking, but read the AC/DoD/invariants from the PR body rather than the issue body (skip step 2's issue-body read for spec purposes). Run `node scripts/loop/validate-pr-body-spec.mjs --repo <owner/name> --pr <pr-number> --expected-issue <issue-number>` (reuses `@dev-loops/core/loop/issue-refinement-artifact`) to confirm the body carries the required invariants — it fails closed with a per-section `missing_*` reason if any is absent, in which case post the gate comment with verdict `blocked`. The PR body MUST carry the `Closes #N` linkage (or GitHub's other closing-keyword forms): `validate-pr-body-spec` fails closed with `missing_closing_issue_reference` without it, and with `closes_wrong_issue` when `--expected-issue` doesn't match. Then continue at step 3, extracting the **Acceptance criteria** checklist items from the PR body itself; step 5's issue-body AC-tick update is unnecessary since the issue body is not the spec surface (the PR body is ticked in step 6 as usual).
|
|
13
|
+
>
|
|
14
|
+
> **Issue-less lightweight** (`--lightweight` alone): no linked issue exists — by design, not a gap. There is nothing to resolve at step 1 and nothing to read or mirror at steps 2 and 5; skip all three. Read AC/DoD/invariants directly from the PR body and run `node scripts/loop/validate-pr-body-spec.mjs --repo <owner/name> --pr <pr-number> --no-issue`, which fails closed with a per-section `missing_*` reason for any absent invariant and with `unexpected_closing_issue_reference` if the body carries a closing reference to an issue that doesn't back it (a closing reference MUST NOT be present). On any validation failure, post the gate comment with verdict `blocked`. Step 1's "zero candidates → blocked" rule is scoped to tracker-backed sessions; for a deliberately issue-less session, zero closing references is the expected state, not a blocked condition. Continue at step 3 against the PR body, then step 4 and 6 as usual.
|
|
15
|
+
>
|
|
16
|
+
> **Plan-file promotion (P4) — a distinct local-planning origin, not a lightweight sub-arm:** no linked issue exists — similar to the issue-less lightweight arm, there is nothing to resolve at step 1 and nothing to read or mirror at steps 2 and 5; skip all three. AC/DoD live in the PR body, copied from the committed plan doc that is the spec-of-record; read them from the PR body as usual.
|
|
17
|
+
>
|
|
18
|
+
> The default issue-backed procedure below is unchanged.
|
|
11
19
|
|
|
12
20
|
1. **Resolve the linked issue number deterministically:** use `gh pr view <pr-number> --repo <owner/name> --json closingIssuesReferences,body` and apply this decision tree: if there is exactly one closing issue reference, use it; else if there is exactly one PR-body `Closes #N` / `Fixes #N` pattern, use it; otherwise (zero or multiple candidates), post the gate comment with verdict `blocked` (gate cannot complete deterministically) rather than guessing.
|
|
13
21
|
|
|
@@ -17,7 +25,7 @@ Canonical owner for the acceptance-criteria verification procedure run during th
|
|
|
17
25
|
|
|
18
26
|
4. **Verify each AC item** against the proposed changes on the current PR head.
|
|
19
27
|
|
|
20
|
-
5. **Update the issue body once:** compute the fully-updated issue body by replacing each verified item's `- [ ]` with `- [x]`, write it to a temporary file, and perform a single `
|
|
28
|
+
5. **Update the issue body once:** compute the fully-updated issue body by replacing each verified item's `- [ ]` with `- [x]`, write it to a temporary file, and perform a single `node scripts/github/edit-issue.mjs --repo <owner/name> --issue <issue-number> --body-file <tmp-file>`. Do not issue one edit per item; prefer `--body-file` over inline `--body` to avoid shell quoting/escaping hazards.
|
|
21
29
|
|
|
22
30
|
6. **Tick the PR body once:** after the verification is clean, flip each verified item's `- [ ]` to `- [x]` in the PR body via a single `gh pr edit --body-file` update, so the merged PR shows checked AC/DoD. Run `node scripts/github/tick-verified-checkboxes.mjs --repo <owner/name> --pr <pr-number> --verified <exact label>...` (one edit; exact-label match; only items actually verified are ticked; unverified or deferred items stay `- [ ]`; fail closed). This runs automatically as part of the `pre_approval_gate`, not by memory.
|
|
23
31
|
|
|
@@ -6,18 +6,18 @@ Canonical owner for anti-pattern guidance across all workflow families.
|
|
|
6
6
|
|
|
7
7
|
1. **Skipping fan-out/fan-in for non-trivial changes**: Do not implement directly without refinement when scope exceeds light-mode thresholds.
|
|
8
8
|
2. **Routing review-only work through local_implementation**: Review-only comparison, synthesis, or consolidation must use `refiner` agent, not `dev-loop` + `local_implementation`.
|
|
9
|
-
3. **Thin placeholder PR descriptions**: Always include change summary, scope/context, acceptance criteria, definition of done, non-goals, and `Closes #N
|
|
9
|
+
3. **Thin placeholder PR descriptions**: Always include change summary, scope/context, acceptance criteria, definition of done, non-goals, and `Closes #N` (tracker-backed; issue-less lightweight and plan-file promotion PRs instead follow [merge precondition 7](merge-preconditions.md#required-before-merge)).
|
|
10
10
|
4. **Merging directly to main without PR**: Use PR-based remote loop when practical.
|
|
11
11
|
5. **Duplicate worktree paths**: See `WORKTREE-DEDUPE` in [Worktree usage guidance](../../docs/worktree-guidance.md#coordination-and-collision-checks).
|
|
12
12
|
6. **Main-checkout mutation**: See `WORKTREE-DEFAULT-USE` in [Worktree usage guidance](../../docs/worktree-guidance.md#default-rule-use-a-worktree-for-mutating-local-work).
|
|
13
13
|
7. **Spelunking tooling internals instead of using the public surface**: Do not read installed package internals, scan tooling source, or run ad-hoc scripts to understand a tool's behavior. Use the CLI, its `--help` subcommands, and `skills/docs/`. Read tool source only when the task is to inspect or change that tool, or when a concrete failure path is inside it and no public CLI/docs path exists. Once a failure is concrete, search changed files for the exact pattern — don't run duplicate broad searches.
|
|
14
14
|
8. **Hand-editing the queue file when a board is configured**: When a GitHub Projects board is configured (`queue.projectNumber`/`queue.boardTitle` in `.devloops`), the board is the authoritative queue MEMBERSHIP and ordering source — not just status. Add work via the board (`dev-loops queue add ... --next-up` to land directly in the normative `Next Up` pickup queue; default lands in Backlog, which is unprioritized intake and never auto-picked), not by hand-editing `.pi/dev-loop-queue.json`; the queue runner reconciles board `Next Up` items into queue entries before each run. See the operator guides under `docs/` (queue board usage/setup) for the workflow.
|
|
15
|
-
9. **Hand-rolling a fan-in wait by polling a subagent transcript or parsing tool JSON with `node -e`/`python3`**: When awaiting fan-out reviewers (gate `draft_gate`/`pre_approval_gate` sub-loops, or any Agent-tool fan-out), NEVER tail/parse another agent's JSONL transcript, NEVER use `node -e`/`python3` to parse tool/subagent JSON, and NEVER `sleep`-poll in a shell loop for completion. These improvisations breach the [internal-tooling-only rule (issue #982)](retrospective-checkpoint-contract.md#internal-tooling-only-rule-issue-982--now-advisory) (no `node -e`/`python3` parsing of tool JSON) and the no-shell-polling rule, and a single improvised wait adds a non-empty entry to the advisory `retrospectiveFindings.rawCallViolations` array (issue #1077: reported to the conductor, **never blocking**). **Sanctioned wait:** rely on the harness completion notification, or read each reviewer's findings artifact at its deterministic output path (see [Checkpoint Review Chain Contract](../../docs/gate-review-sub-loop-contract.md) Phase 2), then join via `consolidateFanin` from `@dev-loops/core/loop/gate-fanin` (Phase 3). See also the dev-loop SKILL "Bounded async task contract".
|
|
15
|
+
9. <!-- rule: ANTIPATTERN-FANIN-WAIT --> `ANTIPATTERN-FANIN-WAIT` — **Hand-rolling a fan-in wait by polling a subagent transcript or parsing tool JSON with `node -e`/`python3`**: When awaiting fan-out reviewers (gate `draft_gate`/`pre_approval_gate` sub-loops, or any Agent-tool fan-out), NEVER tail/parse another agent's JSONL transcript, NEVER use `node -e`/`python3` to parse tool/subagent JSON, and NEVER `sleep`-poll in a shell loop for completion. These improvisations breach the [internal-tooling-only rule (issue #982)](retrospective-checkpoint-contract.md#internal-tooling-only-rule-issue-982--now-advisory) (no `node -e`/`python3` parsing of tool JSON) and the no-shell-polling rule, and a single improvised wait adds a non-empty entry to the advisory `retrospectiveFindings.rawCallViolations` array (issue #1077: reported to the conductor, **never blocking**). **Sanctioned wait:** rely on the harness completion notification, or read each reviewer's findings artifact at its deterministic output path (see [Checkpoint Review Chain Contract](../../docs/gate-review-sub-loop-contract.md) Phase 2), then join via `consolidateFanin` from `@dev-loops/core/loop/gate-fanin` (Phase 3). See also the dev-loop SKILL "Bounded async task contract".
|
|
16
16
|
10. **Ad hoc `gh api graphql` review-thread queries or `gh pr checks`/shell-pipe CI polling**: Do not hand-write a GraphQL query to enumerate review threads, and do not wrap `gh pr checks` in an `awk`/`grep`/`until`-based shell loop to wait for CI. Enumerate threads (with the ids `reply-resolve-review-thread.mjs` needs) via `scripts/github/list-review-threads.mjs`; block on current-head CI settling via `scripts/github/wait-pr-checks.mjs` (or `dev-loops loop watch-ci` for the JSON-status variant); read the aggregate loop/CI/thread state via `detect-copilot-loop-state.mjs` instead of re-deriving it from raw `gh` output.
|
|
17
17
|
|
|
18
18
|
## Light mode exception
|
|
19
19
|
|
|
20
|
-
Small scoped changes (
|
|
20
|
+
Small scoped changes under the configured `localImplementation.lightMode` thresholds (owned by `LOCAL-LIGHT-MODE-CONFIG-SURFACE` in [Local Implementation](../local-implementation/SKILL.md)) may skip fan-out/fan-in but must still run validation and a single review pass.
|
|
21
21
|
|
|
22
22
|
## Cross-references
|
|
23
23
|
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# Artifact authority contract
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Canonical owner for the artifact-selection model: whether a work item originates from a GitHub issue (tracker-first), a persisted markdown plan file (local-planning), or the sanctioned lightweight PR-body-as-spec path.
|
|
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 [Artifact Authority Contract](../docs/artifact-authority-contract.md) from the installed skill directory.
|
|
6
6
|
|
|
7
7
|
Other repo docs may summarize or link this contract, but they should not redefine it.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Three-origin model
|
|
10
10
|
|
|
11
11
|
<!-- rule: ARTIFACT-TWO-TIER-EXCLUSIVE -->
|
|
12
|
-
|
|
12
|
+
<!-- The rule ID predates the three-origin wording below (it was written when the
|
|
13
|
+
model was two-tier); retained as-is for ID stability, not renamed. -->
|
|
14
|
+
dev-loops supports three mutually exclusive artifact authority origins. Every work item MUST originate from exactly one authoritative artifact: a GitHub issue, a persisted markdown plan file, or — on the sanctioned lightweight path — the PR description itself as the spec-of-record (no committed plan artifact). Work MUST NOT originate from a PR (other than the sanctioned lightweight PR-body-as-spec path) or a direct local change unless explicitly requested.
|
|
13
15
|
|
|
14
|
-
The shipped extension default selects local-planning; see [Shipped default posture](#shipped-default-posture) below. The mode names that follow describe the
|
|
16
|
+
The shipped extension default selects local-planning; see [Shipped default posture](#shipped-default-posture) below. The mode names that follow describe the origins; "default" in their headings refers to the local-first code-level default in `BUILT_IN_DEFAULTS`.
|
|
15
17
|
|
|
16
18
|
### Tracker-first
|
|
17
19
|
|
|
@@ -5,7 +5,7 @@ Canonical owner for agent confirmation / authorization rules across all workflow
|
|
|
5
5
|
## Core rule
|
|
6
6
|
|
|
7
7
|
<!-- rule: CONFIRM-CORE-EXPLICIT -->
|
|
8
|
-
Before any state-changing action,
|
|
8
|
+
`CONFIRM-CORE-EXPLICIT`: Before any state-changing action, the agent MUST obtain explicit confirmation unless the latest user message already clearly authorizes that exact action.
|
|
9
9
|
|
|
10
10
|
## What counts as confirmation
|
|
11
11
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Copilot loop operations
|
|
2
2
|
|
|
3
|
-
|
|
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)
|
|
@@ -162,12 +162,14 @@ When you do hand work to Copilot:
|
|
|
162
162
|
|
|
163
163
|
## PR description contract
|
|
164
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
|
+
|
|
165
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.
|
|
166
168
|
|
|
167
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 `- `.
|
|
168
170
|
|
|
169
171
|
<!-- rule: OPS-DRAFT-FIRST-PR -->
|
|
170
|
-
`OPS-DRAFT-FIRST-PR`: New PRs in this workflow MUST be opened as **draft** PRs
|
|
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.
|
|
171
173
|
|
|
172
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`).
|
|
173
175
|
|
|
@@ -26,6 +26,15 @@ For **all new ideas** that are not already anchored to an existing issue (includ
|
|
|
26
26
|
- after approval, run a second async mutation pass (dispatched via the procedure) instead of mutating directly from inherited context
|
|
27
27
|
- verify post-mutation artifact state and record what actually changed
|
|
28
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
|
+
|
|
29
38
|
Deterministic intake + mutation-gate state machine:
|
|
30
39
|
|
|
31
40
|
```text
|
|
@@ -127,15 +136,15 @@ Preflight verdicts:
|
|
|
127
136
|
- `ready_for_followup`: linked PR has become substantive; resume from that PR
|
|
128
137
|
- `timed_out`: observational first; refresh authoritative state
|
|
129
138
|
- if refreshed state is still `waiting_for_initial_copilot_implementation`, remain attached to the same durable wait seam and continue waiting
|
|
130
|
-
- if the refreshed state exits this seam, route based on that refreshed state instead of surfacing timeout attention
|
|
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
|
|
131
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
|
|
132
|
-
- only surface timeout attention when the seam's durable watch budget is actually exhausted
|
|
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
|
|
133
142
|
- for explicit inspect/status requests, report the still-waiting state and exit normally
|
|
134
143
|
- carry that resolved repo slug through every later GitHub issue/PR command
|
|
135
144
|
|
|
136
145
|
### From a plan-doc path
|
|
137
146
|
|
|
138
|
-
- 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
|
|
139
148
|
- default to the current repository slug
|
|
140
149
|
- if the plan-doc reference explicitly points at another GitHub repository, resolve `<resolved-repo>` first
|
|
141
150
|
- search existing issues with:
|
|
@@ -39,13 +39,15 @@ doing manually; it is not a general conflict-resolution engine.
|
|
|
39
39
|
## Required before merge
|
|
40
40
|
|
|
41
41
|
<!-- rule: MERGE-PRECOND-REQUIRED -->
|
|
42
|
+
Before merge, ALL of the following MUST hold:
|
|
43
|
+
|
|
42
44
|
1. ✅ Conflict-free with base (`mergeable: MERGEABLE`; not `CONFLICTING`/`DIRTY`/`BEHIND`/`UNKNOWN`)
|
|
43
45
|
2. ✅ CI green on current head (or crediblyGreen via `--local-validation-head-sha`)
|
|
44
46
|
3. ✅ Draft gate satisfied — clean `draft_gate` verdict per `GATE-COMMENT-VERDICT-VALUES` ([Checkpoint Verdict Comment Contract](../../docs/gate-review-comment-contract.md))
|
|
45
47
|
4. ✅ Pre-approval gate satisfied — clean `pre_approval_gate` verdict on the current head, same rule
|
|
46
48
|
5. ✅ All review threads resolved
|
|
47
49
|
6. ✅ Explicit merge authorization from operator
|
|
48
|
-
7. ✅
|
|
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
|
|
49
51
|
8. ✅ PR **title** free of merge-blocking markers — `WIP`, `[WIP]`, `DRAFT`, `DO NOT MERGE`, `🚧` (case-insensitive)
|
|
50
52
|
|
|
51
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.
|
|
@@ -80,9 +82,9 @@ A marker is allowed only while the PR is still in draft; it must be removed befo
|
|
|
80
82
|
|
|
81
83
|
## Merge authorization
|
|
82
84
|
|
|
83
|
-
-
|
|
85
|
+
- Merge authorization MUST be explicit for the active issue/PR scope
|
|
84
86
|
- `"Merge authorized if gates green"` is valid explicit authorization
|
|
85
|
-
- Implied approval from prior turns
|
|
87
|
+
- Implied approval from prior turns MUST NOT be treated as sufficient
|
|
86
88
|
|
|
87
89
|
### `autonomy.humanMergeOnly` — fixed human-only merge (non-overridable)
|
|
88
90
|
|
|
@@ -80,7 +80,7 @@ This gate uses review angles resolved from config (`resolveGateAngles(config, "p
|
|
|
80
80
|
Boundary note:
|
|
81
81
|
- `pre_approval_gate` governs only final approval readiness for the reviewed head
|
|
82
82
|
- a clean verdict requires no findings at any severity in the gate's `blockCleanOnFindingSeverities` (resolved from config via `resolveGateConfig(config, "preApproval").blockCleanOnFindingSeverities`)
|
|
83
|
-
- non-draft PRs do not need
|
|
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))
|
|
84
84
|
|
|
85
85
|
## Lifecycle states
|
|
86
86
|
|
|
@@ -72,7 +72,8 @@ Use this taxonomy consistently across docs, discovery surfaces, and tests:
|
|
|
72
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 |
|
|
73
73
|
| Reusable role agents | `developer`, `docs`, `review`, `fixer`, `quality`, `refiner` | keep framed as reusable building blocks, not peer public workflow entrypoints |
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
<!-- rule: FACADE-COPILOT-INTERNAL-ONLY -->
|
|
76
|
+
`FACADE-COPILOT-INTERNAL-ONLY`: Any remaining specialized Copilot behavior stays internal-only behind `dev-loop`.
|
|
76
77
|
|
|
77
78
|
<!-- rule: FACADE-TAXONOMY-DRIFT-TEST -->
|
|
78
79
|
`FACADE-TAXONOMY-DRIFT-TEST`: Regression tests MUST fail if this taxonomy drifts in wording or surfaced entrypoint assets.
|
|
@@ -96,8 +96,8 @@ If the gate result is `needs_reconcile`, the caller MUST NOT proceed with the pr
|
|
|
96
96
|
<!-- rule: RETRO-ADVISORY-NEVER-GATE -->
|
|
97
97
|
The retrospective is **advisory**: it runs, records flagged raw-call / discipline
|
|
98
98
|
observations honestly, and passes them back to the conductor (main agent) to
|
|
99
|
-
**decide** what to do with them — but it MUST NOT block a merge or any lifecycle
|
|
100
|
-
transition. The pre-merge retrospective gate (`evaluateRetrospectiveMergeApproval`
|
|
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`
|
|
101
101
|
and the `requireRetrospectiveGate` / `requireRetrospectiveInternalTooling` config
|
|
102
102
|
keys) has been **removed**. There is no `retrospective_gate_pending` / `blocked`
|
|
103
103
|
disposition on account of the internal-tooling raw-call record.
|
|
@@ -135,10 +135,13 @@ scripts legitimately call `gh`/GraphQL internally; that is the tooling. The rule
|
|
|
135
135
|
targets the agent's own top-level shell calls, not a script's internals.
|
|
136
136
|
|
|
137
137
|
**Write-op allowlist (verifier only):** `gh pr merge`, `gh pr ready`,
|
|
138
|
-
`gh issue create
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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.
|
|
142
145
|
|
|
143
146
|
**Inline-interpreter check item:** the raw-call scan below mechanically catches
|
|
144
147
|
`node -e`/`python3 -c`/heredoc calls as a `rawCallViolations` entry — the same
|
|
@@ -17,7 +17,7 @@ Canonical owner for validation requirements across all workflow families.
|
|
|
17
17
|
## Coverage requirements
|
|
18
18
|
|
|
19
19
|
<!-- rule: VALIDATE-COVERAGE-THRESHOLD -->
|
|
20
|
-
`VALIDATE-COVERAGE-THRESHOLD`: Changed files
|
|
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.
|
|
21
21
|
|
|
22
22
|
## Cross-references
|
|
23
23
|
|