@dzhechkov/skills-feature-adr 1.3.57 β†’ 1.3.59

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/README.md CHANGED
@@ -471,6 +471,38 @@ Step 3 and Step 8 share an ADR best-practices contract distilled from the
471
471
  The pipeline **dog-foods** this: a harness test runs the gate against feature-adr's own generated ADR, so a
472
472
  Step-3↔Step-8 drift fails CI rather than shipping.
473
473
 
474
+ ### Amendments are mini-ADRs + the 🚦 Gates line (v1.3.58)
475
+
476
+ Three additions derived from a real post-release incident analysis (a pipeline shipped slices whose defects
477
+ only a *full* post-push review caught), organized by one principle β€” the **cost-of-detection ladder**: every
478
+ check lives on the cheapest layer that reliably holds it (deterministic test > always-loaded file > pipeline
479
+ gate > reviewer judgment > memory). A miss usually means a check lived one layer too weak.
480
+
481
+ - **Amendment Confirmation discipline.** Corrections folded into a run (a Step-3.5 CONDITIONAL condition, a
482
+ challenge-panel confirmed finding, a user checkpoint steer) were historically the least-tested part of the
483
+ pipeline β€” prose deltas with no proving test. Now every amendment is a **mini-ADR** in a `## Amendments`
484
+ section with a fixed, lintable shape:
485
+ ```
486
+ AM-N (qcsd|challenge-panel|user-steer): <change>. Confirmation: <property> β†’ test `test_name` (fails if reverted).
487
+ ```
488
+ Step 8 verifies each named test **exists** and is **non-vacuous** β€” amendment tests join the ADR property
489
+ test in the same `dz discrimination-check` run (a test that stays green at pre-feature base proves
490
+ nothing). A *safeguard* amendment needs a test proving it actually **fires** on a real input, not just
491
+ that its code path exists. No `## Amendments` section β‡’ the gate skips silently (zero cost).
492
+ - **The `🚦 Gates:` line.** Every checkpoint banner (and the workflow's return objects) carries a gate map
493
+ **derived from machine state** β€” artifact existence, JSON verdicts, test results β€” never from what the
494
+ orchestrator remembers. `βœ“` passed Β· `βœ—` failed Β· `not-run` pending Β· `β€”` N/A. The line doesn't make a
495
+ gate run; it makes NOT running one loud.
496
+ - **I/O-on-pure-path rule.** A change that adds I/O (DB/network/file) to a previously-pure path β€” above all
497
+ startup/lifespan/health β€” must carry a **negative resource-down test** (broken resource β†’ the declared
498
+ degradation contract: fail-open for advisory, fail-fast for load-bearing), and Step 8 hunts the
499
+ **fixture-swap smell**: replacing a broken fixture with a healthy one silently deletes the negative
500
+ control that proved the path was I/O-free. The bundled role-default skills gained the matching entries
501
+ (`code-impl` P25, `code-critic` AP14).
502
+
503
+ Both forms carry all of it: the interactive skill (step modules + banner template) and the deterministic
504
+ workflow (stage prompts + derived `gates` in its returns) β€” same shapes, same vocabulary.
505
+
474
506
  ### The `Model` / `Fable?` columns β€” read this before swapping models
475
507
 
476
508
  The `Model` column is the **default recommendation, fully overridable** β€” the routing rule is
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dzhechkov/skills-feature-adr",
3
- "version": "1.3.57",
3
+ "version": "1.3.59",
4
4
  "description": "Adaptive Feature Development skill pack for Claude Code β€” 11-step pipeline with Complexity Router (S/M/L/XL), ADR-driven architecture, 15 agentic-qe skills, multi-agent fleet QE. Supports --full-qe, --full-qe-extended, --with-learning, and --knowledge-extractor modes.",
5
5
  "bin": {
6
6
  "skills-feature-adr": "./bin/cli.js"
@@ -83,3 +83,31 @@ After completion:
83
83
  - Code changes live in the actual codebase (not just in `features/`)
84
84
  - `features/<slug>/` contains the design artifacts (ADRs, diagrams, reports)
85
85
  - These artifacts serve as documentation for the feature
86
+ ## The cost-of-detection ladder (place every check on its cheapest reliable layer)
87
+
88
+ For every quality check the pipeline performs, put it on the **strongest layer that can express it**
89
+ (strong = cheap to run, deterministic, silent-proof). A miss almost always means a check lived one layer
90
+ too weak for its nature:
91
+
92
+ ```
93
+ STRONGEST (cheap, catches 100%, no model needed)
94
+ 1. CI / deterministic test wc -l cap, sha256 pin, grep-guard, dz guard rule
95
+ 2. always-loaded role file architecture/*.md, project-critic β€” read EVERY run
96
+ 3. pipeline step gate Step-8 QE, claim-check, discrimination-check, amendment gate
97
+ 4. skill judgment "the reviewer will notice" β€” runs if invoked well
98
+ 5. agent memory / vibes "I should remember to…" β€” runs if recalled
99
+ WEAKEST (probabilistic, model-dependent, silent when it lapses)
100
+ ```
101
+
102
+ Design rule when adding ANY new check:
103
+ - Deterministic (size, presence, absence, format) β†’ a **repo test / dz guard rule** (layer 1).
104
+ - Structural-but-contextual (a named property must have a proving test) β†’ a **step gate** with a
105
+ machine-checkable output (layer 3) β€” e.g. the ADR Confirmation link, the amendment gate,
106
+ `dz discrimination-check`.
107
+ - Semantic/adversarial (honesty, product-fit, exploitability) β†’ a **review plane run by an independent
108
+ model** (layer 3, model-backed) β€” e.g. cross-model QE, challenge-panel. Never leave it to layer-4.
109
+
110
+ Anti-pattern: "the critic/QE agent will catch it" for anything a 5-line test could catch. Every such push
111
+ from layer 1 up to layer 4 turns a deterministic guarantee into a probabilistic one β€” a future silent miss.
112
+ (Origin: fa-improvements 2026-07-18 β€” a 700-line cap enforced by reviewer judgment caught one file and
113
+ missed its sibling in the same merge request; `wc -l` catches both, always.)
@@ -723,6 +723,33 @@ rollback semantics are lost; recovery becomes case-by-case repair.
723
723
  operation, not inside its parts. If parts must commit separately,
724
724
  name why and ensure each is independently retryable."
725
725
 
726
+ ### AP14. I/O added to a previously-pure path without a negative resource-down test (HIGH)
727
+
728
+ **Principle:** a change that introduces I/O (DB, network, file) into a
729
+ previously I/O-free path β€” especially startup/lifespan/health β€” must
730
+ carry a negative resource-down test proving the declared degradation
731
+ contract (fail-open for advisory, explicit fail-fast for load-bearing),
732
+ not only a happy-path test.
733
+
734
+ **Detection cue:** the code diff adds a DB/network/file call to a
735
+ module that previously imported no I/O; the TEST diff replaces a
736
+ broken/unbound fixture with a healthy one (fixture-swap β€” the old
737
+ fixture was likely a negative control) with no compensating
738
+ resource-down test; a new I/O call in a startup path has no
739
+ try/except and no test with a dead resource handle.
740
+
741
+ **FP exception:** the path already performed I/O (the change only adds
742
+ another call of the same kind); the new call is wrapped and a negative
743
+ test exists elsewhere covering the same contract (name it).
744
+
745
+ **Why bad:** a resource outage takes down the whole path β€” including
746
+ health checks β€” for the sake of the new feature; healthy test fixtures
747
+ hide exactly this case, so it surfaces first in production.
748
+
749
+ **Suggestion direction:** "Keep both tests: healthy fixture (new
750
+ behavior) + broken fixture (degradation contract). State the contract:
751
+ fail-open or fail-fast β€” and prove it with a dead resource handle."
752
+
726
753
  ---
727
754
 
728
755
  ## Section E. Type / contract issues
@@ -583,6 +583,23 @@ boundary (validator + retry, normalizer) β€” not a fourth, sterner
583
583
  prompt. Models also send `null` where the schema says `"none"` β€”
584
584
  tolerate real model behavior at the parsing boundary.
585
585
 
586
+ ### P25. I/O added to a previously-pure path needs a negative resource-down test
587
+
588
+ If your change introduces I/O (DB, network, file) into a path that was
589
+ previously I/O-free β€” above all a startup, lifespan, or health path β€”
590
+ the happy-path test is not enough. Also write the NEGATIVE test: a
591
+ broken/unbound resource handle β†’ the path degrades per its declared
592
+ contract (fail-open for an advisory feature, explicit fail-fast for a
593
+ load-bearing one). Otherwise an outage of that resource takes down the
594
+ whole path β€” including health checks β€” for the sake of an advisory
595
+ feature, and healthy fixtures will hide it until production.
596
+
597
+ Corollary β€” the fixture-swap smell: if making new code pass required
598
+ replacing a "broken" test fixture with a healthy one, stop. The old
599
+ fixture was probably a negative control proving the path was I/O-free.
600
+ Keep BOTH tests (healthy = new behavior, broken = degradation
601
+ contract); never silently delete the case that proved the old property.
602
+
586
603
  ---
587
604
 
588
605
  ## Section 7. Decision discipline
@@ -589,6 +589,7 @@ npx @dzhechkov/skills-feature-adr init --with-learning --knowledge-extractor
589
589
  <promise>[PROMISE_TAG]</promise>
590
590
  Tier: {COMPLEXITY_TIER} | Active Steps: {ACTIVE_STEPS}
591
591
  πŸŽ“ Learning: {recalled} patterns recalled for this feature, {stored} new stored this run
592
+ 🚦 Gates: challenge-panel βœ“ Β· claim-check βœ“ Β· discrimination not-run Β· amendments βœ“ Β· fleet β€”
592
593
 
593
594
  [2-3 line summary]
594
595
  Artifacts: [list] βœ…
@@ -598,3 +599,16 @@ Artifacts: [list] βœ…
598
599
  β€’ "[feedback]" β€” adjust
599
600
  ═══════════════════════════════════════════════════════
600
601
  ```
602
+
603
+ ### The 🚦 Gates line (mandatory, DERIVED β€” never asserted from memory)
604
+
605
+ Every checkpoint banner carries a `🚦 Gates:` line listing each gate relevant to the run so far. Symbols:
606
+ `βœ“` ran and passed Β· `βœ—` ran and failed Β· `not-run` pending Β· `β€”` N/A for this tier/slice (say why once).
607
+ Each value is **derived from machine-checkable state** β€” an artifact's existence, a command's JSON verdict, a
608
+ test result β€” never from what the orchestrator remembers doing. The line does not make a gate run; it makes
609
+ NOT running one loud: a skipped gate shows as `not-run` by construction instead of being silently forgotten
610
+ (cost-of-detection ladder: the banner is the one surface emitted at EVERY step boundary, so strapping the
611
+ checklist to it is the cheapest way to harden orchestrator judgment). Gate sources: challenge-panel β†’ its
612
+ verdict exists; claim-check β†’ its JSON counts (`high-findings` vs `clean`); discrimination β†’ the
613
+ `dz discrimination-check` aggregate; amendments β†’ every `AM-N` row carries its `β†’ test` and it was checked;
614
+ fleet β†’ the 09 artifact (L/XL only, else `β€”`).
@@ -119,7 +119,8 @@ After all agents complete, apply decision logic:
119
119
  | Critical Risks | > 2 | 1-2 | 0 |
120
120
 
121
121
  - **NO-GO**: BLOCK. Requirements/ADR need rework. Return to Step 1 or Step 3.
122
- - **CONDITIONAL**: Proceed with warnings. Pass findings to Steps 6-8 as advisory context.
122
+ - **CONDITIONAL**: Proceed with warnings. Each condition becomes an **amendment row** in a `## Amendments`
123
+ section (see below) β€” not loose advisory prose.
123
124
  - **GO**: Full confidence. Proceed to Step 6.
124
125
 
125
126
  ### 5. Synthesis Report
@@ -132,6 +133,26 @@ Generate consolidated `03.5_ideation_report.md` with:
132
133
  5. Test ideas (categorized: unit / integration / E2E)
133
134
  6. Conditional agent findings (if any)
134
135
  7. Recommendations prioritized by risk Γ— impact
136
+ 8. `## Amendments` β€” on a CONDITIONAL verdict, every condition as a fixed-shape row (see below)
137
+
138
+ ### Amendment Confirmation discipline (every amendment is a mini-ADR)
139
+
140
+ Amendments are where the sharpest design corrections land β€” and, historically, the least-tested part of a
141
+ run: they arrive as prose AFTER the ADR's Confirmation discipline already ran, so a coder can implement one
142
+ with no test proving it works. Therefore every amendment carries a one-line **Confirmation**, in a fixed,
143
+ machine-checkable shape:
144
+
145
+ ```
146
+ AM-N (source): <change>. Confirmation: <property> β†’ test `test_name` (fails if reverted).
147
+ ```
148
+
149
+ - `source` names where it came from (qcsd | challenge-panel | user-steer).
150
+ - The named test must FAIL if the amendment were reverted/broken (non-vacuous β€” Step 8 verifies via
151
+ `dz discrimination-check`).
152
+ - For a **safeguard** amendment (a warning/guard/fallback): the test must prove the safeguard actually
153
+ **TRIGGERS on a real input** β€” not merely that its code path exists. A structurally-dead safeguard passes
154
+ an existence test and never fires in production.
155
+ - A cheap lint holds the shape: every `AM-N` line must contain a `β†’ test ` token naming a test that exists.
135
156
 
136
157
  ## Output
137
158
 
@@ -149,6 +149,11 @@ Create `features/<slug>/06_implementation_plan.md` with:
149
149
  - Parallel groups
150
150
  - Checkpoint schedule
151
151
  - Risk assessment (L/XL)
152
+ - `## Amendments` β€” every correction folded into this plan (a Step-3.5 CONDITIONAL condition, a
153
+ challenge-panel confirmed finding, a user checkpoint steer) as a fixed-shape row:
154
+ `AM-N (source): <change>. Confirmation: <property> β†’ test `test_name` (fails if reverted).`
155
+ A safeguard amendment's named test must prove it TRIGGERS on a real input, not merely that its code
156
+ path exists. Step 8 verifies every named test exists and is non-vacuous (`dz discrimination-check`).
152
157
 
153
158
  Set `{IMPL_PLAN}` variable.
154
159
 
@@ -31,6 +31,24 @@ Before writing any code:
31
31
  - [ ] Identify import patterns and module structure
32
32
  - [ ] Identify error handling patterns
33
33
  - [ ] Identify test patterns
34
+ - [ ] Plan carries `## Amendments`? β†’ implement every AM-N row AND its named Confirmation test (a
35
+ safeguard amendment needs a test proving it FIRES on a real input)
36
+ - [ ] Does the diff add I/O (DB/network/file) to a previously-pure path β€” especially
37
+ startup/lifespan/health? β†’ name the NEGATIVE resource-down test, or justify N/A
38
+
39
+ ### The I/O-on-pure-path rule (and the fixture-swap smell)
40
+
41
+ If a change introduces I/O into a path that was previously I/O-free β€” above all a startup, lifespan, or
42
+ health path β€” the happy-path test is NOT enough. Also write a **negative resource-down test**: a
43
+ broken/unbound resource handle (dead DB, missing table, exhausted pool) β†’ the path degrades per its
44
+ declared contract β€” **fail-open** for an advisory feature, **explicit fail-fast** for a load-bearing one.
45
+ Without it, an outage of the resource takes down the whole path (including health checks) for the sake of
46
+ an advisory feature β€” and healthy test fixtures will hide it.
47
+
48
+ **Fixture-swap smell:** if making the new code pass required replacing a "broken" test fixture with a
49
+ healthy one β€” stop. The old fixture was probably a negative control proving the path was I/O-free. Keep
50
+ BOTH tests: the healthy one (new behavior) and the broken one (degradation contract). Never silently
51
+ delete the case that proved the old property.
34
52
 
35
53
  ### 2. Execute Tasks per Plan
36
54
 
@@ -158,6 +158,30 @@ Reject explainer-masquerading-as-ADR: if the document describes a problem space
158
158
 
159
159
  The Confirmation-to-test link is load-bearing. If absent, grade no better than C and record a blocker gap; for architecture dependency/layering/interface rules, recommend an ArchUnit or ArchUnitTS fitness function.
160
160
 
161
+ ### 3b. Amendment Gate (P2 β€” amendments inherit the Confirmation discipline)
162
+
163
+ Read the `## Amendments` sections of `03.5_ideation_report.md` and `06_implementation_plan.md` (skip
164
+ silently if absent). For EVERY `AM-N` row verify:
165
+ 1. the row contains a `β†’ test ` token naming a real test (the fixed shape);
166
+ 2. the named test **exists** in the suite;
167
+ 3. it is **non-vacuous** β€” include the amendment test files in the SAME
168
+ `dz discrimination-check --test <f1,f2,...> --base HEAD --json` run as the ADR property test. An
169
+ amendment test that stays green at pre-feature base proves nothing about its amendment;
170
+ 4. a **safeguard** amendment's test proves the safeguard FIRES on a real input (a structurally-dead
171
+ safeguard passes an existence test and never fires in production).
172
+
173
+ A missing, unnamed, or vacuous amendment test is a HIGH gap. This closes the distance between "we caught
174
+ the design flaw" (challenge-panel/QCSD) and "we proved the fix works".
175
+
176
+ ### 3c. I/O-on-pure-path + fixture-swap hunt (P5)
177
+
178
+ In the TEST diff, hunt for replacements of broken/unbound fixtures with healthy ones β€” the old fixture was
179
+ probably a **negative control** proving a path was I/O-free; each such swap requires a compensating
180
+ negative resource-down test. In the CODE diff, hunt for new I/O (DB/network/file) on previously-pure
181
+ paths β€” especially startup/lifespan/health: require a negative resource-down test (broken resource β†’ the
182
+ path degrades per its declared contract: fail-open for advisory, explicit fail-fast for load-bearing).
183
+ Missing β†’ HIGH gap.
184
+
161
185
  ### 4. Multi-Agent Review Panel (L/XL)
