@dzhechkov/skills-feature-adr 1.3.56 → 1.3.58
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/bin/cli.js +0 -0
- package/package.json +5 -6
- package/templates/.claude/rules/feature-adr-conventions.md +28 -0
- package/templates/.claude/skills/code-critic/SKILL.md +27 -0
- package/templates/.claude/skills/code-impl/SKILL.md +17 -0
- package/templates/.claude/skills/feature-adr/SKILL.md +14 -0
- package/templates/.claude/skills/feature-adr/modules/03.5-ideation-swarm.md +22 -1
- package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +5 -0
- package/templates/.claude/skills/feature-adr/modules/07-code.md +18 -0
- package/templates/.claude/skills/feature-adr/modules/08-qe.md +24 -0
- package/templates/.claude/workflows/feature-adr.js +28 -5
package/bin/cli.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/skills-feature-adr",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.58",
|
|
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"
|
|
@@ -13,10 +13,6 @@
|
|
|
13
13
|
"CHANGELOG.md",
|
|
14
14
|
"docs/"
|
|
15
15
|
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"test": "node --test \"test/**/*.test.js\"",
|
|
18
|
-
"prepack": "node -e \"const fs=require('fs');const bad=['.claude','.skills-feature-adr.json'].filter(p=>fs.existsSync(p));if(bad.length){console.error('prepack guard: stray init artifacts in package dir: '+bad.join(', ')+' — remove before packing');process.exit(1)}\""
|
|
19
|
-
},
|
|
20
16
|
"keywords": [
|
|
21
17
|
"claude",
|
|
22
18
|
"claude-code",
|
|
@@ -61,5 +57,8 @@
|
|
|
61
57
|
},
|
|
62
58
|
"publishConfig": {
|
|
63
59
|
"access": "public"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"test": "node --test \"test/**/*.test.js\""
|
|
64
63
|
}
|
|
65
|
-
}
|
|
64
|
+
}
|
|
@@ -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.
|
|
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:
|
|
@@ -555,6 +555,19 @@ const PROJECT_SKILLS = { type: 'object', additionalProperties: false, required:
|
|
|
555
555
|
const QE = { type: 'object', additionalProperties: false, required: ['grade', 'gaps', 'codeTestsAdequate', 'docTestsPresent'], properties: { grade: { type: 'string' }, codeTestsAdequate: { type: 'boolean' }, docTestsPresent: { type: 'boolean' }, gaps: { type: 'array', items: { type: 'object', additionalProperties: false, required: ['sev', 'what'], properties: { sev: { type: 'string' }, what: { type: 'string' } } } }, claimCheck: { type: 'object', additionalProperties: false, properties: { findings: { type: 'number' }, high: { type: 'number' }, medium: { type: 'number' } } } } }
|
|
556
556
|
const ADR_TEMPLATE_GUIDE = 'ADR best-practices for Step 3: emit exactly one decision per ADR with the invariant core Title, Status, Context, Decision, Consequences. Template weight is tier-routed: S/M use Nygard/ITD-lightweight form but still include decision drivers, considered options, rationale, consequences, and Confirmation; L/XL use MADR structure plus an NHS Wales Confirmation stanza. Confirmation MUST name verification method, monitoring, success metric, and owner, and its load-bearing safety property MUST be tied to a Step-8 automated test/fitness function. Use status vocabulary proposed/accepted/rejected/deprecated/superseded plus a reversibility clause. Context must be neutral and appear before Decision. Considered Options must include rejected options with symmetric pros/cons. Rationale points must map to stated drivers and explain why losers were rejected. Consequences must include positive and negative outcomes/accepted downsides, follow-up ADR links, an after-action review schedule, and supersession discipline: supersession mints a new ADR and never edits accepted/rejected ADR content in place. Decision must be concrete/testable with exact names, versions, formats, paths, commands, or APIs. Reject explainer-masquerading-as-ADR: a domain overview with no concrete Decision is not an ADR. File names under 03_adr MUST be sequential NNN-{decision-slug}.md with lowercase kebab-case, dateless, ticketless slugs (the auto-001 ADR tracks the feature slug, so the present-tense imperative signal lives in the ADR Title; model-named additional ADRs use imperative slugs). Add a ## Links traceability block (requirements, driving use case, related ADRs) and a one-line provenance note (model-generated, edited for clarity); for a long ADR include a top-of-file table of contents.'
|
|
557
557
|
const ADR_FITNESS_CHECKLIST = 'ADR fitness checklist for Step 8: read every ' + FDIR + '/03_adr/NNN-*.md ADR and fail the QE gate for any miss. Required checks: (1) filename is 03_adr/NNN-{decision-slug}.md where the slug is lowercase kebab-case, imperative, dateless, and ticketless; (2) title is decision-shaped and the ADR records one decision only; (3) Status is non-empty controlled vocabulary proposed/accepted/rejected/deprecated/superseded and includes a reversibility/revisit clause; (4) Context is neutral, problem-first, and appears before Decision; (5) Decision Drivers are stated and ranked/weighted; (6) Considered Options include the chosen and rejected options, each with symmetric pros and cons; (7) Rationale maps each point back to a driver and explains why rejected options lost; (8) Decision is concrete/testable with exact names, versions, formats, paths, commands, or APIs; (9) Consequences include positive and negative outcomes/accepted downsides, follow-up ADR links, and an after-action review schedule; (10) Confirmation names verification method, monitoring, success metric, and owner, then links the load-bearing safety property to an automated test/fitness function; (11) no placeholder text, template hints, raw generation scaffolding, or fake Markdown structure; (12) reject explainer-masquerading-as-ADR: describing a space with no concrete Decision is a blocker; (13) a Related/Links traceability block maps the ADR to its requirements, driving use case, and related ADRs. The ADR Confirmation check is load-bearing: assert the named safety property has a real test by file/name; if absent, grade no better than C and record a blocker gap.'
|
|
558
|
+
// §42 test-discrimination gate (feature step8-discrimination-gate, grounded in cve-bench/evaluate.mjs). Asserting
|
|
559
|
+
// the property HAS a test is presence; this asserts it DISCRIMINATES. Advisory — a false green is a HIGH gap, never
|
|
560
|
+
// an auto-abort (dz's rule: a false gate kills trust). Byte-inlined guidance; the safe worktree/run lives in `dz
|
|
561
|
+
// discrimination-check` (harness-core/src/discrimination-gate.ts).
|
|
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.'
|
|
558
571
|
|
|
559
572
|
// Step 0: Router + MANDATORY self-learning recall
|
|
560
573
|
phase('Router')
|
|
@@ -651,7 +664,7 @@ modelsUsed.ddd = modelLabel(archOpts)
|
|
|
651
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'))
|
|
652
665
|
if (isMplus) {
|
|
653
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'))
|
|
654
|
-
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'))
|
|
655
668
|
const archExtra = isLplus ? ' Also ' + FDIR + '/04_domain_model.md (DDD).' : ''
|
|
656
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'))
|
|
657
670
|
}
|
|
@@ -663,7 +676,7 @@ const design = await parallel(designThunks)
|
|
|
663
676
|
// unavailable/errors — the pipeline never blocks on Codex.
|
|
664
677
|
phase('Plan')
|
|
665
678
|
await usageProbe('Plan')
|
|
666
|
-
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
|
|
667
680
|
// Resolve the plan model. args.models.plan wins; else the planner:'codex' knob (via routingRequested +
|
|
668
681
|
// DEFAULT_MODELS/coder-fold) or the DEFAULT_MODELS.plan ('sonnet') under routing; else {} (BC).
|
|
669
682
|
const planModel = resolveStageModel('plan')
|
|
@@ -774,13 +787,16 @@ if (stopHere) {
|
|
|
774
787
|
let challengeVerdict = null
|
|
775
788
|
try { challengeVerdict = plan ? await runChallengePanel('features/' + SLUG + '/06_implementation_plan.md', plan.planner) : null }
|
|
776
789
|
catch (e) { log('Challenge panel errored (advisory, ignored): ' + (e && e.message ? e.message : String(e))) }
|
|
777
|
-
|
|
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.' }
|
|
778
794
|
}
|
|
779
795
|
|
|
780
796
|
// Step 7: Code (optional Codex fallback on Claude-limit exhaustion)
|
|
781
797
|
phase('Code')
|
|
782
798
|
await usageProbe('Code')
|
|
783
|
-
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')
|
|
784
800
|
// Resolve the coder model. args.models.code wins (a direct 'codex' spec = codex-first); else the legacy
|
|
785
801
|
// CODER knob drives it (with its codex-fallback null-guard). resolveStageModel('code') folds both via the
|
|
786
802
|
// code:null sentinel → resolveCoderSpec(). A Claude resolution merges {model} onto the Claude branch;
|
|
@@ -822,7 +838,7 @@ if (needsCodeLandedBarrier(coderUsed)) {
|
|
|
822
838
|
// Step 8: QE (brutal-honesty, agentic-qe) + MANDATORY teach
|
|
823
839
|
phase('QE')
|
|
824
840
|
await usageProbe('QE')
|
|
825
|
-
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 + ' 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')
|
|
826
842
|
// CROSS-MODEL QE (load-bearing): resolveStageModel('qe') derives the OTHER family than the resolved
|
|
827
843
|
// coder when args.models.qe is unset (coder-codex ⇒ opus; coder-Claude ⇒ codex, or opus if codex absent).
|
|
828
844
|
// An explicit args.models.qe wins. A Claude qe spec is merged onto the qe-code-reviewer base (role
|
|
@@ -969,5 +985,12 @@ return {
|
|
|
969
985
|
polymorphism: POLY.hasManifest ? POLY.report : null,
|
|
970
986
|
claimGate: claimGate,
|
|
971
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
|
+
},
|
|
972
995
|
promiseTags: tags,
|
|
973
996
|
}
|