@dzhechkov/harness-cli 0.5.4 → 0.6.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/.dz-manifest.json +13 -13
- package/README.md +42 -4
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +80 -1
- package/dist/cli.js.map +1 -1
- package/dist/core-compat.d.ts +1 -1
- package/dist/core-compat.js +1 -1
- package/package.json +2 -2
- package/sbom.json +12 -12
- package/src/cli.ts +80 -0
- package/src/core-compat.ts +1 -1
package/.dz-manifest.json
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
"files": [
|
|
6
6
|
{
|
|
7
7
|
"path": "CHANGELOG.md",
|
|
8
|
-
"sha256": "
|
|
8
|
+
"sha256": "fb63e4a05e205a1a2ec6806b61898a4aa5ea19148e4bb0e553e2c9b19e382a5f"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "README.md",
|
|
12
|
-
"sha256": "
|
|
12
|
+
"sha256": "e4d839c8ae59d86f2150bb632e0f8794688ccfa117974eb5f2605676912e7176"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"path": "coverage/coverage-final.json",
|
|
@@ -41,19 +41,19 @@
|
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"path": "dist/cli.d.ts.map",
|
|
44
|
-
"sha256": "
|
|
44
|
+
"sha256": "bc71c42fc8804e71454efde34beee1e4aed2d074ee029edf08fbee3e76cc369a"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"path": "dist/cli.js",
|
|
48
|
-
"sha256": "
|
|
48
|
+
"sha256": "b269e0a6c84ff4069655ee9cd8d264c3be16a12f7de2b849e8d9065d0b6c44b3"
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
"path": "dist/cli.js.map",
|
|
52
|
-
"sha256": "
|
|
52
|
+
"sha256": "8ba4b1bc4d3cc767a686f54a63e38d247fe399ccdbc959951bc788cee52f1eef"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"path": "dist/core-compat.d.ts",
|
|
56
|
-
"sha256": "
|
|
56
|
+
"sha256": "a8a7f048200d1cde46e1c4b9a175734624f86b432e45db13ff69343ef41adee3"
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
"path": "dist/core-compat.d.ts.map",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
"path": "dist/core-compat.js",
|
|
64
|
-
"sha256": "
|
|
64
|
+
"sha256": "817a16aafa21f9d592e1b74fbc7b393208aa6cbe7a1ce44059b3d57e4897ca48"
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
"path": "dist/core-compat.js.map",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
"path": "package.json",
|
|
92
|
-
"sha256": "
|
|
92
|
+
"sha256": "82ac146f7d849e1315dafc8ca4536e031d5c8104317da46ab8b52e543a187b17"
|
|
93
93
|
},
|
|
94
94
|
{
|
|
95
95
|
"path": "src/bin.ts",
|
|
@@ -97,11 +97,11 @@
|
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
"path": "src/cli.ts",
|
|
100
|
-
"sha256": "
|
|
100
|
+
"sha256": "44be85b04467075bf671bc58572bf294f402b43abc76e23354724a74ea2a6c27"
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
"path": "src/core-compat.ts",
|
|
104
|
-
"sha256": "
|
|
104
|
+
"sha256": "80b02871db06aa78df70cdc166e46a67fa9335da2f4956d6f937149b7ea69698"
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
"path": "src/index.ts",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
119
|
"path": "test/command-count.test.ts",
|
|
120
|
-
"sha256": "
|
|
120
|
+
"sha256": "a637ef30d058fcd95dc18ef6eca45d6ac06e0f2bf54341a0aae68b610180b44d"
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"path": "test/core-compat-guard.test.ts",
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
},
|
|
262
262
|
{
|
|
263
263
|
"path": "test/plan-completeness-gate.test.ts",
|
|
264
|
-
"sha256": "
|
|
264
|
+
"sha256": "fafa2d1ff56bd41a6496b7ce569be671f2f617deac07425f47ad6e87b3ec00ce"
|
|
265
265
|
},
|
|
266
266
|
{
|
|
267
267
|
"path": "test/qe-bridge-cli.test.ts",
|
|
@@ -333,5 +333,5 @@
|
|
|
333
333
|
}
|
|
334
334
|
]
|
|
335
335
|
},
|
|
336
|
-
"signature": "
|
|
336
|
+
"signature": "M4tCszFw3PbwC+QugRixQ3UqQH2YccEO9wMHSjJl8I5GSXRVnP4viiaUT7tSAvuxH+/8RBKDzSA/52R2KEbiDQ=="
|
|
337
337
|
}
|
package/README.md
CHANGED
|
@@ -281,7 +281,9 @@ dz help # see all commands
|
|
|
281
281
|
dz pretrain # analyze project files → recommend by tech stack
|
|
282
282
|
dz recommend "build API and deploy to K8s" # keyword match → skills + toolkits
|
|
283
283
|
dz recommend "work on this project" # generic? → auto-runs pretrain → recommends by stack
|
|
284
|
-
dz stats #
|
|
284
|
+
dz stats # 54 packages, 200 skills, 10 targets, 11 presets
|
|
285
|
+
# NB: the preset figure is stats' own, and it UNDER-reports — the registry has 14
|
|
286
|
+
# (reasoning, news and pm are missing from stats). Backlog 6e6ae88d7f7660f6.
|
|
285
287
|
dz dashboard # visual panel — packages, adapters, skill packs
|
|
286
288
|
dz registry # browse all 179 skills by category
|
|
287
289
|
dz registry search kubernetes # find specific skills
|
|
@@ -1735,9 +1737,35 @@ only at their documented scopes (plan + step), and `fanouts[].registry` items mu
|
|
|
1735
1737
|
ItemKey domain the trace plane enforces — `trace.emit` can never decide whether a valid plan runs.
|
|
1736
1738
|
Deferred options are on the loop-designer roadmap.
|
|
1737
1739
|
|
|
1738
|
-
|
|
1740
|
+
### `dz feature-adr-checkpoint` — record a pipeline stage only after WITNESSING it
|
|
1739
1741
|
|
|
1740
|
-
|
|
1742
|
+
```bash
|
|
1743
|
+
# refuses: the stage claims an artifact that is not on disk
|
|
1744
|
+
dz feature-adr-checkpoint --feature-dir ~/proj/features/add-auth \
|
|
1745
|
+
--stage plan --input-hash 8f21c0 --result '{"wrote":["06_implementation_plan.md"]}' \
|
|
1746
|
+
--artifact 06_implementation_plan.md
|
|
1747
|
+
# → dz feature-adr checkpoint: REFUSED — stage plan is missing its artifact(s): 06_implementation_plan.md (exit 1)
|
|
1748
|
+
|
|
1749
|
+
# records: the same call once the plan actually exists
|
|
1750
|
+
# → dz feature-adr checkpoint: recorded plan (witnessed 1 artifact(s)) (exit 0)
|
|
1751
|
+
```
|
|
1752
|
+
|
|
1753
|
+
**When to use it:** you do not call this by hand in normal work — `/feature-adr` in workflow mode calls
|
|
1754
|
+
it after every expensive stage so a crashed run resumes instead of restarting. Reach for it directly
|
|
1755
|
+
only when repairing a run's `.fa-state/checkpoints.jsonl`.
|
|
1756
|
+
|
|
1757
|
+
**Why it is a command and not a line of shell.** The workflow script is sandboxed with no filesystem,
|
|
1758
|
+
so it used to hand a subagent a finished JSON line and say *"append this"*. The subagent verified
|
|
1759
|
+
nothing, and a safety classifier read that shape as one party instructing another to declare a
|
|
1760
|
+
verification gate complete — MEASURED 2026-08-21: nine consecutive writes blocked in one six-hour run,
|
|
1761
|
+
`.fa-state/` never created, resume silently dead, and the run still reported success. The subagent now
|
|
1762
|
+
runs a command that MEASURES the declared artifacts itself. It refuses a null result (a dead stage is
|
|
1763
|
+
never recorded as done), an absent or partially-present artifact set, and a stage that declares nothing
|
|
1764
|
+
to witness — so a stage that did not happen can no longer be recorded, which the old mechanism allowed.
|
|
1765
|
+
|
|
1766
|
+
## All Commands (70)
|
|
1767
|
+
|
|
1768
|
+
*(70 MEASURED — reproducer: `grep -c "^ case '" src/cli.ts`, the dispatch cases.)*
|
|
1741
1769
|
|
|
1742
1770
|
```
|
|
1743
1771
|
dz setup --target <name> [--preset <name>] [--select id,id,...] [--skills-dir <dir>] [--memory agentdb] [--no-memory] [--no-hooks] [--install-driver] [--force]
|
|
@@ -1802,6 +1830,7 @@ dz epoch-replay --emit [--project <dir>] [--limit <N>] [--seed <N>] [--margin <
|
|
|
1802
1830
|
dz epoch-replay --judge <filled-work-order.json> [--out <file>] [--json] # blind judge prompts from the filled plans — the file carries {id, prompt} ONLY (no assignment, no arm names); refuses an order whose digest or seed-derived assignment does not check out; half-pairs skipped WITH A REASON, on stdout
|
|
1803
1831
|
dz epoch-replay --score <judgments.json> --work-order <file> [--slice <name>] [--json] # un-blind against the VERIFIED pre-registered assignment; ONE paired binomial over DECISIVE pairs (ties excluded, reported) → SUPPORTED only when the lift interval (2p−1) lies entirely above zero; FALSIFIED only on harm or a passed non-superiority test (lift upper bound below the margin PRE-REGISTERED in the work order, default 0.05, at 10+ decisive pairs); else INCONCLUSIVE (min 5 decisive pairs). Refuses a forged work order, a --margin flag, or duplicate judgement ids; the verdict is data, not an exit code
|
|
1804
1832
|
dz score --slug <feature> [--project <dir>] [--json] # process scorecard for ONE feature-adr run, from its artifacts: ADR confirmation, discrimination proof, cross-model QE grade, live verification, README-first, learning loop, amendments — DESCRIPTIVE-ONLY (a low score exits 0); evidence lines are shown so the reader judges the heuristics
|
|
1833
|
+
dz feature-adr-checkpoint (--slug <feature> | --feature-dir <abs>) --stage <s> --input-hash <h> --result <json> [--artifact a,b] [--json]
|
|
1805
1834
|
dz reqe [--slug <feature> [--done --report <f>]] [--project <dir>] [--json] # the re-QE debt ledger: a usage-switched feature-adr run whose Step-8 QE ran on the coder's OWN family (cross-model guard suspended, FR-2.9) records a debt; list debts (also surfaced by dz usage), print the cross-family review brief, settle FAIL-CLOSED against an existing GRADED report (the run's own 08_qe_report.md — even hard-linked — can never settle its own debt); settlement lands in 08_qe_report.md, evidence rotates to reqe-settled.json
|
|
1806
1835
|
dz qe-bridge --family claude --slug <feature> [--coder-family codex|claude] [--model <id>] [--files a,b] [--out <f>] [--timeout <s>] [--allow-same-family] [--json] # the REVERSE QE bridge (Codex-hosted → Claude reviewer): the reviewer runs ISOLATED (an empty temp cwd + --safe-mode --strict-mcp-config --tools '' --no-session-persistence, so no CLAUDE.md/skills/plugins/hooks/MCP load) and its verdict is read from the --output-format json RESULT ENVELOPE, so text a customization printed onto the same stdout can never become a signoff. Probes the model first; sends SCOPED extracts under a loud 200k-char ceiling; the grade must agree across three LAST-anchored channels AND the marker must be the final content — empty/gradeless/mismatched/miscounted output is a named failure with an audit record under features/<slug>/.fa-state/qe-bridge/, never a clean review. exit 0 signoff parsed (ANY grade — it reports, it does not gate) / 1 named failure / 2 usage. DZ_QE_BRIDGE_CLAUDE_BIN is a TEST SEAM (recorded as binOverride:true)
|
|
1807
1836
|
dz backlog <sub> add "<idea>" | list | show <id> | goals [--validate] | roulette [--seed n] [--commit <id>] | ship <id…> | drop <id…> | reopen <id…> | enrich <id> | jira <id> | harmonize [--apply] # brain-backed idea backlog: capture an idea → semantic dedup against past ideas/features via the REUSED agentdb vector engine (two-signal: bounded-excerpt cosine DUPLICATE≥0.92 corroborated by shared subject vocabulary — a register-only 0.94 is demoted to RELATED, a length-only re-capture is caught as a subset duplicate; absorbed texts kept in absorbed.jsonl) + GoalMap alignment ("map+compass") → weighted seeded roulette picks one to work on → enrich STAGES an idea2prd hand-off → jira writes an auditable outbox via a configurable MCP adapter seam (jira-mcp|copilot-mcp|none). No 2nd vector store; without agentdb it degrades to exact-text dedup (honest)
|
|
@@ -3992,7 +4021,16 @@ npx @dzhechkov/p-replicator init
|
|
|
3992
4021
|
|
|
3993
4022
|
## Status
|
|
3994
4023
|
|
|
3995
|
-
`v0.
|
|
4024
|
+
`v0.6.0` — adds `dz feature-adr-checkpoint`, which writes the pipeline's durable checkpoint line as a
|
|
4025
|
+
COMMAND instead of leaving a subagent to hand-write state into a file: a security classifier blocked
|
|
4026
|
+
NINE consecutive hand-written checkpoint writes in one run, `.fa-state/checkpoints.jsonl` was never
|
|
4027
|
+
created, resume was silently dead, and the run still reported success. The command measures every
|
|
4028
|
+
declared artifact and refuses to persist a null result, absent or partial artifacts, or a stage that
|
|
4029
|
+
declared no artifact at all. `MIN_CORE` moves to `0.6.0` and the dependency range with it — under 0.x
|
|
4030
|
+
semver a caret pins the minor, so a range left at `^0.5.4` would install a core this build then
|
|
4031
|
+
refuses at startup.
|
|
4032
|
+
|
|
4033
|
+
**v0.5.4** — **published 2026-08-20** (0.5.3 is deprecated — the core it pinned could not be installed). No CLI behavior change of its own: released in lockstep with
|
|
3996
4034
|
`@dzhechkov/harness-core@0.5.3` and pinned to it, so a fresh install gets the per-sibling design
|
|
3997
4035
|
checkpoint in `/feature-adr` (one dead design agent no longer discards three finished siblings) and
|
|
3998
4036
|
its refusal gate (an incomplete design fan stops at the Step-5/6 boundary instead of planning off a
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAA0B,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKtF,OAAO,EA2CL,iBAAiB,EAmBjB,KAAK,oBAAoB,EA6SzB,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ readBacklogConfig, readIdeas, writeIdeas, ideaId, dedupIdea, readGoalMap, readGo
|
|
|
22
22
|
// qe-bridge (feature qe-bridge-claude, ADR-001): the pure half of the reverse QE bridge.
|
|
23
23
|
KNOWN_CLAUDE, isSafeClaudeId, claudeProbeArgs, claudeReviewArgs, interpretClaudeProbe, modelFamily, buildBridgePrompt, parseBridgeOutput, buildBridgeFailureRecord, buildBridgeSignoffRecord, renderBridgeReport, isSafeSlug, hasUnsafePathChars, hasDotDotSegment, buildReqeBrief, settleReqeDebt, renderReqeList, REQE_SCOPE,
|
|
24
24
|
// Mutation gate (feature ha-mutation-gate) — break each named protection, run the suite, require red.
|
|
25
|
-
parseMutationRegistry, applyMutationToText, countFailingTests, classifyBaseline, classifyRunFailure, classifyMutationOutcome, mutationGateExitCode, summarizeMutationResults, renderMutationReport, TRACE_BUNDLE_LEDGER_PATH, TRACE_BUNDLE_SCHEMA, TRACE_BUNDLE_RUN_META_FILE, buildBundle, serializeBundle, parseBundle, planImport, } from '@dzhechkov/harness-core';
|
|
25
|
+
parseMutationRegistry, applyMutationToText, countFailingTests, classifyBaseline, classifyRunFailure, classifyMutationOutcome, mutationGateExitCode, summarizeMutationResults, renderMutationReport, TRACE_BUNDLE_LEDGER_PATH, TRACE_BUNDLE_SCHEMA, TRACE_BUNDLE_RUN_META_FILE, buildBundle, serializeBundle, parseBundle, planImport, decideCheckpointWrite, } from '@dzhechkov/harness-core';
|
|
26
26
|
import { getPreset, PRESET_NAMES } from '@dzhechkov/harness-presets';
|
|
27
27
|
import { scanGitHub, analyzeRepo, generateReport, deepAnalyze, scanAllSources, ScoutMemory } from '@dzhechkov/scout';
|
|
28
28
|
const USAGE = `dz - DZ cross-platform harness CLI
|
|
@@ -62,6 +62,7 @@ Usage:
|
|
|
62
62
|
dz epoch-replay --judge <filled-work-order.json> [--out <file>] (blind judge prompts from the filled plans)
|
|
63
63
|
dz epoch-replay --score <judgments.json> --work-order <file> [--slice <name>] [--json] (un-blind against the pre-registered assignment → SUPPORTED only when the two 95% Wilson CIs are DISJOINT, else FALSIFIED / INCONCLUSIVE)
|
|
64
64
|
dz score --slug <feature> [--project <dir>] [--json] (process scorecard for ONE feature-adr run, from its artifacts: ADR confirmation, discrimination, cross-model QE grade, live verification, README-first, learning loop, amendments — descriptive-only, a low score exits 0)
|
|
65
|
+
dz feature-adr-checkpoint (--slug <feature> | --feature-dir <abs>) --stage <s> --input-hash <h> --result <json> [--artifact a,b] [--json] (record a pipeline stage ONLY after measuring its artifacts on disk; refuses a null result, an absent artifact, or a stage that declares none — the subagent runs a COMMAND instead of hand-writing durable state)
|
|
65
66
|
dz reqe [--slug <feature> [--done --report <f>]] [--json] (the re-QE debt ledger: a usage-switched run whose Step-8 QE ran on the coder's OWN family records a debt; list debts, print the cross-family review brief, settle FAIL-CLOSED against a graded report — the settlement lands in 08_qe_report.md)
|
|
66
67
|
dz qe-bridge --family claude --slug <feature> [--coder-family codex|claude] [--model <id>] [--files a,b] [--out <f>] [--timeout <s>] [--allow-same-family] [--json] (the REVERSE QE bridge: run an INDEPENDENT Claude reviewer over a feature's Step-8 artifacts from ANY host — a Codex session included, plain shell, no Claude agent plane needed — and land a PARSED signoff. The reviewer runs ISOLATED: an EMPTY temp cwd plus --safe-mode --strict-mcp-config --tools '' --no-session-persistence, so no CLAUDE.md/skills/plugins/hooks/MCP load, and the verdict is read from the --output-format json RESULT ENVELOPE — text a session customization printed onto the same stdout can never become a signoff. Probes the model before trusting it; sends SCOPED extracts with a loud 200k-char ceiling (never silent truncation); the grade must AGREE across three LAST-anchored channels (terminal marker line, fenced qe-bridge-signoff JSON, the report's own GRADE line) AND the marker must be the FINAL content — empty, gradeless, self-contradicting or miscounted output is one of 18 NAMED failures with an audit record under features/<slug>/.fa-state/qe-bridge/ (runId, resolved executable + binOverride, prompt sha256, channel offsets, requestedOut, reportWritten, retained raw stdout; 0600 files in a 0700 dir), never a clean review. A --coder-family that contradicts the recorded reqe debt is refused. Writes features/<slug>/08b_reqe_report.md, which dz reqe --done settles unchanged. DISCLOSURE: the extracts you scope are sent to the Claude runtime; the bridge cannot classify secrets. DZ_QE_BRIDGE_CLAUDE_BIN is a TEST SEAM, not a flag. exit 0 signoff parsed (ANY grade — it reports, it does not gate) / 1 named failure / 2 usage)
|
|
67
68
|
dz mutation-gate [--package <dir>] [--registry <file>] [--test-cmd "<cmd>"] [--only <id[,id]>] [--timeout <ms>] [--rebaseline per-entry|final] [--keep-scratch] [--json] (prove each NAMED protection has a test that DISCRIMINATES: copy the package to a scratch dir, verify the baseline suite is green, apply each registry mutation, run the suite, REQUIRE red, restore. The red must be BEHAVIOURAL: a mutation that no longer parses is MUTATION_UNPARSEABLE; a red run whose OWN output reports a test FILE failing to load (node --test file-level not-ok with exitCode, vitest Failed Suites) is MUTATION_LOAD_FATAL — the signal comes from the same run as the failing count, never from a separate isolated import; red output whose shape matches no known runner is INCONCLUSIVE (a runner-coverage gap, loud, never PROVEN); a count far above the entry's bound is OVER_FAILING; a restored tree that does not reproduce green makes the entry INCONCLUSIVE (flaky). Mutation writes are realpath-contained to the scratch copy: a symlink escape or a node_modules/ target is refused (exit 2), the real tree is never written. A mutation that does not apply, a green suite, or an inconclusive run is a FAILURE — never a skip. exit 0 all proven / 1 gate failed / 2 setup error)
|
|
@@ -8614,6 +8615,82 @@ function scanOneReqeRoot(featuresDir, keyMatchesDir, out, addMalformed) {
|
|
|
8614
8615
|
* `dz reqe` — the re-QE debt ledger (backlog 6b40e667): list usage-switched same-family QE debts,
|
|
8615
8616
|
* print the cross-family review brief, settle FAIL-CLOSED against a graded report.
|
|
8616
8617
|
*/
|
|
8618
|
+
/**
|
|
8619
|
+
* `dz feature-adr checkpoint` — record a pipeline stage, but only after WITNESSING its artifacts.
|
|
8620
|
+
*
|
|
8621
|
+
* Why this is a command and not a line of shell (2026-08-21). The workflow script is sandboxed with
|
|
8622
|
+
* no filesystem, so it delegated checkpoint writes to a subagent by handing it a finished JSON line
|
|
8623
|
+
* and saying "append this". The subagent verified nothing. A safety classifier read that shape as one
|
|
8624
|
+
* party instructing another to declare a verification gate complete, and blocked NINE consecutive
|
|
8625
|
+
* writes in one run — router, four design substages, plan, code, qe, and the cost-ledger row. The
|
|
8626
|
+
* measured consequence: `.fa-state/checkpoints.jsonl` was never created, resume was silently dead,
|
|
8627
|
+
* and the six-hour run still reported success.
|
|
8628
|
+
*
|
|
8629
|
+
* The classifier's premise was wrong for those particular writes — every stage had run. Its instinct
|
|
8630
|
+
* was not: the old mechanism could not tell a real completion from a fabricated one, which is exactly
|
|
8631
|
+
* what a cross-family reviewer had already filed against the `fleet` stage. So the subagent now runs
|
|
8632
|
+
* THIS, and the verification lives in code under test instead of in the wording of a prompt.
|
|
8633
|
+
*
|
|
8634
|
+
* It measures `--artifact` paths on disk itself. A caller cannot assert presence; it can only name
|
|
8635
|
+
* what must be there.
|
|
8636
|
+
*/
|
|
8637
|
+
function cmdFeatureAdrCheckpoint(options, flags, cwd, write) {
|
|
8638
|
+
const json = flags.has('json');
|
|
8639
|
+
const emit = (payload, human, code) => {
|
|
8640
|
+
if (json)
|
|
8641
|
+
write(JSON.stringify(payload));
|
|
8642
|
+
else
|
|
8643
|
+
write(human);
|
|
8644
|
+
return code;
|
|
8645
|
+
};
|
|
8646
|
+
const slug = (options.get('slug') ?? '').trim();
|
|
8647
|
+
const stage = (options.get('stage') ?? '').trim();
|
|
8648
|
+
const inputHash = (options.get('input-hash') ?? '').trim();
|
|
8649
|
+
const resultRaw = options.get('result') ?? '';
|
|
8650
|
+
const artifacts = (options.get('artifact') ?? '')
|
|
8651
|
+
.split(',')
|
|
8652
|
+
.map((a) => a.trim())
|
|
8653
|
+
.filter((a) => a !== '');
|
|
8654
|
+
if ((slug === '' && (options.get('feature-dir') ?? '').trim() === '') || stage === '' || inputHash === '') {
|
|
8655
|
+
return emit({ ok: false, reason: 'usage' }, 'dz feature-adr checkpoint: --stage, --input-hash and one of --slug / --feature-dir are required', 2);
|
|
8656
|
+
}
|
|
8657
|
+
let result;
|
|
8658
|
+
try {
|
|
8659
|
+
result = JSON.parse(resultRaw);
|
|
8660
|
+
}
|
|
8661
|
+
catch {
|
|
8662
|
+
return emit({ ok: false, reason: 'result is not valid JSON' }, 'dz feature-adr checkpoint: --result must be valid JSON', 2);
|
|
8663
|
+
}
|
|
8664
|
+
// --feature-dir wins when given: the workflow knows the absolute path already, and depending on
|
|
8665
|
+
// cwd resolution there would make the command's behaviour depend on where the subagent happened to
|
|
8666
|
+
// stand. --slug stays for humans running this by hand from a repo root.
|
|
8667
|
+
const explicitDir = (options.get('feature-dir') ?? '').trim();
|
|
8668
|
+
const featureDir = explicitDir !== '' ? explicitDir : join(cwd, 'features', slug);
|
|
8669
|
+
// MEASURE, never trust: presence is established here, by this process, on this disk.
|
|
8670
|
+
const present = artifacts.filter((rel) => {
|
|
8671
|
+
const abs = join(featureDir, rel);
|
|
8672
|
+
try {
|
|
8673
|
+
return statSync(abs).isFile();
|
|
8674
|
+
}
|
|
8675
|
+
catch {
|
|
8676
|
+
return false;
|
|
8677
|
+
}
|
|
8678
|
+
});
|
|
8679
|
+
const verdict = decideCheckpointWrite({ stage, inputHash, result, artifacts, present });
|
|
8680
|
+
if (!verdict.ok) {
|
|
8681
|
+
return emit({ ok: false, stage, reason: verdict.reason }, 'dz feature-adr checkpoint: REFUSED — ' + verdict.reason, 1);
|
|
8682
|
+
}
|
|
8683
|
+
const stateDir = join(featureDir, '.fa-state');
|
|
8684
|
+
try {
|
|
8685
|
+
mkdirSync(stateDir, { recursive: true });
|
|
8686
|
+
appendFileSync(join(stateDir, 'checkpoints.jsonl'), verdict.line + '\n', 'utf-8');
|
|
8687
|
+
}
|
|
8688
|
+
catch (err) {
|
|
8689
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
8690
|
+
return emit({ ok: false, stage, reason }, 'dz feature-adr checkpoint: write failed — ' + reason, 1);
|
|
8691
|
+
}
|
|
8692
|
+
return emit({ ok: true, stage, witnessed: verdict.witnessed }, 'dz feature-adr checkpoint: recorded ' + stage + ' (witnessed ' + verdict.witnessed.length + ' artifact(s))', 0);
|
|
8693
|
+
}
|
|
8617
8694
|
function cmdReqe(options, flags, cwd, write) {
|
|
8618
8695
|
const json = flags.has('json');
|
|
8619
8696
|
if (flags.has('help')) {
|
|
@@ -11436,6 +11513,8 @@ export async function runCli(argv, io = {}) {
|
|
|
11436
11513
|
return cmdEpochReplay(options, flags, cwd, write);
|
|
11437
11514
|
case 'score':
|
|
11438
11515
|
return cmdScore(options, flags, cwd, write);
|
|
11516
|
+
case 'feature-adr-checkpoint':
|
|
11517
|
+
return cmdFeatureAdrCheckpoint(options, flags, cwd, write);
|
|
11439
11518
|
case 'reqe':
|
|
11440
11519
|
return cmdReqe(options, flags, cwd, write);
|
|
11441
11520
|
case 'qe-bridge':
|