162
186
 
163
187
  For L/XL features, spawn 3 parallel review agents using brutal-honesty modes:
@@ -560,6 +560,14 @@ const ADR_FITNESS_CHECKLIST = 'ADR fitness checklist for Step 8: read every ' +
560
560
  // an auto-abort (dz's rule: a false gate kills trust). Byte-inlined guidance; the safe worktree/run lives in `dz
561
561
  // discrimination-check` (harness-core/src/discrimination-gate.ts).
562
562
  const DISCRIMINATION_GATE = 'Β§42 TEST-DISCRIMINATION GATE (run right after asserting the property has a test): the ADR Confirmation names `Required automated check: <test file>` for the load-bearing property. Prove that test DISCRIMINATES, not just that it is green β€” via Bash run EXACTLY `dz discrimination-check --test <that test file> --base HEAD --json` (the Step-7 feature diff is UNCOMMITTED, so HEAD is the pre-feature base). It runs the property test in an isolated git worktree at HEAD (no feature diff) and reports {aggregate, finding}. Parse it: `NON_DISCRIMINATING` = the test PASSES even without the fix (a false green that would stay green if the property regressed) β†’ record a HIGH gap "property test does not discriminate: <file>" but do NOT drop the grade to a blocker on that alone (advisory β€” the owner decides). `DISCRIMINATES` (red by assertion) and `DISCRIMINATES_VIA_ERROR` (could not load at base β€” inferred, note it) both PASS. `CANNOT_ISOLATE` folds into the existing "property untested" finding. Record the verdict in the 08_qe_report.md ADR Fitness section. If `dz discrimination-check` is unavailable, note it and continue β€” never block on the tool.'
