dev-loops 0.2.7 → 0.3.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/developer.md +1 -0
- package/.claude/agents/fixer.md +1 -0
- package/.claude/agents/review.md +30 -0
- package/.claude/skills/copilot-pr-followup/SKILL.md +57 -3
- package/.claude/skills/dev-loop/SKILL.md +5 -5
- package/.claude/skills/docs/anti-patterns.md +2 -0
- package/.claude/skills/docs/copilot-loop-operations.md +2 -2
- package/.claude/skills/local-implementation/SKILL.md +17 -3
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +43 -0
- package/agents/developer.agent.md +1 -0
- package/agents/fixer.agent.md +1 -0
- package/agents/review.agent.md +30 -0
- package/cli/index.mjs +39 -6
- package/package.json +2 -2
- package/scripts/README.md +6 -5
- package/scripts/_core-helpers.mjs +1 -0
- package/scripts/claude/headless-dev-loop.mjs +53 -13
- package/scripts/claude/headless-info-smoke.mjs +45 -11
- package/scripts/github/build-adjacent-bundle.mjs +448 -0
- package/scripts/github/{create-draft-pr.mjs → create-pr.mjs} +28 -12
- package/scripts/github/detect-checkpoint-evidence.mjs +95 -4
- package/scripts/github/post-gate-findings.mjs +392 -0
- package/scripts/github/reconcile-draft-gate.mjs +2 -2
- package/scripts/github/request-copilot-review.mjs +69 -8
- package/scripts/github/upsert-checkpoint-verdict.mjs +597 -15
- package/scripts/github/verify-fresh-review-context.mjs +12 -1
- package/scripts/github/write-gate-context.mjs +634 -0
- package/scripts/github/write-gate-findings-log.mjs +1 -1
- package/scripts/loop/detect-change-scope.mjs +36 -11
- package/scripts/loop/detect-pr-gate-coordination-state.mjs +30 -18
- package/scripts/loop/detect-tracker-first-loop-state.mjs +38 -11
- package/scripts/loop/run-queue.mjs +87 -15
- package/scripts/projects/add-queue-item.mjs +60 -43
- package/scripts/projects/archive-done-items.mjs +135 -39
- package/scripts/projects/ensure-queue-board.mjs +65 -64
- package/scripts/projects/list-queue-items.mjs +57 -56
- package/scripts/projects/move-queue-item.mjs +123 -124
- package/scripts/projects/reorder-queue-item.mjs +62 -44
- package/scripts/projects/sync-item-status.mjs +198 -0
- package/skills/copilot-pr-followup/SKILL.md +57 -3
- package/skills/dev-loop/scripts/log-bash-exit-1.mjs +2 -2
- package/skills/dev-loop/scripts/phase-files.mjs +2 -2
- package/skills/docs/anti-patterns.md +2 -0
- package/skills/docs/copilot-loop-operations.md +2 -2
- package/skills/local-implementation/SKILL.md +17 -3
|
@@ -264,6 +264,24 @@ Do not treat `fix applied locally` as the end of the loop when the workflow also
|
|
|
264
264
|
|
|
265
265
|
For every `draft_gate` or `pre_approval_gate` comment, you MUST run:
|
|
266
266
|
|
|
267
|
+
For a gate that ran via the fan-out/fan-in sub-loop, pass the structured per-angle review results via `--findings-json` (NOT the wall-of-text `--findings-summary`). The operator/loop writes that JSON file from the collected per-angle results — the same per-angle `{angle, verdict, findings}` objects the fan-out reviewers wrote to `tmp/gate-reviews/<repo-slug>/pr-<N>/<gate>-<headSha>/<angle>.json` that feed `consolidateFanin`. The helper renders a readable per-angle breakdown and derives the single-line `**Findings summary:**` digest itself:
|
|
268
|
+
|
|
269
|
+
```sh
|
|
270
|
+
node <resolved-skill-scripts>/github/upsert-checkpoint-verdict.mjs \
|
|
271
|
+
--repo <owner/name> \
|
|
272
|
+
--pr <number> \
|
|
273
|
+
--gate <draft_gate|pre_approval_gate> \
|
|
274
|
+
--head-sha <current_head_sha> \
|
|
275
|
+
--verdict <clean|findings_present|blocked> \
|
|
276
|
+
--findings-json <path-to-per-angle-results.json> \
|
|
277
|
+
--next-action "<next action>" --findings-severity-counts '{"must-fix":0,"worth-fixing-now":0,"defer":0}' \
|
|
278
|
+
--execution-mode fanout_fanin
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`--findings-json` accepts the per-angle review-results array (`[{ angle, verdict?, findings:[{severity, summary, file?, line?, disposition?}] }]`, the primary shape that feeds `consolidateFanin`); it also accepts the flat per-finding array that `consolidateFanin`/`toFindingsLogShape` produce (`[{ severity, summary, angle?, ... }]`), grouping it by each finding's `.angle`. A non-empty input matching neither shape is rejected rather than silently rendering all-clean. If the structured results are not available, fall back to `--findings-summary "<summary>"` (the inline_single_agent fallback path).
|
|
282
|
+
|
|
283
|
+
For a gate that ran inline (single agent, not via the sub-loop):
|
|
284
|
+
|
|
267
285
|
```sh
|
|
268
286
|
node <resolved-skill-scripts>/github/upsert-checkpoint-verdict.mjs \
|
|
269
287
|
--repo <owner/name> \
|
|
@@ -272,13 +290,26 @@ node <resolved-skill-scripts>/github/upsert-checkpoint-verdict.mjs \
|
|
|
272
290
|
--head-sha <current_head_sha> \
|
|
273
291
|
--verdict <clean|findings_present|blocked> \
|
|
274
292
|
--findings-summary "<summary>" \
|
|
275
|
-
--next-action "<next action>" --findings-severity-counts '{"must-fix":0,"worth-fixing-now":0,"defer":0}'
|
|
293
|
+
--next-action "<next action>" --findings-severity-counts '{"must-fix":0,"worth-fixing-now":0,"defer":0}' \
|
|
294
|
+
--execution-mode inline_single_agent --inline-reason "<why>"
|
|
276
295
|
```
|
|
277
296
|
|
|
297
|
+
`--execution-mode <fanout_fanin|inline_single_agent>` records how the gate review ran (default `inline_single_agent`). When the gate did not run via the fan-out/fan-in sub-loop ([Gate Review Sub-Loop Contract](../../docs/gate-review-sub-loop-contract.md)), you MUST pass `--execution-mode inline_single_agent --inline-reason "<why>"` — silent inline runs are no longer allowed: inline mode requires a non-empty `--inline-reason` and emits a stderr warning. Because inline is the default mode, a bare call with neither flag now fails with an argument error, so always pass `--execution-mode` explicitly (and `--inline-reason` for inline). The recorded `executionMode` is surfaced by `detect-checkpoint-evidence.mjs` and gated by `gates.requireFanoutEvidence`.
|
|
298
|
+
|
|
278
299
|
Do NOT use `gh pr comment`, `gh api`, or `gh pr review` for gate comments.
|
|
279
300
|
|
|
280
301
|
`--force --force-reason` on `upsert-checkpoint-verdict.mjs` is a narrow operator-authorized CI override for the helper itself, not the default gate path. Use it only when the helper refuses gate entry solely because the current head is `blocked_needs_user_decision` with `ciStatus="failure"`, and only after the user explicitly authorizes ignoring that current-head CI failure for this one gate-comment upsert. It does **not** bypass stale-head checks, unresolved-thread / unsettled-review refusal, non-draft `draft_gate` refusal, merge conflicts, or other legality checks.
|
|
281
302
|
|
|
303
|
+
### Gate fan-out/fan-in procedure (agent-orchestrated)
|
|
304
|
+
|
|
305
|
+
Both gates run this same checkpoint review chain. It is an **agent-orchestrated skill procedure** — a node script cannot spawn the per-angle reviewers, so the conductor agent drives the fan-out and uses the pure `@dev-loops/core/loop/gate-fanin` helpers only for consolidation, batching, and ledger mapping. The cost model is **build once, seed many**: the context-builder script builds ONE deterministic, neutral context bundle (diff + adjacent code) and each independent reviewer is seeded with that identical bundle verbatim instead of re-deriving it (work-dedup; no fork primitive, no Workflow tool). See [Gate Review Sub-Loop Contract](../../docs/gate-review-sub-loop-contract.md).
|
|
306
|
+
|
|
307
|
+
1. **Context (Phase 1) — build the neutral bundle ONCE:** build/read the gate-context artifact via `scripts/github/write-gate-context.mjs` (`buildGateContext` resolves the angle set through `resolveGateAnglesDynamic`; mandatory angles always survive). The artifact at `tmp/gate-context/<repo-slug>/pr-<N>/<gate>-<headSha>.json` carries the resolved angles + change scope + acceptance-criteria pointer. When the resolver was handed a diff with `diffOutput`, `buildGateContext` also persists the FULL diff to `tmp/gate-context/<repo-slug>/pr-<N>/<gate>-<headSha>.diff` and records `scope.diffPath` (relative) plus `scope.changedFiles` (full repo-relative paths). It ADDITIONALLY builds a deterministic, neutral `adjacentCode` bundle — each changed file plus its 1-hop import in/out-edges (callers/callees/imports), with size guards (skip lockfiles/generated/binary/minified; cap per-file bytes; truncate the long tail) recorded in a `stripped`/`truncated`/`missing` manifest. This single bundle is the build-once seed; reviewers do not re-derive the diff + adjacent code.
|
|
308
|
+
2. **Fan-out (Phase 2) — seed each reviewer with the bundle verbatim:** plan batches with `planFanoutBatches(angles, resolveMaxFanoutReviewers(config))` (default cap 8). Spawn one scoped `review` agent per resolved angle (plain Agent tool), parallel up to the cap, batching any overflow sequentially. When `degraded` is true, record the sequential degradation in the gate evidence. Reviewers are independent: each is seeded with the IDENTICAL neutral bundle (the gate-context artifact's `scope.diffPath` + `adjacentCode`) verbatim plus its single angle, and never inherits the conductor agent's conversation or opinions. Each reviewer follows the [review agent scoped angle-review mode](../../agents/review.agent.md): fresh context, single angle, read-only, writing its per-angle findings artifact to `tmp/gate-reviews/<repo-slug>/pr-<N>/<gate>-<headSha>/<angle>.json`. Brief each reviewer to use the provided bundle as its base and to review like an external code reviewer hunting real bugs: read the FULL diff (from `scope.diffPath`, or `git diff` when null) and the bundled adjacent code (callers, callees, imports) rather than re-deriving them, then review adversarially for concrete defects (edge cases, input validation, numeric coercion incl. NaN/Infinity/floats/negatives, null/undefined, boundary conditions, mismatched caller/callee contracts, dedup/identity bugs) with `file:line` + the failing scenario — not process nits like "no test exists". Reviewers are read-only and MAY widen scope (open adjacent repo files beyond the bundle) only when their angle genuinely needs more; that widening is recorded in the optional `contextWidened` field on each per-angle findings artifact.
|
|
309
|
+
3. **Fan-in (Phase 3):** consolidate the per-angle artifacts via `consolidateFanin({ angleResults, blockCleanOnFindingSeverities })` (blocking severities from `resolveGateConfig(config, <configKey>).blockCleanOnFindingSeverities`, where `<configKey>` is the config key for the gate — `draft` for `draft_gate`, `preApproval` for `pre_approval_gate` — not the `draft_gate|pre_approval_gate` artifact name). It yields the gate `verdict` (`clean` when no blocking-severity finding remains, `findings_present` when one does, `blocked` when any per-angle artifact is malformed/missing). Map consolidated findings with `toFindingsLogShape(...)` and write the disposition ledger via `write-gate-findings-log.mjs` **before** the visible comment. The ledger is written regardless of any comment opt-out. Then, when `resolveGatePostFindingsComments(config)` is true (default; opt-out via `gates.postFindingsComments: false`), post the consolidated findings as a visible, marker-tagged PR comment via `node <resolved-skill-scripts>/github/post-gate-findings.mjs --repo <owner/name> --pr <number> --gate <gate> --head-sha <current_head_sha> --findings '<toFindingsLogShape JSON>'` so the findings are auditable and Copilot/humans are aware of them. The helper is idempotent per gate (exactly one comment per gate, updated in place on each run; the reviewed head is shown in the body) and posts a brief "no findings" note when the consolidated set is empty. When `postFindingsComments` is false the helper no-ops with a `skipped` result and you skip this post step; the ledger still records the findings.
|
|
310
|
+
4. **Verdict (Phase 4):** post the verdict with the [Gate comment command](#mandatory-gate-comment-command-contract) using `--execution-mode fanout_fanin` and `--findings-json <path>`. Write that JSON from the collected per-angle results (the same per-angle `{angle, verdict, findings}` artifacts at `tmp/gate-reviews/<repo-slug>/pr-<N>/<gate>-<headSha>/<angle>.json` that fed `consolidateFanin` in Phase 3; the flat `toFindingsLogShape` output is also accepted and grouped by `.angle`) so the verdict comment renders the structured per-angle breakdown instead of a wall-of-text summary. Do NOT use `--findings-summary` for a fan-out gate — that is the inline_single_agent fallback.
|
|
311
|
+
5. **Retry (Phase 5):** on blocking findings, drive each internal fan-out finding through the SAME fix → reply-with-resolving-commit → resolve loop used for external Copilot review comments (Step 7 above): fix on the branch, push the resolving commit, then re-run only the `findings_present` angles from the previous pass (the context-builder and fan-in always re-run); repeat until the consolidated verdict is `clean` for the current head SHA. Internal fan-out findings and external review comments are handled identically by that loop.
|
|
312
|
+
|
|
282
313
|
### Draft gate contract (before marking PR ready for review)
|
|
283
314
|
|
|
284
315
|
The canonical checkpoint verdict comment contract is [Gate Review Comment Contract](../../docs/gate-review-comment-contract.md). This section summarizes the procedural integration only.
|
|
@@ -286,11 +317,16 @@ The canonical checkpoint verdict comment contract is [Gate Review Comment Contra
|
|
|
286
317
|
- **Gate name:** Draft gate
|
|
287
318
|
- **Trigger / boundary:** right before running `gh pr ready` (draft → ready for review)
|
|
288
319
|
- **Skip rule:** before entering the draft gate, run `detect-pr-gate-coordination-state.mjs` and check `draftGateAlreadySatisfied`. If `true`, skip the draft gate entirely — the draft→ready transition was already recorded. `draft_gate` is a one-time gate; do not re-post on new heads once clean draft-gate evidence exists for the transition record. (While the PR is still draft, advancing the head SHA does require a new draft-gate comment for the new head.) This skip rule applies only to the draft boundary.
|
|
289
|
-
- **Execution directive:** run the
|
|
320
|
+
- **Execution directive:** run the [Gate fan-out/fan-in procedure](#gate-fan-outfan-in-procedure-agent-orchestrated) (the agent-orchestrated chain defined in [Gate Review Sub-Loop Contract](../../docs/gate-review-sub-loop-contract.md)) with the draft gate inspection angles resolved from config.
|
|
290
321
|
- **Review angles:** resolved at runtime from config via `resolveGateAngles(config, "draft")` from `@dev-loops/core/config`. Default config enables all configured draft gate angle families; consumer repos may opt out individual angles via `excludeAngles`. Do **not** apply angles from the other gate; each gate owns its own angle list from config.
|
|
291
322
|
- **CI prerequisite:** resolve the draft gate config first (`resolveGateConfig(config, "draft")`). When `requireCi=true` (default), wait for green current-head CI before entering `draft_gate`. When `requireCi=false`, the draft gate may proceed without green CI. This draft-only override does **not** relax `pre_approval_gate`; final approval and merge readiness still require green current-head CI.
|
|
292
323
|
- **Pass criteria:** all configured draft gate angles pass; all findings at severities in `blockCleanOnFindingSeverities` are addressed; validation passes; no unrelated files are included.
|
|
293
324
|
- **Next step after passing:** mark the PR ready for review.
|
|
325
|
+
- **Board status sync (best-effort, after ready-for-review):** once the PR is created/marked ready for review, sync the linked issue's board item to "In Progress" so the queue board reflects active work without a manual `add-queue-item --status`:
|
|
326
|
+
```sh
|
|
327
|
+
node <resolved-skill-scripts>/projects/sync-item-status.mjs --repo <owner/name> --item <linked-issue> --to-column "In Progress"
|
|
328
|
+
```
|
|
329
|
+
Best-effort and NON-FATAL: it uses local `gh` auth (no CI/PAT), exits 0 when the board is not configured / the item is not on the board / the API fails, and never blocks marking the PR ready.
|
|
294
330
|
- **Non-substitution rule:** a clean `draft_gate` comment only authorizes the draft → ready-for-review transition for that head SHA. It does **not** satisfy `pre_approval_gate`, final-approval readiness, or merge-ready requirements.
|
|
295
331
|
- **Required PR comment:** post a visible checkpoint verdict comment using the mandatory [Gate comment command](#mandatory-gate-comment-command-contract). Keep validation reporting concise: include command names with pass/fail status. Do **not** paste raw passing test output into the visible gate comment. If you include a failing validation excerpt, keep it focused and truncate it to a deterministic retained-prefix length before posting the comment. See [Gate Review Comment Contract](../../docs/gate-review-comment-contract.md). Do not run `gh pr ready` unless a visible `clean` `draft_gate` checkpoint verdict comment exists for the current head SHA. A checkpoint verdict comment for an older head SHA does not satisfy this requirement for the current head. If findings exist, the PR stays draft and needs fixes before retry. If fixes advance the head SHA while still draft, post a new checkpoint verdict comment for the new head. If the checkpoint verdict comment cannot be posted, fail closed and do not run `gh pr ready`.
|
|
296
332
|
|
|
@@ -300,7 +336,7 @@ This is the default pre-approval gate for this workflow boundary. The canonical
|
|
|
300
336
|
|
|
301
337
|
- **Gate name:** Pre-approval gate
|
|
302
338
|
- **Trigger / boundary:** right before calling a PR/branch review-complete, approval-ready, merge-ready, or ready for final handoff
|
|
303
|
-
- **Execution directive:** run the
|
|
339
|
+
- **Execution directive:** run the [Gate fan-out/fan-in procedure](#gate-fan-outfan-in-procedure-agent-orchestrated) (the agent-orchestrated chain defined in [Gate Review Sub-Loop Contract](../../docs/gate-review-sub-loop-contract.md)) with the pre-approval gate inspection angles resolved from config. The `acceptance-criteria` angle is mandatory for this gate (see `.devloops` `gates.preApproval.mandatoryAngles`) and always survives dynamic resolution. Retry rule: in subsequent cycles, only re-run reviewers that produced `findings_present` in the previous pass.
|
|
304
340
|
- **Review angles:** resolved at runtime from config via `resolveGateAngles(config, "preApproval")` from `@dev-loops/core/config`. Default config enables all configured pre-approval gate angle families; consumer repos may opt out individual angles via `excludeAngles`.
|
|
305
341
|
- **Persona mapping:** each angle resolves to a reviewer persona via `resolveReviewerRole(config, angle)` from `@dev-loops/core/config`. Include this prompt in each reviewer's briefing so the reviewer knows exactly what to look for.
|
|
306
342
|
- **Pass criteria:** the sub-loop completes with verdict `clean`; all configured angles pass; if parallel execution is impractical, still run all configured lenses and explicitly record the limitation.
|
|
@@ -362,6 +398,24 @@ node <resolved-skill-scripts>/loop/checkpoint-contract.mjs --state skipped --rea
|
|
|
362
398
|
|
|
363
399
|
Do not report completion or advance to the next PR queue item until `.pi/dev-loop-retrospective-checkpoint.json` is updated to `complete` or `skipped`.
|
|
364
400
|
|
|
401
|
+
### Post-merge board archive (best-effort)
|
|
402
|
+
|
|
403
|
+
After the retrospective checkpoint write, optionally tidy the queue board locally:
|
|
404
|
+
|
|
405
|
+
```sh
|
|
406
|
+
node <resolved-skill-scripts>/projects/archive-done-items.mjs --repo <owner/name>
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Board and threshold resolve from `.devloops` (`queue.projectNumber`/`queue.boardTitle`, `queue.archiveOlderThanDays`, default 7d), using local `gh` auth — no CI, cron, or PAT. This step is best-effort and NON-FATAL: ignore any failure and never let it block the merge or the retrospective.
|
|
410
|
+
|
|
411
|
+
Alongside the archive step, sync the linked issue's board item to "Done" so the queue board reflects the merge without a manual `add-queue-item --status`:
|
|
412
|
+
|
|
413
|
+
```sh
|
|
414
|
+
node <resolved-skill-scripts>/projects/sync-item-status.mjs --repo <owner/name> --item <linked-issue> --to-column "Done"
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
Same best-effort/NON-FATAL contract as the archive step: local `gh` auth (no CI/PAT), exits 0 when the board is not configured / the item is not on the board / the API fails, and never blocks the merge or the retrospective.
|
|
418
|
+
|
|
365
419
|
## Validation policy
|
|
366
420
|
|
|
367
421
|
Follow [Validation Policy](../docs/validation-policy.md). Default: `npm run verify` before PR creation, gate entry, and merge. For repo-local examples: `npm run test:dev-loop` for skill scripts, contract tests for templates, `git diff --check` for docs. When CI runs exist, use `gh run watch` or `detect-copilot-loop-state.mjs` instead of `sleep`-based polling. Distinguish: locally validated, full PR-equivalent checks, awaiting CI.
|
|
@@ -9,9 +9,9 @@ export {
|
|
|
9
9
|
readRecordFromStdin,
|
|
10
10
|
runCli,
|
|
11
11
|
truncateText,
|
|
12
|
-
} from "
|
|
12
|
+
} from "@dev-loops/core/bash-exit-one";
|
|
13
13
|
|
|
14
|
-
import { runCli } from "
|
|
14
|
+
import { runCli } from "@dev-loops/core/bash-exit-one";
|
|
15
15
|
|
|
16
16
|
const invokedAsScript = process.argv[1]
|
|
17
17
|
? import.meta.url === pathToFileURL(process.argv[1]).href
|
|
@@ -13,9 +13,9 @@ export {
|
|
|
13
13
|
uniqueSortedStrings,
|
|
14
14
|
upsertPhaseIndex,
|
|
15
15
|
writeJson,
|
|
16
|
-
} from "
|
|
16
|
+
} from "@dev-loops/core/loop/phase-files";
|
|
17
17
|
|
|
18
|
-
import { runCli } from "
|
|
18
|
+
import { runCli } from "@dev-loops/core/loop/phase-files";
|
|
19
19
|
|
|
20
20
|
const invokedAsScript = process.argv[1]
|
|
21
21
|
? import.meta.url === pathToFileURL(process.argv[1]).href
|
|
@@ -10,6 +10,8 @@ Canonical owner for anti-pattern guidance across all workflow families.
|
|
|
10
10
|
4. **Merging directly to main without PR**: Use PR-based remote loop when practical.
|
|
11
11
|
5. **Duplicate worktree paths**: Check `git worktree list` before creating new worktrees; reuse existing matching worktrees.
|
|
12
12
|
6. **Main-checkout mutation**: Reserve main checkout for inspection/control; use `tmp/worktrees/` paths for mutation work.
|
|
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
|
+
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 project add ... --status "Next Up"`), 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.
|
|
13
15
|
|
|
14
16
|
## Light mode exception
|
|
15
17
|
|
|
@@ -172,9 +172,9 @@ Checkbox rule: acceptance criteria, definition-of-done items, and any task list
|
|
|
172
172
|
|
|
173
173
|
New PRs in this workflow must be opened as **draft** PRs first when the repository enables `.devloops` at repo root `workflow.requireDraftFirst`. The built-in shipped default remains permissive; this repo opts in. Do not create a fresh PR directly in ready-for-review state unless the user explicitly overrides that policy for the current PR scope. The draft gate inspection is a real workflow boundary, so a new PR must exist in draft before `gh pr ready` is even eligible.
|
|
174
174
|
|
|
175
|
-
Only use `node <resolved-skill-scripts>/github/create-
|
|
175
|
+
Only use `node <resolved-skill-scripts>/github/create-pr.mjs` when authoritative issue↔PR resolution says there is no already-open linked PR. If a PR already exists, reuse/update that canonical PR instead of opening another one. This wrapper preserves the underlying `gh pr create` output contract while enforcing draft-first mechanically and self-assigning the PR by default (`--assignee @me`).
|
|
176
176
|
|
|
177
|
-
MUST use `node <resolved-skill-scripts>/github/create-
|
|
177
|
+
MUST use `node <resolved-skill-scripts>/github/create-pr.mjs --repo <owner/name> --assignee @me --base <base> --head <head> --title "..." --body-file <body-file>` (always draft, self-assigned by default; `--assignee @me` is the default).
|
|
178
178
|
|
|
179
179
|
## Timeout and watch policy
|
|
180
180
|
|
|
@@ -59,7 +59,7 @@ When the local spec already lives in a tracker issue:
|
|
|
59
59
|
- sync durable scope / acceptance / status changes back to the tracker issue rather than maintaining a duplicate local phase doc
|
|
60
60
|
- keep `tmp/` as temporary local execution state only; it does not become a second durable spec surface
|
|
61
61
|
- for tracker-backed sessions, the handoff path is always: push the working branch → open a PR → merge via GitHub
|
|
62
|
-
- for tracker-backed sessions,
|
|
62
|
+
- for tracker-backed sessions, always open PRs through the canonical `dev-loops pr create` path, which is ALWAYS draft and always assigned — self-assigned by default (`--assignee @me` when none is given; honors an explicit `--assignee <login>` / `-a <login>`), never via raw `gh pr create`. The PR body must contain `Closes #N` (or `Fixes #N`) for the linked issue so GitHub auto-closes it on merge. When `.devloops` sets `workflow.requireDraftFirst` to true, use `dev-loops pr create --assignee @me ...`. Do not create a fresh PR directly in ready-for-review state unless the user explicitly overrides that policy for the current PR scope. The draft gate inspection is a real workflow boundary.
|
|
63
63
|
- do not suggest a direct local-main merge for tracker-backed sessions; do not merge the working branch into local `main` at phase completion
|
|
64
64
|
|
|
65
65
|
## Primary execution rules
|
|
@@ -87,6 +87,20 @@ This gate does **not** apply to other routed strategies (`copilot_pr_followup`,
|
|
|
87
87
|
|
|
88
88
|
Development-only bypass (`PI_PREFLIGHT_BYPASS=1`) exists for testing the gate itself but must not be used in production workflow runs. The bypass variable is a testing convenience, not an operational escape hatch.
|
|
89
89
|
|
|
90
|
+
## Narrow failure-triage fast path
|
|
91
|
+
|
|
92
|
+
When resuming local implementation with dirty work or an observed failing command, use this path before broad discovery:
|
|
93
|
+
|
|
94
|
+
1. run startup once from the relevant worktree/context
|
|
95
|
+
2. inspect current state with `git status` and the changed files
|
|
96
|
+
3. reproduce or identify the failing command
|
|
97
|
+
4. run an exact-pattern search in changed files for the suspect call site
|
|
98
|
+
5. patch the minimum call sites
|
|
99
|
+
6. run focused smoke checks for that failure
|
|
100
|
+
7. run default verification
|
|
101
|
+
|
|
102
|
+
Follow [Anti-patterns](../docs/anti-patterns.md) for the general tooling-internals and duplicate-broad-search prohibition; this local fast path owns only the ordered failure-triage procedure above.
|
|
103
|
+
|
|
90
104
|
### Step 1
|
|
91
105
|
|
|
92
106
|
- Implement **one phase at a time**.
|
|
@@ -513,7 +527,7 @@ After the phase plan passes review:
|
|
|
513
527
|
10. Update `tmp/phases/phase-x/manifest.json` and `tmp/phases/index.json`.
|
|
514
528
|
11. Update [Implementation State](../../docs/IMPLEMENTATION_STATE.md).
|
|
515
529
|
12. **Exit validation gate — no uncommitted changes.** Before the subagent session terminates, run `git status --porcelain` and verify the output is empty. If uncommitted changes exist, first determine whether they are intended implementation changes or unintended/post-validation deltas. Revert any unintended or speculative changes. For intended changes, rerun the narrowest justified validation (`npm run verify` or equivalent) before staging and committing with an appropriate message; for tracker-backed sessions, also push the branch. A subagent session that exits with uncommitted changes in the worktree is a workflow defect and must not be treated as a clean completion. After committing, verify `git status --porcelain` is empty before declaring phase completion.
|
|
516
|
-
13. For tracker-backed sessions, create
|
|
530
|
+
13. For tracker-backed sessions, create the PR from the working branch using the canonical `dev-loops pr create --assignee @me --repo <owner/name> --base main --head <branch> --title "..." --body-file <body-file>` (always draft, self-assigned by default; `--assignee @me` is the default and is shown here for clarity). When the `dev-loops` CLI helper is unavailable, use the equivalent `create-pr.mjs` script directly: `node <resolved-skill-scripts>/github/create-pr.mjs --repo <owner/name> --assignee @me --base main --head <branch> --title "..." --body-file <body-file>`. Never open a PR with raw `gh pr create`. The PR body must contain `Closes #N` (or `Fixes #N`) for the linked issue. Do not create a fresh PR directly in ready-for-review state unless the user explicitly overrides that policy.
|
|
517
531
|
14. If authorized, merge the fully reviewed, locally validated phase branch back into local `main` (phase-doc-backed sessions) or proceed through the PR gate pipeline (tracker-backed sessions).
|
|
518
532
|
15. If authorization for PR creation or merge is still pending (commit authorization is already enforced by the exit validation gate in step 12), mark the phase as `awaiting-finalization` rather than `completed`, and record exactly which finalization step is pending.
|
|
519
533
|
|
|
@@ -620,7 +634,7 @@ See [Stop Conditions](../docs/stop-conditions.md). Local-specific stops: phase c
|
|
|
620
634
|
- Rerun validation after review-driven fixes.
|
|
621
635
|
- A phase is not operationally closed until its branch state is captured in commit history and the reviewed branch has been finalized according to session type (merged into local `main` for phase-doc-backed sessions; merged via GitHub PR for tracker-backed sessions), unless authorization for that finalization is still pending.
|
|
622
636
|
- For tracker-backed sessions, the handoff path is always: push the working branch → open a PR → merge via GitHub; never merge the working branch into local `main`.
|
|
623
|
-
- PR creation
|
|
637
|
+
- PR creation always goes through `dev-loops pr create`, which is ALWAYS draft and always assigned — self-assigned by default (`--assignee @me` when none is given; honors an explicit `--assignee <login>` / `-a <login>`), never via raw `gh pr create`, and the PR body must contain `Closes #N` (or `Fixes #N`) for the linked issue so GitHub auto-closes it on merge. When `.devloops` sets `workflow.requireDraftFirst` to true, use `dev-loops pr create --assignee @me ...`. Do not create a fresh PR directly in ready-for-review state unless the user explicitly overrides that policy for the current PR scope. The draft gate inspection is a real workflow boundary, so a new PR must exist in draft before `gh pr ready` is eligible.
|
|
624
638
|
- When authorization is pending, record the phase as `awaiting-finalization` and describe the exact missing step.
|
|
625
639
|
- For phase-doc-backed sessions, merge the fully reviewed, locally validated branch back into local `main` when authorized.
|
|
626
640
|
|