devflow-kit 2.2.0 → 2.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/CHANGELOG.md +24 -0
- package/dist/commands/resolve.md +29 -16
- package/package.json +1 -1
- package/src/assets/agents/learning.md +63 -13
- package/src/assets/agents/triage.md +19 -1
- package/src/assets/commands/resolve.mds +29 -16
- package/src/assets/scripts/hooks/background-memory-update +180 -37
- package/src/assets/scripts/hooks/is-hex-sha +14 -0
- package/src/assets/scripts/hooks/json-helper.cjs +223 -38
- package/src/assets/scripts/hooks/lib/decisions-format.cjs +264 -43
- package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +1 -1
- package/src/assets/scripts/hooks/lib/render-decisions.cjs +59 -28
- package/src/assets/scripts/hooks/pre-compact-memory +40 -22
- package/src/assets/scripts/hooks/session-start-memory +19 -20
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to Devflow will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.3.0] - 2026-08-31
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **`refresh-anchor` ledger op**: post-promotion reinforcement now reaches rendered output. When the Learning agent reinforces an already-anchored observation (sharpening its `pattern`/`details`), calling `refresh-anchor <anchor_id>` re-projects the updated log row through the same `toLedgerRow` projector as `assign-anchor` and re-renders all three `.md` files. Previously, post-promotion sharpening was written to the log but never projected forward, so the rendered entry silently froze at its first-promotion snapshot.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **`decisions-ledger.jsonl` is now the anchor registry only (ADR-022)**: `decisions-log.jsonl` is the content authority; the ledger holds anchor numbers and `decisions_status` only. Entry content reaches the ledger exclusively through `assign-anchor` (first promotion) and `refresh-anchor` (post-promotion re-projection) via `toLedgerRow`. The Learning agent's previously sanctioned path of editing ledger rows directly is removed — content changes go to the log, then `refresh-anchor` re-projects. Tooling that reads or writes `decisions-ledger.jsonl` directly is affected.
|
|
15
|
+
- **`/resolve` DUPLICATE verdict**: `/resolve` now collapses duplicate cross-reviewer findings via a new `DUPLICATE` triage verdict — resolution-summary counts unique issues, with a `Duplicates Collapsed` statistics row and a `## Duplicates` section for traceability.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **Semicolon-safe `details` field parsing**: the decisions formatter now splits `details` into fields using a segment-aware parser (`segmentDetails`) instead of delimiter regexes. The parser recognises a segment as a new field only when it starts with a known key name followed by `:` (anchored to segment start); semicolons inside values are preserved. Fixes four related defects: truncation at the first internal semicolon, unanchored-key false match (e.g. `reissue:` matching `issue:`), first-match-wins hijack (a key name mentioned inside an earlier value would capture the wrong segment), and newline breakage. Measured blast radius on this repo's own ledger: 111 truncated field extractions before the fix, 0 after. **Installed projects' rendered decisions/pitfalls `.md` may show one-time `--check` drift under the new parser — self-heals on the next ledger op.**
|
|
19
|
+
- **Armed double-assign guard**: `assign-anchor` now writes `anchor_id` back to the log row on promotion, enabling the guard that prevents re-anchoring an already-anchored observation. Previously `anchor_id` was never written back, so the guard was permanently inert and running `assign-anchor` twice on the same observation silently minted two anchors.
|
|
20
|
+
- **Pitfall date stamping and render date-purity**: `assign-anchor` now stamps a `date` field on all entry types (decisions and pitfalls). Previously only decision rows received a date stamp, leaving the 7-day protection window permanently inert for all pitfall entries. Render formatters now use `row.date || ''` (D5) instead of reading the clock, making renders deterministic and avoiding phantom date changes on re-render.
|
|
21
|
+
- **Amendments rendering**: `formatAmendmentsLine` renders the `amendments` field as a `- **Amendments**: ...` line in the entry body. Previously the projected `amendments` field was never rendered, so amendment notes were lost at the `.md` level. Index extraction regexes are now line-anchored (`/m` flag) to prevent amendment text that mentions `- **Status**:` or `- **Area**:` from hijacking the extracted values.
|
|
22
|
+
- **Working memory worker staged-write CAS** (closes #306): the background memory worker now writes to `WORKING-MEMORY.md.new` (staged file, never the real path) and compare-and-swaps into place only if `WORKING-MEMORY.md` is byte-identical to the pre-run snapshot. Previously the success check accepted any mtime bump on a file whose line 1 carried the stamp prefix — including a human's own concurrent edit — and on that false success the worker deleted the unprocessed queue batch and touched `.last-refresh-ok`, producing silent loss of captured turns under a healthy freshness marker.
|
|
23
|
+
- **Stamped pre-compact bootstrap**: `pre-compact-memory` now writes a HEAD SHA stamp on line 1 of `WORKING-MEMORY.md` (guarded by a 40-hex validation gate) and lays out the five canonical sections in fixed order. Previously the bootstrap ran without a stamp, producing "synced @ unknown" at the next SessionStart and an incorrect State-A classification that hid any real drift.
|
|
24
|
+
- **Reconciliation-aware worker prompt**: the memory worker prompt now includes bounded git evidence since the last stamp, explicit reconciliation and expiry guidance, and a strict DONE definition (per PF-010). Addresses unbounded carry-forward, conversation-coined labels promoted to durable state, and no-expiry instruction.
|
|
25
|
+
- **State-C orphaned `.processing` visibility**: `session-start-memory`'s State C queue-depth count now includes lines from any orphaned `.pending-turns.processing` file, not just `.pending-turns.jsonl`. Previously an orphaned `.processing` was invisible to the State C detector, so a CONFLICT-requeued batch did not show in the refresh-failing banner.
|
|
26
|
+
- **`/resolve` base branch token**: resolution summaries now render the base branch name instead of a literal `{base}` token. Step 0b was not extracting `base_branch` while the summary template referenced it.
|
|
27
|
+
- **render summary byte counts**: `render-decisions.cjs` now reports file sizes via `Buffer.byteLength()` instead of `String.length`. The em dash separator in index Area fields (U+2014, 3 UTF-8 bytes, 1 JS character) caused the logged index.md size to be 2 bytes per em dash in the rendered index under the old code.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
8
31
|
## [2.2.0] - 2026-08-25
|
|
9
32
|
|
|
10
33
|
### Changed
|
|
@@ -1192,6 +1215,7 @@ devflow init
|
|
|
1192
1215
|
---
|
|
1193
1216
|
|
|
1194
1217
|
[Unreleased]: https://github.com/dean0x/devflow/compare/v2.0.0...HEAD
|
|
1218
|
+
[2.3.0]: https://github.com/dean0x/devflow/compare/v2.2.0...v2.3.0
|
|
1195
1219
|
[2.2.0]: https://github.com/dean0x/devflow/compare/v2.1.0...v2.2.0
|
|
1196
1220
|
[2.1.0]: https://github.com/dean0x/devflow/compare/v2.0.1...v2.1.0
|
|
1197
1221
|
[2.0.1]: https://github.com/dean0x/devflow/compare/v2.0.0...v2.0.1
|
package/dist/commands/resolve.md
CHANGED
|
@@ -50,7 +50,7 @@ In multi-worktree mode, spawn all pre-flight agents **in a single message** (par
|
|
|
50
50
|
|
|
51
51
|
**If BLOCKED:** In single-worktree mode, stop and report the blocker to user. If no reviews found, suggest `/code-review` or `/bug-analysis` first. In multi-worktree mode, report the failure but continue with other worktrees.
|
|
52
52
|
|
|
53
|
-
**Extract from response:** `branch`, `branch_slug`, `pr_number`, `review_count`, `diff_files` per worktree.
|
|
53
|
+
**Extract from response:** `branch`, `base_branch`, `branch_slug`, `pr_number`, `review_count`, `diff_files` per worktree.
|
|
54
54
|
|
|
55
55
|
**Fetch PR body** (after extracting `pr_number`):
|
|
56
56
|
```bash
|
|
@@ -186,7 +186,7 @@ Issues are extracted from `{TARGET_DIR}` only — never cross-reference reviews
|
|
|
186
186
|
### Phase 1b: Fetch External Review Threads (Compliance-gated)
|
|
187
187
|
|
|
188
188
|
**Produces:** THREAD_MAP
|
|
189
|
-
**Requires:**
|
|
189
|
+
**Requires:** BRANCH_INFO, COMPLIANCE_SKILL_INSTALLED
|
|
190
190
|
|
|
191
191
|
Skip this phase if `COMPLIANCE_SKILL_INSTALLED` is false.
|
|
192
192
|
|
|
@@ -205,7 +205,7 @@ Parse `THREAD_MAP` from Git agent output. If Git agent returns `TRACEABILITY: DE
|
|
|
205
205
|
### Phase 2: Global Triage
|
|
206
206
|
|
|
207
207
|
**Produces:** TRIAGE_RESULTS
|
|
208
|
-
**Requires:** ISSUES, DIFF_FILES, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, PR_DESCRIPTION
|
|
208
|
+
**Requires:** ISSUES, DIFF_FILES, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, PR_DESCRIPTION
|
|
209
209
|
|
|
210
210
|
Spawn a single global Triage agent for ALL issues:
|
|
211
211
|
|
|
@@ -217,7 +217,7 @@ WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
|
217
217
|
DECISIONS_CONTEXT: {decisions_context}
|
|
218
218
|
FEATURE_KNOWLEDGE: {feature_knowledge}
|
|
219
219
|
PR_DESCRIPTION: <pr-description>{pr_description}</pr-description>
|
|
220
|
-
Triage every issue
|
|
220
|
+
Triage every issue: collapse duplicates first, then apply the blast-radius disposition matrix to each group's primary. Assign exactly one verdict per issue.
|
|
221
221
|
Follow devflow:apply-decisions to Read full ADR/PF bodies on demand.
|
|
222
222
|
Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE."
|
|
223
223
|
```
|
|
@@ -229,11 +229,12 @@ Wait for Triage agent to complete before proceeding. Parse verdict ledger from T
|
|
|
229
229
|
- **BY_DESIGN**: Intentional code (with ADR or code doc citation)
|
|
230
230
|
- **FIX_SEPARATE**: Valid but out of blast-radius scope (must become manage-debt ticket)
|
|
231
231
|
- **TECH_DEBT**: Architectural overhaul only — LAST RESORT
|
|
232
|
+
- **DUPLICATE**: Collapsed duplicate issue — carries `duplicate_of: <primary-id>` referencing the non-DUPLICATE primary; inherits the primary's outcome
|
|
232
233
|
|
|
233
234
|
Collect all decisions citations (ADR-NNN / PF-NNN) from Triage agent Reasoning columns.
|
|
234
235
|
|
|
235
236
|
**Triage agent completeness assertion (avoids PF-002):** Verify the parsed ledger against ISSUES before proceeding:
|
|
236
|
-
1. Every issue `id` from ISSUES must appear in exactly one verdict bucket — none may vanish, none may appear in multiple buckets.
|
|
237
|
+
1. Every issue `id` from ISSUES must appear in exactly one verdict bucket — none may vanish, none may appear in multiple buckets. DUPLICATE is a valid bucket; a valid DUPLICATE entry must name its `duplicate_of` primary (the `Duplicate Of` column of the ledger's DUPLICATE table) and that primary must be a non-DUPLICATE issue id. A missing `duplicate_of` or one that chains to another DUPLICATE is a **Triage agent failure** (retry-then-abort as below).
|
|
237
238
|
2. If the Triage agent output is empty, contains a skill re-entrancy guard string (e.g., contains `already running`), or is missing any issue IDs from ISSUES: treat as a **Triage agent failure**:
|
|
238
239
|
- Retry the Triage agent once with the same inputs.
|
|
239
240
|
- If the retry also fails the completeness check: abort with a clear error message listing the missing issue IDs and failure reason — never proceed with dropped issues.
|
|
@@ -247,7 +248,7 @@ Collect all decisions citations (ADR-NNN / PF-NNN) from Triage agent Reasoning c
|
|
|
247
248
|
|
|
248
249
|
If FIX_NOW list is empty: skip to Phase 5 — write full summary (Phase 5), run manage-debt (Phase 9) if FIX_SEPARATE/TECH_DEBT exist, run thread resolution + resolution comment (Phase 9b), run merge readiness (Phase 9c), display results (Phase 10).
|
|
249
250
|
|
|
250
|
-
Otherwise, batch FIX_NOW issues for Code agent execution:
|
|
251
|
+
Otherwise, batch FIX_NOW issues for Code agent execution. **DUPLICATE issues are never dispatched** — they inherit the primary's outcome:
|
|
251
252
|
- **Same-file issues** → one batch (one Code agent per file, sequential for same-file pairs)
|
|
252
253
|
- **Distinct-file issues** → parallel Code agents
|
|
253
254
|
- **Max 5 issues per batch** — chunk large sets
|
|
@@ -255,7 +256,7 @@ Otherwise, batch FIX_NOW issues for Code agent execution:
|
|
|
255
256
|
### Phase 4: Fix (Code agent × N)
|
|
256
257
|
|
|
257
258
|
**Produces:** CODE_AGENT_RESULTS
|
|
258
|
-
**Requires:** BATCHES, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
|
|
259
|
+
**Requires:** BATCHES, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
|
|
259
260
|
|
|
260
261
|
For each batch, spawn Code agent with `OPERATION: issue-fix` and `PUSH: false`:
|
|
261
262
|
|
|
@@ -284,12 +285,14 @@ Collect from each Code agent:
|
|
|
284
285
|
### Phase 5: Write resolution-summary.md
|
|
285
286
|
|
|
286
287
|
**Produces:** RESOLUTION_FILE (early write for compaction safety)
|
|
287
|
-
**Requires:** TRIAGE_RESULTS, CODE_AGENT_RESULTS
|
|
288
|
+
**Requires:** TRIAGE_RESULTS, CODE_AGENT_RESULTS, TARGET_DIR, BRANCH_INFO
|
|
288
289
|
|
|
289
290
|
**Immediately write `resolution-summary.md`** to `{TARGET_DIR}` using the Write tool. Do this now — not in Phase 9 — while results are fresh in context. This ensures the record is persisted even if later phases (Simplify, Verification Gate, CI gate, Tech Debt) trigger context compaction.
|
|
290
291
|
|
|
291
292
|
Set `Tracked` for FIX_SEPARATE and TECH_DEBT items to `(pending)` — to be backfilled after Phase 9 manage-debt.
|
|
292
293
|
|
|
294
|
+
DUPLICATE issues are listed **only** in `## Duplicates` — never in `## Fixed Issues`, `## False Positives`, `## By Design`, `## Fix Separately`, `## Deferred to Tech Debt`, `## Escalations`, or `## Blocked`. A duplicate of a FALSE_POSITIVE primary therefore leaves only the primary in the `False Positive` row and the `## False Positives` section; the same holds for every other outcome the duplicate inherits.
|
|
295
|
+
|
|
293
296
|
Use the template from the Output Artifact section below.
|
|
294
297
|
|
|
295
298
|
### Phase 6: Simplify
|
|
@@ -382,7 +385,7 @@ Otherwise, for each worktree with fixes:
|
|
|
382
385
|
|
|
383
386
|
**IMPORTANT**: Run sequentially across all worktrees (not in parallel) to avoid GitHub API conflicts.
|
|
384
387
|
|
|
385
|
-
If any issues are FIX_SEPARATE or TECH_DEBT, spawn Git agent:
|
|
388
|
+
If any issues are FIX_SEPARATE or TECH_DEBT, spawn Git agent. **DUPLICATE issues never create their own debt tickets** — a duplicate of a deferred primary is covered by the primary's ticket:
|
|
386
389
|
|
|
387
390
|
```
|
|
388
391
|
Agent(subagent_type="Git"):
|
|
@@ -407,6 +410,7 @@ Skip this step if `COMPLIANCE_SKILL_INSTALLED` is false or THREAD_MAP is empty.
|
|
|
407
410
|
|
|
408
411
|
Prepare THREAD_MAP with verdicts from triage/code agent results:
|
|
409
412
|
- For each `ext-{N}`: match to an issue verdict (FIXED, FALSE_POSITIVE, BY_DESIGN, ESCALATED) by `file:line` correlation
|
|
413
|
+
- If the matched issue has verdict DUPLICATE, use the **primary's** verdict and verification status for the reply — do not expose DUPLICATE to the thread author (avoids PF-024; caller-side mapping — git.md contracts unchanged)
|
|
410
414
|
- Include `commit_sha` from Code agent results for FIXED verdicts
|
|
411
415
|
- Unmatched threads: ESCALATED (human review)
|
|
412
416
|
|
|
@@ -447,7 +451,7 @@ Update `## Third-Party Threads` section in resolution-summary.md with thread res
|
|
|
447
451
|
### Phase 9c: Merge Readiness (Compliance-gated, Report-only)
|
|
448
452
|
|
|
449
453
|
**Produces:** MERGE_READINESS_REPORT
|
|
450
|
-
**Requires:**
|
|
454
|
+
**Requires:** BRANCH_INFO, COMPLIANCE_SKILL_INSTALLED
|
|
451
455
|
|
|
452
456
|
Skip this phase if `COMPLIANCE_SKILL_INSTALLED` is false.
|
|
453
457
|
|
|
@@ -466,7 +470,7 @@ If Git agent returns `TRACEABILITY: DEGRADED`: warn, proceed to Phase 10.
|
|
|
466
470
|
|
|
467
471
|
### Phase 10: Report
|
|
468
472
|
|
|
469
|
-
**Requires:** TARGET_DIR
|
|
473
|
+
**Requires:** BRANCH_INFO, TARGET_DIR
|
|
470
474
|
|
|
471
475
|
The resolution summary was already written to `{TARGET_DIR}/resolution-summary.md` in Phase 5 (updated by Phase 7 and Phase 9). Display results to the user:
|
|
472
476
|
|
|
@@ -486,6 +490,7 @@ The resolution summary was already written to `{TARGET_DIR}/resolution-summary.m
|
|
|
486
490
|
| Deferred | {n} |
|
|
487
491
|
| Blocked | {n} |
|
|
488
492
|
| Escalated | {n} |
|
|
493
|
+
| Duplicates Collapsed | {n} |
|
|
489
494
|
|
|
490
495
|
### Verification
|
|
491
496
|
Final gate: {PASS | FAILED after N attempts}
|
|
@@ -578,9 +583,9 @@ After writing, commit the two files to the current worktree branch yourself by r
|
|
|
578
583
|
│ └─ Git agent (fetch-review-threads) → THREAD_MAP
|
|
579
584
|
│
|
|
580
585
|
├─ Phase 2: Global Triage [Triage agent, opus, single agent]
|
|
581
|
-
│ └─ ALL issues → verdict ledger by disposition
|
|
586
|
+
│ └─ ALL issues → verdict ledger by disposition (incl. DUPLICATE with duplicate_of)
|
|
582
587
|
│
|
|
583
|
-
├─ Phase 3: Batch FIX_NOW issues (skip if empty)
|
|
588
|
+
├─ Phase 3: Batch FIX_NOW issues (skip if empty; DUPLICATE issues never dispatched)
|
|
584
589
|
│ └─ same-file sequential, distinct-file parallel, max 5/batch
|
|
585
590
|
│
|
|
586
591
|
├─ Phase 4: Fix [Code agent × N, OPERATION: issue-fix, PUSH: false]
|
|
@@ -623,6 +628,8 @@ After writing, commit the two files to the current worktree branch yourself by r
|
|
|
623
628
|
| Worktree pre-flight fails | Report failure, continue with other worktrees |
|
|
624
629
|
| Empty FIX_NOW list | Skip Phases 3-4/6-8; still write full summary + run manage-debt if FIX_SEPARATE/TECH_DEBT exist |
|
|
625
630
|
| ESCALATED security issues | Surfaced in ## Escalations + display callout; never routed to manage-debt |
|
|
631
|
+
| DUPLICATE verdict without duplicate_of, or chained to another DUPLICATE | Treated as Triage failure — same retry-then-abort as a vanished id |
|
|
632
|
+
| DUPLICATE issues in THREAD_MAP | Map ext-{N} to primary's verdict/verification status for thread reply |
|
|
626
633
|
| Verification Gate FAILED after 2 attempts | Recorded as FAILED in ## Verification + blocking callout; CI gate skipped; proceed to Phase 9 (manage-debt) then Phase 10 (display) |
|
|
627
634
|
| gh/GitHub absent | manage-debt fails gracefully; Tracked stays "(pending)" + noted — recorded, not dropped |
|
|
628
635
|
| COMPLIANCE_SKILL_INSTALLED false | Phases 1b, 9b-step-1, and 9c are skipped; post-resolution-summary (Phase 9b step 2) still runs if a PR is known |
|
|
@@ -651,7 +658,7 @@ Written in Phase 5 (Collect Results) to `{TARGET_DIR}/resolution-summary.md`:
|
|
|
651
658
|
```markdown
|
|
652
659
|
# Resolution Summary
|
|
653
660
|
|
|
654
|
-
**Branch**: {branch} -> {
|
|
661
|
+
**Branch**: {branch} -> {base_branch}
|
|
655
662
|
**Date**: {timestamp}
|
|
656
663
|
**Review**: {TARGET_DIR}
|
|
657
664
|
**Command**: /resolve
|
|
@@ -673,8 +680,9 @@ Written in Phase 5 (Collect Results) to `{TARGET_DIR}/resolution-summary.md`:
|
|
|
673
680
|
| Deferred | {n} |
|
|
674
681
|
| Blocked | {n} |
|
|
675
682
|
| Escalated | {n} |
|
|
683
|
+
| Duplicates Collapsed | {n} |
|
|
676
684
|
|
|
677
|
-
_(Note: `Deferred` = `## Fix Separately` count + `## Deferred to Tech Debt` count combined — the two sections are distinct by scope, but the Statistics row aggregates both for the convergence parser.)_
|
|
685
|
+
_(Note: `Deferred` = `## Fix Separately` count + `## Deferred to Tech Debt` count combined — the two sections are distinct by scope, but the Statistics row aggregates both for the convergence parser. `Total Issues` counts every triaged issue including collapsed duplicates; every row **between** `Total Issues` and `Duplicates Collapsed` counts UNIQUE (non-DUPLICATE) issues only, so `Total Issues` equals the sum of the rows below it. Excluding duplicates from `Fixed`, `False Positive`, and `Deferred` de-skews the fp\_ratio convergence formula in code-review without any parser change.)_
|
|
678
686
|
|
|
679
687
|
## Verification
|
|
680
688
|
| Command | Result |
|
|
@@ -720,6 +728,11 @@ Final gate: PASS | FAILED after {n} attempts
|
|
|
720
728
|
|-------|-----------|---------|
|
|
721
729
|
| {description} | {file}:{line} | {why} |
|
|
722
730
|
|
|
731
|
+
## Duplicates
|
|
732
|
+
| Issue | Duplicate Of | File:Line |
|
|
733
|
+
|-------|-------------|-----------|
|
|
734
|
+
| {description} | {primary-id} | {file}:{line} |
|
|
735
|
+
|
|
723
736
|
## Third-Party Threads
|
|
724
737
|
| Thread | File:Line | Verdict | Status |
|
|
725
738
|
|--------|-----------|---------|--------|
|
|
@@ -728,4 +741,4 @@ Final gate: PASS | FAILED after {n} attempts
|
|
|
728
741
|
|
|
729
742
|
_(Omit `## Third-Party Threads` if `COMPLIANCE_SKILL_INSTALLED` is false or no external threads were found.)_
|
|
730
743
|
|
|
731
|
-
**Statistics mapping (parser contract)**: the `Deferred` row = FIX_SEPARATE + TECH_DEBT (both deferral dispositions combined); By Design and Escalated are counted separately and excluded from `Deferred`. The `/code-review` convergence parser reads
|
|
744
|
+
**Statistics mapping (parser contract)**: the `Deferred` row = FIX_SEPARATE + TECH_DEBT (both deferral dispositions combined); By Design and Escalated are counted separately and excluded from `Deferred`. The `Duplicates Collapsed` row is additive — the `/code-review` convergence parser reads only `Deferred`, `Fixed`, and `False Positive` rows plus `## Fixed Issues` / `## False Positives` headings — keep those labels byte-stable. All rows that the parser reads count UNIQUE (non-DUPLICATE) issues only, so collapsed duplicates do not inflate fp\_ratio.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devflow-kit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "A meta-harness for Claude Code — turns a single coding agent into an engineering team: orchestration, parallel review, persistent memory, self-learning, and graph workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@ skills:
|
|
|
18
18
|
You process the pending decisions queue for one project: claim it atomically, detect
|
|
19
19
|
decision/pitfall patterns worth keeping, curate the existing ledger, and delete the claimed
|
|
20
20
|
queue as your final act. You read and edit the data files directly — no script reads,
|
|
21
|
-
validates, or applies anything on your behalf. The only executables you call are the
|
|
21
|
+
validates, or applies anything on your behalf. The only executables you call are the four
|
|
22
22
|
ledger ops below.
|
|
23
23
|
|
|
24
24
|
## Iron Law
|
|
@@ -26,11 +26,12 @@ ledger ops below.
|
|
|
26
26
|
> **assign-anchor OWNS NUMBERING; render OWNS THE .md; NEVER HAND-EDIT decisions.md, pitfalls.md, or index.md**
|
|
27
27
|
>
|
|
28
28
|
> ADR and PF numbers are assigned exclusively by `assign-anchor`. The `.md` files are written
|
|
29
|
-
> exclusively by `render-decisions.cjs` (invoked internally by `assign-anchor`/`retire-anchor`).
|
|
30
|
-
> One `assign-anchor` invocation claims one number and re-renders all three files
|
|
31
|
-
> (decisions.md, pitfalls.md, index.md
|
|
32
|
-
>
|
|
33
|
-
>
|
|
29
|
+
> exclusively by `render-decisions.cjs` (invoked internally by `assign-anchor`/`retire-anchor`/`refresh-anchor`).
|
|
30
|
+
> One `assign-anchor` invocation claims one number and re-renders all three files
|
|
31
|
+
> (decisions.md, pitfalls.md, index.md — each write atomic; the sequence is not transactional:
|
|
32
|
+
> a crash between writes self-heals on the next op). To deprecate, supersede, or retire an entry, call
|
|
33
|
+
> `retire-anchor <anchor_id> <status>` — never edit the `.md` files directly. Every ledger op
|
|
34
|
+
> re-renders all three files internally; there is no separate render step for you to run.
|
|
34
35
|
|
|
35
36
|
## Environment
|
|
36
37
|
|
|
@@ -39,6 +40,7 @@ are relative to it. The ledger ops live at `$HOME/.devflow/scripts/hooks/json-he
|
|
|
39
40
|
|
|
40
41
|
- `assign-anchor <type> <obs_id>` — claims the next ADR/PF number and re-renders all three `.md` files (decisions.md, pitfalls.md, index.md)
|
|
41
42
|
- `retire-anchor <anchor_id> <status>` — flips a ledger row's rendered status and re-renders
|
|
43
|
+
- `refresh-anchor <anchor_id> [<anchor_id>...]` — variadic: re-projects one or more anchored log rows through the same projector as `assign-anchor` in a single lock/parse/render pass; use after reinforcing already-anchored observations (ADR-022)
|
|
42
44
|
- `rotate-observations` — archives `observing` log rows older than 30 days
|
|
43
45
|
|
|
44
46
|
Each op self-locks internally. Call them plainly — never wrap them in a lock of your own,
|
|
@@ -119,6 +121,23 @@ rewrite the whole file:
|
|
|
119
121
|
timestamps are UTC ISO (`date -u +%Y-%m-%dT%H:%M:%SZ`). Estimate `confidence` honestly —
|
|
120
122
|
it is curation metadata only, NOT a gate; do not inflate it.
|
|
121
123
|
|
|
124
|
+
**`details` grammar**: use `Key: value` segments separated by `;`. Recognised keys are per
|
|
125
|
+
type and disjoint — decisions: `context:`, `decision:`, `rationale:`; pitfalls: `area:`,
|
|
126
|
+
`issue:`, `impact:`, `resolution:`. A segment that begins with a key recognised FOR THAT TYPE
|
|
127
|
+
starts a new field; any other segment (including a key from the opposite type) is appended to
|
|
128
|
+
the previous field's value, so semicolons inside a value are preserved. Keep prose out of key
|
|
129
|
+
positions — do not start a value with text that looks like a recognised key for that type. The
|
|
130
|
+
parser has a recovery pass for legacy mid-segment keys.
|
|
131
|
+
|
|
132
|
+
**`amendments` field**: when reinforcing an already-anchored observation with a dated
|
|
133
|
+
correction or ratification that should remain visible as history (rather than silently
|
|
134
|
+
rewriting `details`), APPEND `{ "date": "YYYY-MM-DD", "note": "..." }` to the log row's
|
|
135
|
+
`amendments` array (create the array if absent). The shape is exactly `{date, note}` — the
|
|
136
|
+
schema guard rejects bare strings. Amendments render at the end of the entry body in
|
|
137
|
+
`decisions.md`/`pitfalls.md`; they never appear in `index.md` lines. A follow-up
|
|
138
|
+
`refresh-anchor <anchor_id>` is required to propagate the addition to the rendered files
|
|
139
|
+
(ADR-022).
|
|
140
|
+
|
|
122
141
|
- **Reinforce an existing row** — use the Edit tool to replace that row's single line:
|
|
123
142
|
increment `observations`, union `evidence` (dedupe, cap 10), update `last_seen`, and
|
|
124
143
|
refresh `pattern`/`details`/`confidence` only where the new evidence sharpens them.
|
|
@@ -134,12 +153,32 @@ node "$HOME/.devflow/scripts/hooks/json-helper.cjs" assign-anchor "pitfall" "obs
|
|
|
134
153
|
NEVER hand-edit `decisions.md` or `pitfalls.md`. NEVER invent an ADR-NNN/PF-NNN number
|
|
135
154
|
yourself — `assign-anchor` is the only source of numbering.
|
|
136
155
|
|
|
156
|
+
**After reinforcing already-anchored observations**: once you have updated all target log rows
|
|
157
|
+
(incrementing `observations`, refreshing `pattern`/`details`, updating `last_seen`), collect
|
|
158
|
+
all anchor ids and make ONE variadic call:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
node "$HOME/.devflow/scripts/hooks/json-helper.cjs" refresh-anchor <anchor_id1> [<anchor_id2> ...]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
This re-projects all sharpened log rows in a single lock/parse/render pass, propagating
|
|
165
|
+
improvements to `decisions.md`/`pitfalls.md`/`index.md`. BATCH: do not call once per row — N
|
|
166
|
+
calls pay N full-corpus renders; one variadic call pays one. Refresh calls do not consume
|
|
167
|
+
curation slots; however, at most 10 anchors may be refreshed per run — stop if the cap is
|
|
168
|
+
reached.
|
|
169
|
+
|
|
137
170
|
## Part 2 — Curation
|
|
138
171
|
|
|
139
172
|
Periodic housekeeping of the ledger and rendered `.md` files. Bounds: **≤5 curation changes
|
|
140
173
|
per run**. **7-day protection window** — never touch any entry whose `date` field in the
|
|
141
174
|
ledger (`.devflow/learning/decisions-ledger.jsonl`) is within the past 7 days. The window key
|
|
142
|
-
is the ledger row's `date` field (YYYY-MM-DD), not anything in the `.md` file.
|
|
175
|
+
is the ledger row's `date` field (YYYY-MM-DD), not anything in the `.md` file. If the ledger
|
|
176
|
+
row lacks a `date` field (pitfall rows promoted before date-stamping was added), use the
|
|
177
|
+
observation log row's `last_seen` date for the window. If `last_seen` is also unavailable, the
|
|
178
|
+
entry predates date-stamping and is outside the protection window (no backfill: a fabricated date would be worse than an unprotected entry — ADR-022).
|
|
179
|
+
Example: a pitfall row with no ledger `date` whose log row has `last_seen: "2026-08-27"` → window
|
|
180
|
+
key 2026-08-27 (protected if within 7 days of today); no ledger `date` AND no log `last_seen`
|
|
181
|
+
→ outside the window, eligible for curation.
|
|
143
182
|
|
|
144
183
|
Ground yourself first, all by direct reads:
|
|
145
184
|
- Active entries and counts: `decisions.md` / `pitfalls.md` — what is rendered is what is active.
|
|
@@ -148,6 +187,13 @@ Ground yourself first, all by direct reads:
|
|
|
148
187
|
those files still exist (Glob). An entry whose referenced files are gone is a preferred
|
|
149
188
|
retirement candidate — a signal to prefer, not an automatic retirement.
|
|
150
189
|
|
|
190
|
+
**PF-040 pointer-vs-citation gate**: before acting on a missing-path signal (a file cited in
|
|
191
|
+
`details`/`evidence` no longer exists), determine whether the reference is a live POINTER (a
|
|
192
|
+
file a reader should follow today) or a HISTORICAL CITATION (the file the entry recorded
|
|
193
|
+
deleting, replacing, or retiring). A missing live pointer is drift — repair the reference. A
|
|
194
|
+
missing historical citation is confirmation that the decision was implemented — leave the entry
|
|
195
|
+
intact.
|
|
196
|
+
|
|
151
197
|
**Rotate stale observations first** (before selecting curation candidates):
|
|
152
198
|
|
|
153
199
|
```bash
|
|
@@ -180,10 +226,13 @@ node "$HOME/.devflow/scripts/hooks/json-helper.cjs" retire-anchor <anchor_id> <s
|
|
|
180
226
|
|
|
181
227
|
`retire-anchor` is atomic and idempotent. Call it once per entry.
|
|
182
228
|
|
|
183
|
-
**Citation preservation
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
`
|
|
229
|
+
**Citation preservation** (ADR-022 — log is content authority): if an entry being retired
|
|
230
|
+
has inbound `applies ADR-NNN` citations in other entries' `pattern`/`details`, update those
|
|
231
|
+
other entries to reference the surviving entry — do this by editing their **log rows** in
|
|
232
|
+
`decisions-log.jsonl` (one line at a time), then collecting all updated anchor ids and calling
|
|
233
|
+
ONCE: `node "$HOME/.devflow/scripts/hooks/json-helper.cjs" refresh-anchor <anchor_id1> [<anchor_id2> ...]`
|
|
234
|
+
Batch all ids into the single variadic call — one lock/parse/render pass for the whole set.
|
|
235
|
+
Never edit the ledger directly for content changes; the log is the authority.
|
|
187
236
|
|
|
188
237
|
**Cap enforcement**: stop after 5 changes regardless of remaining candidates.
|
|
189
238
|
|
|
@@ -191,8 +240,9 @@ instead — edit those ledger rows directly (one line at a time), then re-render
|
|
|
191
240
|
|
|
192
241
|
1. Run `rotate-observations` if you have not already this run (Part 2 covers it — never run
|
|
193
242
|
it twice).
|
|
194
|
-
2. Delete the claim file as your FINAL act, strictly after every other write (
|
|
195
|
-
|
|
243
|
+
2. Delete the claim file as your FINAL act, strictly after every other write (`rm -f` is
|
|
244
|
+
denied by devflow's recommended deny-list; `unlink` and a flagless `rm` both pass — use
|
|
245
|
+
`unlink` (PF-003)):
|
|
196
246
|
`unlink .devflow/learning/.pending-turns.processing`
|
|
197
247
|
If deletion is denied, finish normally and note the leftover claim file in your summary —
|
|
198
248
|
the next run's stale-merge recovery folds it in.
|
|
@@ -28,10 +28,22 @@ You receive from orchestrator:
|
|
|
28
28
|
|
|
29
29
|
1. **Read context per issue**: For each issue, Read 30 lines around the reported file:line to understand the actual code.
|
|
30
30
|
2. **Apply Decisions**: Scan the DECISIONS_CONTEXT index to identify relevant ADR and PF entries. Read full bodies on demand. Cite `applies ADR-NNN` / `avoids PF-NNN` in your Reasoning column. Skip when DECISIONS_CONTEXT is empty or `(none)`. Use only verbatim IDs from the index — do not fabricate.
|
|
31
|
-
3. **Assign disposition**:
|
|
31
|
+
3. **Assign disposition**: Run the duplicate grouping pre-pass, then apply the blast-radius matrix to each group's primary. Every issue gets exactly one verdict (DUPLICATE included) — none may vanish.
|
|
32
32
|
4. **Document evidence**: FALSE_POSITIVE requires cited grep/file:line. BY_DESIGN requires an ADR or inline comment/doc citation.
|
|
33
33
|
5. **Assign risk tier**: For every FIX_NOW issue, annotate Standard or Careful.
|
|
34
34
|
|
|
35
|
+
## Duplicate Grouping Pre-Pass
|
|
36
|
+
|
|
37
|
+
Run this pre-pass **before** the disposition matrix. It is a relation between issues, not a matrix row.
|
|
38
|
+
|
|
39
|
+
1. **Group by same defect**: cluster issues that share the same root cause — typically the same or adjacent file:line reported by different review foci, or the same logical error in different phrasings.
|
|
40
|
+
2. **Select primary**: from each group, designate as primary the most specific and complete report — but when a group mixes security and non-security findings (a 'security member' is one that would trigger the Security Gate), the security member is always the primary. All other members are non-primary duplicates.
|
|
41
|
+
3. **Security gate applies to the whole group**: if ANY member is a security finding, the group's primary passes through the Security Gate (→ FIX_NOW or ESCALATED only). Never downgrade a group because non-security members outnumber the security finding.
|
|
42
|
+
4. **Non-primary members**: assign verdict **DUPLICATE** with `duplicate_of: <primary-id>`. Never chain — `duplicate_of` must reference a non-DUPLICATE issue. A DUPLICATE inherits its primary's outcome.
|
|
43
|
+
5. **Single-member groups**: if an issue has no duplicates it is its own primary — apply the matrix directly.
|
|
44
|
+
|
|
45
|
+
Apply the disposition matrix to each group's **primary only**.
|
|
46
|
+
|
|
35
47
|
## Blast-Radius Disposition Matrix
|
|
36
48
|
|
|
37
49
|
**First match wins. Apply in the order listed.**
|
|
@@ -117,6 +129,11 @@ Return the verdict ledger grouped by disposition:
|
|
|
117
129
|
|----------|-----------|----------------------|
|
|
118
130
|
| {id} | {file}:{line} | {why requires complete redesign} |
|
|
119
131
|
|
|
132
|
+
### DUPLICATE
|
|
133
|
+
| Issue ID | Duplicate Of | File:Line | Reason |
|
|
134
|
+
|----------|-------------|-----------|--------|
|
|
135
|
+
| {id} | {primary-id} | {file}:{line} | {same defect as {primary-id}, reported by {focus}} |
|
|
136
|
+
|
|
120
137
|
### Summary
|
|
121
138
|
- Total Issues: {n}
|
|
122
139
|
- ESCALATED: {n}
|
|
@@ -125,6 +142,7 @@ Return the verdict ledger grouped by disposition:
|
|
|
125
142
|
- BY_DESIGN: {n}
|
|
126
143
|
- FIX_SEPARATE: {n}
|
|
127
144
|
- TECH_DEBT: {n}
|
|
145
|
+
- DUPLICATE: {n}
|
|
128
146
|
```
|
|
129
147
|
|
|
130
148
|
## Boundaries
|
|
@@ -56,7 +56,7 @@ In multi-worktree mode, spawn all pre-flight agents **in a single message** (par
|
|
|
56
56
|
|
|
57
57
|
**If BLOCKED:** In single-worktree mode, stop and report the blocker to user. If no reviews found, suggest `/code-review` or `/bug-analysis` first. In multi-worktree mode, report the failure but continue with other worktrees.
|
|
58
58
|
|
|
59
|
-
**Extract from response:** `branch`, `branch_slug`, `pr_number`, `review_count`, `diff_files` per worktree.
|
|
59
|
+
**Extract from response:** `branch`, `base_branch`, `branch_slug`, `pr_number`, `review_count`, `diff_files` per worktree.
|
|
60
60
|
|
|
61
61
|
**Fetch PR body** (after extracting `pr_number`):
|
|
62
62
|
```bash
|
|
@@ -138,7 +138,7 @@ Issues are extracted from `\{TARGET_DIR\}` only — never cross-reference review
|
|
|
138
138
|
### Phase 1b: Fetch External Review Threads (Compliance-gated)
|
|
139
139
|
|
|
140
140
|
**Produces:** THREAD_MAP
|
|
141
|
-
**Requires:**
|
|
141
|
+
**Requires:** BRANCH_INFO, COMPLIANCE_SKILL_INSTALLED
|
|
142
142
|
|
|
143
143
|
Skip this phase if `COMPLIANCE_SKILL_INSTALLED` is false.
|
|
144
144
|
|
|
@@ -157,7 +157,7 @@ Parse `THREAD_MAP` from Git agent output. If Git agent returns `TRACEABILITY: DE
|
|
|
157
157
|
### Phase 2: Global Triage
|
|
158
158
|
|
|
159
159
|
**Produces:** TRIAGE_RESULTS
|
|
160
|
-
**Requires:** ISSUES, DIFF_FILES, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, PR_DESCRIPTION
|
|
160
|
+
**Requires:** ISSUES, DIFF_FILES, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, PR_DESCRIPTION
|
|
161
161
|
|
|
162
162
|
Spawn a single global Triage agent for ALL issues:
|
|
163
163
|
|
|
@@ -169,7 +169,7 @@ WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
|
169
169
|
DECISIONS_CONTEXT: {decisions_context}
|
|
170
170
|
FEATURE_KNOWLEDGE: {feature_knowledge}
|
|
171
171
|
PR_DESCRIPTION: <pr-description>{pr_description}</pr-description>
|
|
172
|
-
Triage every issue
|
|
172
|
+
Triage every issue: collapse duplicates first, then apply the blast-radius disposition matrix to each group's primary. Assign exactly one verdict per issue.
|
|
173
173
|
Follow devflow:apply-decisions to Read full ADR/PF bodies on demand.
|
|
174
174
|
Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE."
|
|
175
175
|
```
|
|
@@ -181,11 +181,12 @@ Wait for Triage agent to complete before proceeding. Parse verdict ledger from T
|
|
|
181
181
|
- **BY_DESIGN**: Intentional code (with ADR or code doc citation)
|
|
182
182
|
- **FIX_SEPARATE**: Valid but out of blast-radius scope (must become manage-debt ticket)
|
|
183
183
|
- **TECH_DEBT**: Architectural overhaul only — LAST RESORT
|
|
184
|
+
- **DUPLICATE**: Collapsed duplicate issue — carries `duplicate_of: <primary-id>` referencing the non-DUPLICATE primary; inherits the primary's outcome
|
|
184
185
|
|
|
185
186
|
Collect all decisions citations (ADR-NNN / PF-NNN) from Triage agent Reasoning columns.
|
|
186
187
|
|
|
187
188
|
**Triage agent completeness assertion (avoids PF-002):** Verify the parsed ledger against ISSUES before proceeding:
|
|
188
|
-
1. Every issue `id` from ISSUES must appear in exactly one verdict bucket — none may vanish, none may appear in multiple buckets.
|
|
189
|
+
1. Every issue `id` from ISSUES must appear in exactly one verdict bucket — none may vanish, none may appear in multiple buckets. DUPLICATE is a valid bucket; a valid DUPLICATE entry must name its `duplicate_of` primary (the `Duplicate Of` column of the ledger's DUPLICATE table) and that primary must be a non-DUPLICATE issue id. A missing `duplicate_of` or one that chains to another DUPLICATE is a **Triage agent failure** (retry-then-abort as below).
|
|
189
190
|
2. If the Triage agent output is empty, contains a skill re-entrancy guard string (e.g., contains `already running`), or is missing any issue IDs from ISSUES: treat as a **Triage agent failure**:
|
|
190
191
|
- Retry the Triage agent once with the same inputs.
|
|
191
192
|
- If the retry also fails the completeness check: abort with a clear error message listing the missing issue IDs and failure reason — never proceed with dropped issues.
|
|
@@ -199,7 +200,7 @@ Collect all decisions citations (ADR-NNN / PF-NNN) from Triage agent Reasoning c
|
|
|
199
200
|
|
|
200
201
|
If FIX_NOW list is empty: skip to Phase 5 — write full summary (Phase 5), run manage-debt (Phase 9) if FIX_SEPARATE/TECH_DEBT exist, run thread resolution + resolution comment (Phase 9b), run merge readiness (Phase 9c), display results (Phase 10).
|
|
201
202
|
|
|
202
|
-
Otherwise, batch FIX_NOW issues for Code agent execution:
|
|
203
|
+
Otherwise, batch FIX_NOW issues for Code agent execution. **DUPLICATE issues are never dispatched** — they inherit the primary's outcome:
|
|
203
204
|
- **Same-file issues** → one batch (one Code agent per file, sequential for same-file pairs)
|
|
204
205
|
- **Distinct-file issues** → parallel Code agents
|
|
205
206
|
- **Max 5 issues per batch** — chunk large sets
|
|
@@ -207,7 +208,7 @@ Otherwise, batch FIX_NOW issues for Code agent execution:
|
|
|
207
208
|
### Phase 4: Fix (Code agent × N)
|
|
208
209
|
|
|
209
210
|
**Produces:** CODE_AGENT_RESULTS
|
|
210
|
-
**Requires:** BATCHES, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
|
|
211
|
+
**Requires:** BATCHES, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
|
|
211
212
|
|
|
212
213
|
For each batch, spawn Code agent with `OPERATION: issue-fix` and `PUSH: false`:
|
|
213
214
|
|
|
@@ -236,12 +237,14 @@ Collect from each Code agent:
|
|
|
236
237
|
### Phase 5: Write resolution-summary.md
|
|
237
238
|
|
|
238
239
|
**Produces:** RESOLUTION_FILE (early write for compaction safety)
|
|
239
|
-
**Requires:** TRIAGE_RESULTS, CODE_AGENT_RESULTS
|
|
240
|
+
**Requires:** TRIAGE_RESULTS, CODE_AGENT_RESULTS, TARGET_DIR, BRANCH_INFO
|
|
240
241
|
|
|
241
242
|
**Immediately write `resolution-summary.md`** to `\{TARGET_DIR\}` using the Write tool. Do this now — not in Phase 9 — while results are fresh in context. This ensures the record is persisted even if later phases (Simplify, Verification Gate, CI gate, Tech Debt) trigger context compaction.
|
|
242
243
|
|
|
243
244
|
Set `Tracked` for FIX_SEPARATE and TECH_DEBT items to `(pending)` — to be backfilled after Phase 9 manage-debt.
|
|
244
245
|
|
|
246
|
+
DUPLICATE issues are listed **only** in `## Duplicates` — never in `## Fixed Issues`, `## False Positives`, `## By Design`, `## Fix Separately`, `## Deferred to Tech Debt`, `## Escalations`, or `## Blocked`. A duplicate of a FALSE_POSITIVE primary therefore leaves only the primary in the `False Positive` row and the `## False Positives` section; the same holds for every other outcome the duplicate inherits.
|
|
247
|
+
|
|
245
248
|
Use the template from the Output Artifact section below.
|
|
246
249
|
|
|
247
250
|
### Phase 6: Simplify
|
|
@@ -334,7 +337,7 @@ Otherwise, for each worktree with fixes:
|
|
|
334
337
|
|
|
335
338
|
**IMPORTANT**: Run sequentially across all worktrees (not in parallel) to avoid GitHub API conflicts.
|
|
336
339
|
|
|
337
|
-
If any issues are FIX_SEPARATE or TECH_DEBT, spawn Git agent:
|
|
340
|
+
If any issues are FIX_SEPARATE or TECH_DEBT, spawn Git agent. **DUPLICATE issues never create their own debt tickets** — a duplicate of a deferred primary is covered by the primary's ticket:
|
|
338
341
|
|
|
339
342
|
```
|
|
340
343
|
Agent(subagent_type="Git"):
|
|
@@ -359,6 +362,7 @@ Skip this step if `COMPLIANCE_SKILL_INSTALLED` is false or THREAD_MAP is empty.
|
|
|
359
362
|
|
|
360
363
|
Prepare THREAD_MAP with verdicts from triage/code agent results:
|
|
361
364
|
- For each `ext-\{N\}`: match to an issue verdict (FIXED, FALSE_POSITIVE, BY_DESIGN, ESCALATED) by `file:line` correlation
|
|
365
|
+
- If the matched issue has verdict DUPLICATE, use the **primary's** verdict and verification status for the reply — do not expose DUPLICATE to the thread author (avoids PF-024; caller-side mapping — git.md contracts unchanged)
|
|
362
366
|
- Include `commit_sha` from Code agent results for FIXED verdicts
|
|
363
367
|
- Unmatched threads: ESCALATED (human review)
|
|
364
368
|
|
|
@@ -399,7 +403,7 @@ Update `## Third-Party Threads` section in resolution-summary.md with thread res
|
|
|
399
403
|
### Phase 9c: Merge Readiness (Compliance-gated, Report-only)
|
|
400
404
|
|
|
401
405
|
**Produces:** MERGE_READINESS_REPORT
|
|
402
|
-
**Requires:**
|
|
406
|
+
**Requires:** BRANCH_INFO, COMPLIANCE_SKILL_INSTALLED
|
|
403
407
|
|
|
404
408
|
Skip this phase if `COMPLIANCE_SKILL_INSTALLED` is false.
|
|
405
409
|
|
|
@@ -418,7 +422,7 @@ If Git agent returns `TRACEABILITY: DEGRADED`: warn, proceed to Phase 10.
|
|
|
418
422
|
|
|
419
423
|
### Phase 10: Report
|
|
420
424
|
|
|
421
|
-
**Requires:** TARGET_DIR
|
|
425
|
+
**Requires:** BRANCH_INFO, TARGET_DIR
|
|
422
426
|
|
|
423
427
|
The resolution summary was already written to `\{TARGET_DIR\}/resolution-summary.md` in Phase 5 (updated by Phase 7 and Phase 9). Display results to the user:
|
|
424
428
|
|
|
@@ -438,6 +442,7 @@ The resolution summary was already written to `\{TARGET_DIR\}/resolution-summary
|
|
|
438
442
|
| Deferred | {n} |
|
|
439
443
|
| Blocked | {n} |
|
|
440
444
|
| Escalated | {n} |
|
|
445
|
+
| Duplicates Collapsed | {n} |
|
|
441
446
|
|
|
442
447
|
### Verification
|
|
443
448
|
Final gate: {PASS | FAILED after N attempts}
|
|
@@ -483,9 +488,9 @@ In multi-worktree mode, report results per worktree with aggregate summary.
|
|
|
483
488
|
│ └─ Git agent (fetch-review-threads) → THREAD_MAP
|
|
484
489
|
│
|
|
485
490
|
├─ Phase 2: Global Triage [Triage agent, opus, single agent]
|
|
486
|
-
│ └─ ALL issues → verdict ledger by disposition
|
|
491
|
+
│ └─ ALL issues → verdict ledger by disposition (incl. DUPLICATE with duplicate_of)
|
|
487
492
|
│
|
|
488
|
-
├─ Phase 3: Batch FIX_NOW issues (skip if empty)
|
|
493
|
+
├─ Phase 3: Batch FIX_NOW issues (skip if empty; DUPLICATE issues never dispatched)
|
|
489
494
|
│ └─ same-file sequential, distinct-file parallel, max 5/batch
|
|
490
495
|
│
|
|
491
496
|
├─ Phase 4: Fix [Code agent × N, OPERATION: issue-fix, PUSH: false]
|
|
@@ -528,6 +533,8 @@ In multi-worktree mode, report results per worktree with aggregate summary.
|
|
|
528
533
|
| Worktree pre-flight fails | Report failure, continue with other worktrees |
|
|
529
534
|
| Empty FIX_NOW list | Skip Phases 3-4/6-8; still write full summary + run manage-debt if FIX_SEPARATE/TECH_DEBT exist |
|
|
530
535
|
| ESCALATED security issues | Surfaced in ## Escalations + display callout; never routed to manage-debt |
|
|
536
|
+
| DUPLICATE verdict without duplicate_of, or chained to another DUPLICATE | Treated as Triage failure — same retry-then-abort as a vanished id |
|
|
537
|
+
| DUPLICATE issues in THREAD_MAP | Map ext-\{N\} to primary's verdict/verification status for thread reply |
|
|
531
538
|
| Verification Gate FAILED after 2 attempts | Recorded as FAILED in ## Verification + blocking callout; CI gate skipped; proceed to Phase 9 (manage-debt) then Phase 10 (display) |
|
|
532
539
|
| gh/GitHub absent | manage-debt fails gracefully; Tracked stays "(pending)" + noted — recorded, not dropped |
|
|
533
540
|
| COMPLIANCE_SKILL_INSTALLED false | Phases 1b, 9b-step-1, and 9c are skipped; post-resolution-summary (Phase 9b step 2) still runs if a PR is known |
|
|
@@ -556,7 +563,7 @@ Written in Phase 5 (Collect Results) to `\{TARGET_DIR\}/resolution-summary.md`:
|
|
|
556
563
|
```markdown
|
|
557
564
|
# Resolution Summary
|
|
558
565
|
|
|
559
|
-
**Branch**: {branch} -> {
|
|
566
|
+
**Branch**: {branch} -> {base_branch}
|
|
560
567
|
**Date**: {timestamp}
|
|
561
568
|
**Review**: {TARGET_DIR}
|
|
562
569
|
**Command**: /resolve
|
|
@@ -578,8 +585,9 @@ Written in Phase 5 (Collect Results) to `\{TARGET_DIR\}/resolution-summary.md`:
|
|
|
578
585
|
| Deferred | {n} |
|
|
579
586
|
| Blocked | {n} |
|
|
580
587
|
| Escalated | {n} |
|
|
588
|
+
| Duplicates Collapsed | {n} |
|
|
581
589
|
|
|
582
|
-
_(Note: `Deferred` = `## Fix Separately` count + `## Deferred to Tech Debt` count combined — the two sections are distinct by scope, but the Statistics row aggregates both for the convergence parser.)_
|
|
590
|
+
_(Note: `Deferred` = `## Fix Separately` count + `## Deferred to Tech Debt` count combined — the two sections are distinct by scope, but the Statistics row aggregates both for the convergence parser. `Total Issues` counts every triaged issue including collapsed duplicates; every row **between** `Total Issues` and `Duplicates Collapsed` counts UNIQUE (non-DUPLICATE) issues only, so `Total Issues` equals the sum of the rows below it. Excluding duplicates from `Fixed`, `False Positive`, and `Deferred` de-skews the fp\_ratio convergence formula in code-review without any parser change.)_
|
|
583
591
|
|
|
584
592
|
## Verification
|
|
585
593
|
| Command | Result |
|
|
@@ -625,6 +633,11 @@ Final gate: PASS | FAILED after {n} attempts
|
|
|
625
633
|
|-------|-----------|---------|
|
|
626
634
|
| {description} | {file}:{line} | {why} |
|
|
627
635
|
|
|
636
|
+
## Duplicates
|
|
637
|
+
| Issue | Duplicate Of | File:Line |
|
|
638
|
+
|-------|-------------|-----------|
|
|
639
|
+
| {description} | {primary-id} | {file}:{line} |
|
|
640
|
+
|
|
628
641
|
## Third-Party Threads
|
|
629
642
|
| Thread | File:Line | Verdict | Status |
|
|
630
643
|
|--------|-----------|---------|--------|
|
|
@@ -633,4 +646,4 @@ Final gate: PASS | FAILED after {n} attempts
|
|
|
633
646
|
|
|
634
647
|
_(Omit `## Third-Party Threads` if `COMPLIANCE_SKILL_INSTALLED` is false or no external threads were found.)_
|
|
635
648
|
|
|
636
|
-
**Statistics mapping (parser contract)**: the `Deferred` row = FIX_SEPARATE + TECH_DEBT (both deferral dispositions combined); By Design and Escalated are counted separately and excluded from `Deferred`. The `/code-review` convergence parser reads
|
|
649
|
+
**Statistics mapping (parser contract)**: the `Deferred` row = FIX_SEPARATE + TECH_DEBT (both deferral dispositions combined); By Design and Escalated are counted separately and excluded from `Deferred`. The `Duplicates Collapsed` row is additive — the `/code-review` convergence parser reads only `Deferred`, `Fixed`, and `False Positive` rows plus `## Fixed Issues` / `## False Positives` headings — keep those labels byte-stable. All rows that the parser reads count UNIQUE (non-DUPLICATE) issues only, so collapsed duplicates do not inflate fp\_ratio.
|