563
+ // P2 (amendment-confirmation-discipline, fa-improvements 2026-07-18): amendments are where the SHARPEST design
564
+ // corrections land (challenge-panel/QCSD) and were the least-tested β€” prose deltas with no proving test. Every
565
+ // amendment is a mini-ADR: it carries a one-line Confirmation naming the test that falsifies it. Machine-checkable
566
+ // shape (a linter can assert the `β†’ test ` token); Step-8 verifies existence + non-vacuity via the SAME
567
+ // dz discrimination-check that guards the ADR property (cost-of-detection ladder: judgment β†’ step gate).
568
+ const AMENDMENT_RULE = 'AMENDMENT CONFIRMATION DISCIPLINE (every amendment is a mini-ADR): whenever a correction/amendment is folded in (a QCSD CONDITIONAL condition, a challenge-panel confirmed finding, or a user checkpoint steer), record it in a `## Amendments` section as a fixed-shape row: `AM-N (source): <change>. Confirmation: <property> β†’ test `test_name` (fails if reverted).` β€” naming the test that would FAIL if the amendment were reverted/broken. For a SAFEGUARD amendment (a warning/guard/fallback), the named test must prove the safeguard actually TRIGGERS on a real input β€” not merely that its code path exists (a structurally-dead safeguard passes an existence test and never fires in production).'
569
+ const AMENDMENT_GATE = 'AMENDMENT GATE (P2): read the `## Amendments` sections of ' + FDIR + '/03.5_ideation_report.md and ' + FDIR + '/06_implementation_plan.md (skip silently if absent). EVERY `AM-N` row must contain a `β†’ test ` token naming a real test. Verify: (a) the named test EXISTS in the suite; (b) it is NON-VACUOUS β€” include the amendment test files in the SAME `dz discrimination-check --test <f1,f2,...> --base HEAD --json` run as the ADR property test (an amendment test that stays green at pre-feature base proves nothing); (c) a safeguard amendment\'s test proves the safeguard FIRES on a real input. A missing, unnamed, or vacuous amendment test is a HIGH gap. ' +
570
+ 'IO-ON-PURE-PATH + FIXTURE-SWAP HUNT (P5): in the test diff, hunt for replacements of broken/unbound fixtures with healthy ones β€” the old fixture was probably a NEGATIVE CONTROL proving a path was I/O-free; each such swap requires a compensating negative resource-down test. If the code diff adds I/O (DB/network/file) to a previously-pure path β€” especially startup/lifespan/health β€” require a negative resource-down test (broken/unbound resource β†’ the path degrades per its declared contract: fail-open for advisory, explicit fail-fast for load-bearing). Missing β†’ HIGH gap.'
563
571
 
564
572
  // Step 0: Router + MANDATORY self-learning recall
565
573
  phase('Router')
@@ -656,7 +664,7 @@ modelsUsed.ddd = modelLabel(archOpts)
656
664
  designThunks.push(() => designStage('Step 1 (Requirements)' + (isLplus ? ' + Step 2 (Research)' : '') + ' of /feature-adr for "' + DESC + '" (tier ' + tier + ', slug ' + SLUG + '). Code: ' + CODE_HINT + '. APPLY these Step-0 recalled LEARNED PATTERNS (fold the applicable ones into requirements/constraints - the loop paying off): ' + LEARNED + '. Write ' + FDIR + '/01_requirements.md (functional + non-functional requirements, acceptance criteria, constraints, and an "Applied learned patterns" note).' + reqExtra + ' Return wrote[] + a 1-line summary.' + PS_GUIDANCE('design'), reqOpts, FDIR + '/01_requirements.md', 'requirements'))
657
665
  if (isMplus) {
658
666
  designThunks.push(() => designStage('Step 3 (ADR + shift-left testability) of /feature-adr for "' + DESC + '" (' + SLUG + '). READ the actual code (' + CODE_HINT + ') to ground it. ' + ADR_TEMPLATE_GUIDE + ' Write ' + FDIR + '/03_adr/001-' + SLUG + '.md as a MADR-structured ADR that PASSES the Step-8 ADR fitness checklist (do NOT emit the legacy shape). Emit ALL of these sections, in order: a decision-shaped # Title (present-tense imperative verb β€” the auto-filename tracks the feature slug, so the IMPERATIVE signal lives in the title); ## Status (proposed/accepted/rejected/deprecated/superseded + a reversibility/revisit clause); ## Context (neutral, problem-first, BEFORE the Decision); ## Decision Drivers (ranked/weighted D1, D2, …); ## Considered Options (frame the CHOSEN approach as one option ALONGSIDE the rejected ones, each with symmetric Pros:/Cons:); ## Decision (concrete/testable β€” exact names, versions, paths, commands); ## Rationale (map each point to a driver Dn + why the losers lost); ## Consequences (Positive + Negative/Accepted Downsides + Follow-up ADRs + After-action Review with owner + date); a REQUIRED ## Confirmation stanza with Method:, Monitoring:, Success metric:, Owner:, Load-bearing property:, and Required automated check: `<test file>` NAMING the load-bearing property that MUST have a Step-8 test (the recurring lesson: the key safety property is often the untested one); and a ## Links traceability block (requirements, driving use case, related ADRs). Add a one-line provenance note (model-generated, edited for clarity) and, for a long ADR, a top-of-file table of contents. Do NOT use an "Alternatives considered" or "Testability/shift-left" heading in place of Considered Options / Confirmation. When creating ADDITIONAL ADRs, name them 03_adr/NNN-{decision-slug}.md with a lowercase-kebab, present-tense imperative, dateless, ticketless slug. Return wrote[] + summary.', adrOpts, FDIR + '/03_adr/001-' + SLUG + '.md', 'adr'))
659
- designThunks.push(() => designStage('Step 3.5 (QCSD ideation swarm - HTSM quality criteria + SFDIPOT risk) of /feature-adr for "' + DESC + '" (' + SLUG + '). Assess quality criteria + product-factors risk. Write ' + FDIR + '/03.5_ideation_report.md with a GO/CONDITIONAL/NO-GO verdict + top quality risks for QE. Return wrote[] + summary.', qcsdOpts, FDIR + '/03.5_ideation_report.md', 'qcsd'))
667
+ designThunks.push(() => designStage('Step 3.5 (QCSD ideation swarm - HTSM quality criteria + SFDIPOT risk) of /feature-adr for "' + DESC + '" (' + SLUG + '). Assess quality criteria + product-factors risk. Write ' + FDIR + '/03.5_ideation_report.md with a GO/CONDITIONAL/NO-GO verdict + top quality risks for QE. On a CONDITIONAL verdict, write each condition as an amendment row in a `## Amendments` section. ' + AMENDMENT_RULE + ' Return wrote[] + summary.', qcsdOpts, FDIR + '/03.5_ideation_report.md', 'qcsd'))
660
668
  const archExtra = isLplus ? ' Also ' + FDIR + '/04_domain_model.md (DDD).' : ''
661
669
  designThunks.push(() => designStage((isLplus ? 'Step 4 (DDD) + ' : '') + 'Step 5 (Architecture) of /feature-adr for "' + DESC + '" (' + SLUG + '). READ the code. Write ' + FDIR + '/05_architecture.md (components, data flow, integration points, the emit/merge/wiring shape).' + archExtra + ' Return wrote[] + summary.', archOpts, FDIR + '/05_architecture.md', 'architecture'))
662
670
  }
@@ -668,7 +676,7 @@ const design = await parallel(designThunks)
668
676
  // unavailable/errors β€” the pipeline never blocks on Codex.
669
677
  phase('Plan')
670
678
  await usageProbe('Plan')
671
- const planPrompt = 'Step 6 (SPARC-GOAP implementation plan) of /feature-adr for "' + DESC + '" (' + SLUG + ', tier ' + tier + '). Given the requirements + ADR + architecture in ' + FDIR + ', decompose into milestones + concrete tasks with success metrics. Write ' + FDIR + '/06_implementation_plan.md. Return wrote[] + summary.' + ABSOLUTE_PATH_NOTE
679
+ const planPrompt = 'Step 6 (SPARC-GOAP implementation plan) of /feature-adr for "' + DESC + '" (' + SLUG + ', tier ' + tier + '). Given the requirements + ADR + architecture in ' + FDIR + ', decompose into milestones + concrete tasks with success metrics. Write ' + FDIR + '/06_implementation_plan.md. If any corrections from Step 3.5 (a CONDITIONAL verdict) or other sources are folded into this plan, carry them in a `## Amendments` section. ' + AMENDMENT_RULE + ' Return wrote[] + summary.' + ABSOLUTE_PATH_NOTE
672
680
  // Resolve the plan model. args.models.plan wins; else the planner:'codex' knob (via routingRequested +
673
681
  // DEFAULT_MODELS/coder-fold) or the DEFAULT_MODELS.plan ('sonnet') under routing; else {} (BC).
674
682
  const planModel = resolveStageModel('plan')
@@ -779,13 +787,16 @@ if (stopHere) {
779
787
  let challengeVerdict = null
780
788
  try { challengeVerdict = plan ? await runChallengePanel('features/' + SLUG + '/06_implementation_plan.md', plan.planner) : null }
781
789
  catch (e) { log('Challenge panel errored (advisory, ignored): ' + (e && e.message ? e.message : String(e))) }
782
- return { tier: tier, phase: 'checkpoint-after-plan', artifactsDir: FDIR, planner: (plan ? plan.planner : null), plan: (plan ? plan.summary : null), modelsUsed: plannedModels, challengeVerdict: challengeVerdict, usageEvents: usageEvents, usageThreshold: USAGE_THRESHOLD, polymorphism: POLY.hasManifest ? POLY.report : null, note: 'L/XL checkpoint - review the ADR + plan (+ the planned code/qe/fleet models) + the challenge panel verdict (advisory), then re-invoke with args.stopAfter="none" to implement + QE.' }
790
+ // P4 (checkpoint-gate-line): a DERIVED gates map β€” each entry comes from machine state (artifact/verdict
791
+ // presence), never from prose, so a skipped gate shows as 'not-run' instead of being silently forgotten.
792
+ const planGates = { plan: (plan ? 'produced' : 'missing'), challengePanel: (challengeVerdict ? 'ran' : 'not-run'), code: 'not-run', qe: 'not-run' }
793
+ return { tier: tier, phase: 'checkpoint-after-plan', artifactsDir: FDIR, planner: (plan ? plan.planner : null), plan: (plan ? plan.summary : null), modelsUsed: plannedModels, challengeVerdict: challengeVerdict, gates: planGates, usageEvents: usageEvents, usageThreshold: USAGE_THRESHOLD, polymorphism: POLY.hasManifest ? POLY.report : null, note: 'L/XL checkpoint - review the ADR + plan (+ the planned code/qe/fleet models) + the challenge panel verdict (advisory) + the gates line, then re-invoke with args.stopAfter="none" to implement + QE. Present the gates map as a `🚦 Gates:` line in the checkpoint banner.' }
783
794
  }
784
795
 
785
796
  // Step 7: Code (optional Codex fallback on Claude-limit exhaustion)
786
797
  phase('Code')
787
798
  await usageProbe('Code')
788
- const codePrompt = 'Step 7 (Code) of /feature-adr for "' + DESC + '" (' + SLUG + '). Implement the feature per the plan + ADR + architecture in ' + FDIR + '. Write the ACTUAL production code + its tests (mirror the closest existing implementation named in research/architecture). Follow repo conventions; build must pass. Write a change manifest ' + FDIR + '/07_code_changes/change_manifest.md listing every file touched. Return wrote[] (incl. real source files) + summary.' + ABSOLUTE_PATH_NOTE + PS_GUIDANCE('code')
799
+ const codePrompt = 'Step 7 (Code) of /feature-adr for "' + DESC + '" (' + SLUG + '). Implement the feature per the plan + ADR + architecture in ' + FDIR + '. Write the ACTUAL production code + its tests (mirror the closest existing implementation named in research/architecture). If the plan carries a `## Amendments` section, implement every AM-N row AND its named Confirmation test (for a safeguard amendment: a test proving it FIRES on a real input). IO-ON-PURE-PATH RULE: if your diff adds I/O (DB/network/file) to a previously-pure path β€” especially a startup/lifespan/health path β€” also write a NEGATIVE resource-down test (broken/unbound resource handle β†’ the path degrades per its declared contract: fail-open for an advisory feature, explicit fail-fast for a load-bearing one) alongside the happy-path test; never fix a failing test by swapping a broken fixture for a healthy one without keeping BOTH cases. Follow repo conventions; build must pass. Write a change manifest ' + FDIR + '/07_code_changes/change_manifest.md listing every file touched. Return wrote[] (incl. real source files) + summary.' + ABSOLUTE_PATH_NOTE + PS_GUIDANCE('code')
789
800
  // Resolve the coder model. args.models.code wins (a direct 'codex' spec = codex-first); else the legacy
790
801
  // CODER knob drives it (with its codex-fallback null-guard). resolveStageModel('code') folds both via the
791
802
  // code:null sentinel β†’ resolveCoderSpec(). A Claude resolution merges {model} onto the Claude branch;
@@ -827,7 +838,7 @@ if (needsCodeLandedBarrier(coderUsed)) {
827
838
  // Step 8: QE (brutal-honesty, agentic-qe) + MANDATORY teach
828
839
  phase('QE')
829
840
  await usageProbe('QE')
830
- const qePrompt = 'Step 8 (QE - brutal-honesty review, agentic-qe) of /feature-adr for "' + DESC + '" (' + SLUG + '). Adversarially review the SHIPPED code (read it): correctness, edge cases, error handling, and the LOAD-BEARING property the ADR named (ASSERT it has a test - the recurring lesson). Run this ADR gate before final grading: ' + ADR_FITNESS_CHECKLIST + ' ' + DISCRIMINATION_GATE + ' Grade A/B/C/D honestly. Assess code-test adequacy + doc-test presence. List CONFIRMED gaps with severity. Write ' + FDIR + '/08_qe_report.md with an ADR Fitness Checklist section showing PASS/FAIL per ADR and evidence for the Confirmation-linked test. MANDATORY SELF-LEARNING STORE (close the loop, never skip): compare every candidate lesson against the Step-0 recalled LEARNED patterns above. Teach ONLY lessons NOT covered by Step-0 recall. On overlap, run `dz teach --reinforce "<recalled pattern id or exact text>" --project ' + BRAIN + '` instead of minting a near-duplicate; if --reinforce is unavailable, skip the duplicate teach and report `reinforced existing pattern <id>` in the QE report. Store every genuinely new lesson in the CANONICAL BRAIN store at `' + BRAIN + '` so it is NOT lost to a target repo you may have cd`d into. Via Bash run EXACTLY `' + DZ_TEACH('<a durable reusable lesson from this feature - a rule/pattern/pitfall, NOT a checkpoint echo>', '<0.7-0.95>', '<area>') + '` for each genuine NEW lesson (1-3 max, high-signal) β€” the `cd ' + BRAIN + ' &&` prefix + `--project ' + BRAIN + '` pin guarantee the lesson lands in the brain regardless of your CWD. Then run `' + DZ + ' statusline --fa-record --slug ' + SLUG + ' --step "Step 8 QE" --recalled 3 --stored <count taught> --reinforced <count reinforced> --mode ' + MODE + ' --project ' + REPO + '` (run it verbatim via Bash, do not skip). Do NOT teach trivia or invent gaps. AUTHORING-TIME CLAIM-CHECK (Deliverable of claim-check-authoring-time): after writing ' + FDIR + '/08_qe_report.md, run EXACTLY `dz claim-check ' + FDIR + '/08_qe_report.md --json --fail-on none` via Bash, parse the {ok, findings, scanned} JSON, and report claimCheck: {findings: N, high: N, medium: N} (counts by severity) in your return object. TAG EVERY QUANTITATIVE CLAIM you write in the report using the convention the checker recognizes as honest β€” write "1131 tests pass (MEASURED β€” `npx vitest run`)", never a bare "1131 tests pass" β€” and where you QUOTE a forbidden phrase as an example (e.g. the retracted "100% passing" framing), backtick the literal so it reads as code, not an assertion, so your own compliant report scans clean. Return {grade, gaps, codeTestsAdequate, docTestsPresent, claimCheck}.' + ABSOLUTE_PATH_NOTE + landedNote + PS_GUIDANCE('qe')
841
+ const qePrompt = 'Step 8 (QE - brutal-honesty review, agentic-qe) of /feature-adr for "' + DESC + '" (' + SLUG + '). Adversarially review the SHIPPED code (read it): correctness, edge cases, error handling, and the LOAD-BEARING property the ADR named (ASSERT it has a test - the recurring lesson). Run this ADR gate before final grading: ' + ADR_FITNESS_CHECKLIST + ' ' + DISCRIMINATION_GATE + ' ' + AMENDMENT_GATE + ' Grade A/B/C/D honestly. Assess code-test adequacy + doc-test presence. List CONFIRMED gaps with severity. Write ' + FDIR + '/08_qe_report.md with an ADR Fitness Checklist section showing PASS/FAIL per ADR and evidence for the Confirmation-linked test. MANDATORY SELF-LEARNING STORE (close the loop, never skip): compare every candidate lesson against the Step-0 recalled LEARNED patterns above. Teach ONLY lessons NOT covered by Step-0 recall. On overlap, run `dz teach --reinforce "<recalled pattern id or exact text>" --project ' + BRAIN + '` instead of minting a near-duplicate; if --reinforce is unavailable, skip the duplicate teach and report `reinforced existing pattern <id>` in the QE report. Store every genuinely new lesson in the CANONICAL BRAIN store at `' + BRAIN + '` so it is NOT lost to a target repo you may have cd`d into. Via Bash run EXACTLY `' + DZ_TEACH('<a durable reusable lesson from this feature - a rule/pattern/pitfall, NOT a checkpoint echo>', '<0.7-0.95>', '<area>') + '` for each genuine NEW lesson (1-3 max, high-signal) β€” the `cd ' + BRAIN + ' &&` prefix + `--project ' + BRAIN + '` pin guarantee the lesson lands in the brain regardless of your CWD. Then run `' + DZ + ' statusline --fa-record --slug ' + SLUG + ' --step "Step 8 QE" --recalled 3 --stored <count taught> --reinforced <count reinforced> --mode ' + MODE + ' --project ' + REPO + '` (run it verbatim via Bash, do not skip). Do NOT teach trivia or invent gaps. AUTHORING-TIME CLAIM-CHECK (Deliverable of claim-check-authoring-time): after writing ' + FDIR + '/08_qe_report.md, run EXACTLY `dz claim-check ' + FDIR + '/08_qe_report.md --json --fail-on none` via Bash, parse the {ok, findings, scanned} JSON, and report claimCheck: {findings: N, high: N, medium: N} (counts by severity) in your return object. TAG EVERY QUANTITATIVE CLAIM you write in the report using the convention the checker recognizes as honest β€” write "1131 tests pass (MEASURED β€” `npx vitest run`)", never a bare "1131 tests pass" β€” and where you QUOTE a forbidden phrase as an example (e.g. the retracted "100% passing" framing), backtick the literal so it reads as code, not an assertion, so your own compliant report scans clean. Return {grade, gaps, codeTestsAdequate, docTestsPresent, claimCheck}.' + ABSOLUTE_PATH_NOTE + landedNote + PS_GUIDANCE('qe')
831
842
  // CROSS-MODEL QE (load-bearing): resolveStageModel('qe') derives the OTHER family than the resolved
832
843
  // coder when args.models.qe is unset (coder-codex β‡’ opus; coder-Claude β‡’ codex, or opus if codex absent).
833
844
  // An explicit args.models.qe wins. A Claude qe spec is merged onto the qe-code-reviewer base (role
@@ -974,5 +985,12 @@ return {
974
985
  polymorphism: POLY.hasManifest ? POLY.report : null,
975
986
  claimGate: claimGate,
976
987
  autoCost: Object.keys(AUTOCOST).length ? AUTOCOST : null,
988
+ // P4 (checkpoint-gate-line): DERIVED gate map for the final banner β€” from actual run state, never prose.
989
+ gates: {
990
+ code: (code ? 'produced' : 'missing'),
991
+ qe: (qe ? (qe.grade || 'ran') : 'not-run'),
992
+ claimCheck: (qe && qe.claimCheck ? (qe.claimCheck.high > 0 ? 'high-findings' : 'clean') : 'not-run'),
993
+ fleet: (isLplus ? (fleet ? 'ran' : 'not-run') : 'n/a'),
994
+ },
977
995
  promiseTags: tags,
978
996
  }