@dzhechkov/harness-cli 0.3.262 → 0.4.2
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 +125 -17
- package/README.md +428 -11
- package/dist/bin.js +11 -1
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1092 -63
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
- package/sbom.json +292 -22
- package/src/bin.ts +12 -1
- package/src/cli.ts +1069 -65
package/README.md
CHANGED
|
@@ -132,7 +132,7 @@ point any tool at (a skill is just Markdown). Dedicated targets are on the [road
|
|
|
132
132
|
|
|
133
133
|
## User Journey — from install to mastery
|
|
134
134
|
|
|
135
|
-
All
|
|
135
|
+
All 66 commands (MEASURED — reproducer: `grep -c "^ case '" src/cli.ts`, the dispatch cases) mapped to a real workflow:
|
|
136
136
|
|
|
137
137
|
```
|
|
138
138
|
DISCOVER → INSTALL → USE → CREATE → MAINTAIN → SHARE
|
|
@@ -230,9 +230,10 @@ dz upgrade --target openclaude # check specific platform
|
|
|
230
230
|
dz sync # canonical → project skills
|
|
231
231
|
dz migrate # detect legacy installations
|
|
232
232
|
|
|
233
|
-
#
|
|
234
|
-
dz workflow --
|
|
235
|
-
dz workflow
|
|
233
|
+
# Author + gate custom Workflow loops (loop-plan/1):
|
|
234
|
+
dz workflow init --name my-loop --pattern pipeline --o my-loop.plan.json
|
|
235
|
+
dz workflow render my-loop.plan.json --o my-loop.js
|
|
236
|
+
dz workflow-lint my-loop.js --plan my-loop.plan.json --require-plan
|
|
236
237
|
|
|
237
238
|
# Cross-host state sync:
|
|
238
239
|
dz roam --apply # sync agent state across machines
|
|
@@ -838,6 +839,110 @@ the discriminator is a heuristic — a package counts as a skill pack only if it
|
|
|
838
839
|
registrable skill, and a directory is flagged only when a `SKILL.md` really exists inside it but in the
|
|
839
840
|
wrong place. Ordinary `scripts/`, `docs/` and pure npx toolkits stay silent.
|
|
840
841
|
|
|
842
|
+
### Does your test actually DEFEND the protection? — `dz mutation-gate`
|
|
843
|
+
|
|
844
|
+
A green test proves the code works. It does NOT prove the test would have noticed the protection
|
|
845
|
+
being deleted. Three cross-model QE rounds on `@dzhechkov/health-advisor` produced 53 → 14 → 14
|
|
846
|
+
findings while the whole suite stayed green (MEASURED — reproducer: the three QE rounds recorded in
|
|
847
|
+
that package's history; the round-1 exploit string the code comment records as MEASURED passed a
|
|
848
|
+
444-test green suite). The one technique that proved a protection real in those rounds was:
|
|
849
|
+
delete the protection in a scratch copy, re-run the suite, require red. `dz mutation-gate` is that
|
|
850
|
+
measurement as a layer-1 repo check.
|
|
851
|
+
|
|
852
|
+
The registry is declarative DATA (data is harder to make lie): one entry per NAMED safety property,
|
|
853
|
+
with an exact `{find, replace}` mutation that deletes the protection.
|
|
854
|
+
|
|
855
|
+
```jsonc
|
|
856
|
+
// test/mutation-registry.json
|
|
857
|
+
{
|
|
858
|
+
"testCommand": "npm test",
|
|
859
|
+
"entries": [{
|
|
860
|
+
"id": "verbatim-door-requires-resolvable-locator",
|
|
861
|
+
"property": "An evidence quote is exempt from content scans only when its locator resolves…",
|
|
862
|
+
"file": "lib/appraisal-core.js",
|
|
863
|
+
"mutation": { "find": "<exact source text>", "replace": "<neutered text>" },
|
|
864
|
+
"minFailing": 1, // the entry's contract: at least this many tests MUST go red
|
|
865
|
+
"observed": 4 // how many did when written — a later lower count prints a COVERAGE DROP warning
|
|
866
|
+
}]
|
|
867
|
+
}
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
```bash
|
|
871
|
+
cd packages/@dzhechkov/health-advisor
|
|
872
|
+
dz mutation-gate # registry auto-found at test/mutation-registry.json
|
|
873
|
+
dz mutation-gate --only lock-root-resolves-to-itself # one entry while iterating
|
|
874
|
+
dz mutation-gate --rebaseline final # cheap flake guard: one re-run at the end instead of per red entry
|
|
875
|
+
dz mutation-gate --json # machine contract {baseline, results, summary, warnings, exitCode}
|
|
876
|
+
npm run test:mutation # the package's own alias for the full run
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
Expected output (abridged from a real run — MEASURED 2026-08-07, reproducer: `cd
|
|
880
|
+
packages/@dzhechkov/health-advisor && dz mutation-gate`, 18 entries over a 484-test `node --test`
|
|
881
|
+
suite; wall-clock 9m32s with the default per-entry re-baseline, 4m53s with `--rebaseline final` —
|
|
882
|
+
same reproducer, both modes timed on the same tree):
|
|
883
|
+
|
|
884
|
+
```
|
|
885
|
+
mutation-gate: baseline suite in scratch copy of …/health-advisor …
|
|
886
|
+
mutation-gate: verbatim-door-requires-resolvable-locator — mutating lib/appraisal-core.js, running suite …
|
|
887
|
+
baseline: GREEN — baseline suite green in the scratch copy
|
|
888
|
+
✓ verbatim-door-requires-resolvable-locator applied=yes failing=4 PROVEN
|
|
889
|
+
✗ cli-swallows-only-epipe applied=yes failing=0 UNDEFENDED
|
|
890
|
+
suite stayed GREEN with the protection deleted — property UNDEFENDED: "Only EPIPE is
|
|
891
|
+
swallowed on stdout/stderr — every other stream error stays a loud crash." …
|
|
892
|
+
summary: 17/18 proven · 1 undefended · 0 not-applied · 0 below-min · 0 unparseable · 0 over-failing · 0 inconclusive · 0 coverage drop(s)
|
|
893
|
+
verdict: FAIL — at least one named protection is undefended, unmutable, or unproven
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
That `UNDEFENDED` line is the command earning its keep: on its FIRST run against health-advisor the
|
|
897
|
+
gate found 2 protections whose suite stayed green with the protection deleted (MEASURED 2026-08-07 —
|
|
898
|
+
reproducer: `dz mutation-gate --package packages/@dzhechkov/health-advisor --json` at the commit
|
|
899
|
+
before `test/case-state-alias-and-stream-error-discrimination.test.js` landed), plus a third
|
|
900
|
+
(the post-acquisition lock-scope re-assert) that was undefended in BOTH the pre-fix and current
|
|
901
|
+
trees. All three now have discriminating tests and registry entries.
|
|
902
|
+
|
|
903
|
+
Four rules the gate itself obeys — these are what distinguish it from a green-looking script:
|
|
904
|
+
|
|
905
|
+
1. **A mutation that does not apply is a FAILURE, never a skip** — `find` absent, or present more
|
|
906
|
+
than once, fails loudly (code drifts; a silently-skipped mutation reports a protection as proven
|
|
907
|
+
having tested nothing — the `dz skills-verify` lesson: inconclusive ≠ pass).
|
|
908
|
+
2. **A green suite under mutation is a FAILURE** that names WHICH property is undefended.
|
|
909
|
+
3. **The working tree is never mutated.** The package is copied into a scratch shadow of its repo
|
|
910
|
+
(siblings symlinked, `node_modules` linked, the copy git-initialized so hygiene tests keep
|
|
911
|
+
working); the baseline suite must be green there BEFORE any mutation, and a red baseline is a
|
|
912
|
+
setup error (exit 2), never a mutation result.
|
|
913
|
+
4. **The gate carries its own discrimination proof**: a fixture package with a deliberately
|
|
914
|
+
undefended property lives in this repo's test suite, and the gate MUST fail on it — a gate that
|
|
915
|
+
cannot fail cannot pass.
|
|
916
|
+
|
|
917
|
+
When to reach for it: after a QE round names safety properties (seed the registry so they STAY
|
|
918
|
+
defended); in CI for a package whose protections have burned you before (`npm run test:mutation`);
|
|
919
|
+
and in feature-adr Step 8, where the QE reviewer runs it whenever the touched package has a
|
|
920
|
+
registry — the Step-8 assertion is now "the safety property the ADR names has a test that
|
|
921
|
+
DISCRIMINATES", not merely "has a test".
|
|
922
|
+
|
|
923
|
+
Verdicts per entry: `PROVEN` (red, count ≥ `minFailing`) · `UNDEFENDED` (green — the failure this
|
|
924
|
+
gate exists for) · `NOT_APPLIED` (find-text absent/ambiguous) · `BELOW_MIN` (red but a reliable
|
|
925
|
+
count under the entry's `minFailing` contract) · `MUTATION_UNPARSEABLE` (the mutated file no
|
|
926
|
+
longer parses — structural redness, a registry error) · `MUTATION_LOAD_FATAL` (THE SUITE RUN'S OWN
|
|
927
|
+
OUTPUT reports a test FILE failing to load under the mutation — a file-named `node --test` TAP
|
|
928
|
+
point carrying `exitCode:`/`signal:` fields, or a vitest `Failed Suites` entry — as opposed to
|
|
929
|
+
assertion failures inside running tests; the signal comes from the SAME run that produced the
|
|
930
|
+
failing count, never from a separate isolated import, so there is no environment mismatch to
|
|
931
|
+
false-PASS through) · `OVER_FAILING` (a reliable count far
|
|
932
|
+
above the entry's bound — the mutation broke much more than the protection's own tests) ·
|
|
933
|
+
`INCONCLUSIVE` (no exit code — timeout/kill — or red output whose SHAPE matches no runner the
|
|
934
|
+
classifier knows — jest, mocha, an opaque wrapper: a loud runner-coverage gap, never a silent
|
|
935
|
+
pass — or a restored baseline that did not reproduce
|
|
936
|
+
green; a failure, never a pass). Rule-3 containment is enforced on REALPATHS: an entry whose file
|
|
937
|
+
resolves outside the scratch copy (a symlink escape — writing would mutate the REAL tree) is
|
|
938
|
+
refused with exit 2, and a registry `file` under `node_modules/` is refused outright.
|
|
939
|
+
The red/green verdict rides the suite's EXIT CODE; failing-test counts are
|
|
940
|
+
a best-effort secondary (TAP `# fail N`, vitest/jest summaries) used only for `BELOW_MIN` and the
|
|
941
|
+
COVERAGE-DROP warning — count-parse failure never decides a verdict. A drop (`failing < observed`
|
|
942
|
+
but still ≥ `minFailing`) WARNS loudly instead of failing: `observed` is history, `minFailing` is
|
|
943
|
+
the contract; history drifting down while the contract holds is the early warning that arrives
|
|
944
|
+
before the property breaks.
|
|
945
|
+
|
|
841
946
|
### Portable delivery gate — `dz delivery-check` (Step-10, on every shell target)
|
|
842
947
|
|
|
843
948
|
The feature-adr Step-10 Delivery Gate reviews a landed feature across four orthogonal planes and
|
|
@@ -988,7 +1093,76 @@ Get the whole set with `dz init --target claude-code --preset meta`, or pick one
|
|
|
988
1093
|
|
|
989
1094
|
> **A skill and its npx toolkit are not duplicates — they're a graduation.** Several skills (e.g. `feature-adr`, `design-thinking`) exist BOTH as a skill inside a `dz` preset AND as a standalone `npx` package. The preset's SKILL.md is **fully functional on its own** (the whole methodology — modules + references — travels with it, and it auto-activates by description), and it's the only way to compile that capability to the **non-Claude platforms** (Codex/OpenCode/Hermes/OpenClaude) via `dz`. The npx package adds **project-level runtime governance** around the same skill: a slash command, governance rules, a context shard, and (for feature-adr) reward-learning + `/harvest`. So: pick the **skill/preset** for a working capability across platforms; pick the **npx toolkit** when you want it as a governed, command-driven fixture of one project.
|
|
990
1095
|
|
|
991
|
-
##
|
|
1096
|
+
## Design custom Workflow loops (`workflow` · `workflow-lint` · `workflow-trace`)
|
|
1097
|
+
|
|
1098
|
+
Custom loops used to be born by copy-pasting a 1470-line workflow script; nothing deterministic
|
|
1099
|
+
checked the copy. The loop-designer meta-factory replaces that: a versioned typed plan
|
|
1100
|
+
(`loop-plan/1`), a schema-driven generator, a 17-rule lint gate, and a local trace plane.
|
|
1101
|
+
|
|
1102
|
+
```bash
|
|
1103
|
+
# 1. Scaffold a plan (pipeline | barrier | fanout | gate), edit the TODO prompts:
|
|
1104
|
+
dz workflow init --name triage-loop --pattern barrier --o triage-loop.plan.json
|
|
1105
|
+
# → dz workflow init: wrote /abs/triage-loop.plan.json (pattern: barrier)
|
|
1106
|
+
|
|
1107
|
+
# 2. Validate it (CI-runnable; INV-1..8 — unbounded fanout, dangling deps, retry-on-non-idempotent
|
|
1108
|
+
# are all hard failures):
|
|
1109
|
+
dz workflow validate triage-loop.plan.json
|
|
1110
|
+
# → dz workflow validate: OK (digest sha256:1df9e5582f8ec888…)
|
|
1111
|
+
|
|
1112
|
+
# 3. Render the executable loop (sidecar plan first, then the script; USER regions survive
|
|
1113
|
+
# re-renders byte-for-byte; a marker-less hand-written target is REFUSED without --force):
|
|
1114
|
+
dz workflow render triage-loop.plan.json --o triage-loop.js
|
|
1115
|
+
# → dz workflow render: wrote …/triage-loop.plan.json then …/triage-loop.js (exec-fp sha256:…, blobs: checkpoints, trace)
|
|
1116
|
+
|
|
1117
|
+
# 4. Gate it (generated-loop CI mode; exit 0/1/3 — inconclusive is NEVER a pass):
|
|
1118
|
+
dz workflow-lint triage-loop.js --plan triage-loop.plan.json --require-plan
|
|
1119
|
+
# → dz workflow-lint: PASS (mode=require-plan; 0 fail, 0 warn, 0 inconclusive over 17 rules)
|
|
1120
|
+
|
|
1121
|
+
# 5. Run it via Workflow({scriptPath:'triage-loop.js', args:{traceDir:'/abs/run-dir'}}), then read
|
|
1122
|
+
# the run's own trace (seq-ordered; wallTime is diagnostic only):
|
|
1123
|
+
dz workflow-trace /abs/run-dir --invariants triage-loop.plan.json --html report.html
|
|
1124
|
+
# → run fitness-run-1; sources: trace, … + INVARIANT PASS rows + a self-contained report.html
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
**When to use:** any new multi-agent Workflow loop (a pipeline over items, blind parallel lanes
|
|
1128
|
+
behind a barrier, a bounded fanout, a gated produce-check loop) — instead of copy-pasting
|
|
1129
|
+
`feature-adr.js`. `dz workflow-lint --legacy` also runs over hand-written loops (plan-anchored
|
|
1130
|
+
rules honestly report `inconclusive` there, never a silent green). `dz workflow blobs --check`
|
|
1131
|
+
self-checks the shared-subsystem blob registry (checkpoints, model-resolver, trace, …) that the
|
|
1132
|
+
generator injects verbatim — edit the canonical TS in harness-core, regenerate, never the copies.
|
|
1133
|
+
|
|
1134
|
+
**Scope, stated plainly: `dz` AUTHORS, GATES and READS loops — it never RUNS one.** There is no
|
|
1135
|
+
`dz workflow run`, and step 5 above is not a `dz` command: execution belongs to the Claude Code
|
|
1136
|
+
host's `Workflow({scriptPath})` runtime, which owns the agent dispatch the generated script calls
|
|
1137
|
+
into. So every claim on this page is about the plan, the generated script, the lint verdict, and the
|
|
1138
|
+
run's own trace file — not about runtime behaviour `dz` could observe itself. `dz workflow-trace`
|
|
1139
|
+
reads what a HOST run already wrote (`trace.jsonl`, seq-ordered by the loop's own counter); with no
|
|
1140
|
+
host run there is nothing to read, and it says so rather than inventing a timeline. Portability
|
|
1141
|
+
follows from the same boundary: on a non-Claude-Code target the authoring and lint verbs work
|
|
1142
|
+
unchanged, and only execution is absent.
|
|
1143
|
+
|
|
1144
|
+
**The v1 plan surface is deliberately NARROW and fully enacted** — `dz workflow validate` REJECTS
|
|
1145
|
+
(named diagnostics, never a silent no-op) anything the generated loop would not perform: retry
|
|
1146
|
+
timing (`initialDelayMs`/`backoffMultiplier`/`maxDelayMs`/`jitter` — v1 retries are immediate;
|
|
1147
|
+
`ENACT-RETRY-TIMING`), non-inline dispatch routes (`codex-wrapper`/`codex-exec`;
|
|
1148
|
+
`ENACT-DISPATCH`), per-step checkpoint granularity and `checkpointing.schemaVersion`
|
|
1149
|
+
(`ENACT-CKPT-OPT` — checkpointing is all-or-nothing per run, schema stamp pinned), plus caching,
|
|
1150
|
+
jitterless subsystems and branch schemas as before (`ENACT-*`). It also enforces required-field
|
|
1151
|
+
presence per record kind (an absent `fanouts[].stage` is a parse error, not a zero-agent run),
|
|
1152
|
+
unique stepIds that lower to DISTINCT generated identifiers (`a-b` and `a.b` no longer collide in
|
|
1153
|
+
the generated script — the lowering is collision-resistant, not injective, and `IDENT-1` is the
|
|
1154
|
+
parse check that actually rejects a collision),
|
|
1155
|
+
and dependency order at EFFECTIVE execution positions (a fanout member executes at its region's
|
|
1156
|
+
position, not its declaration index). The schema is CLOSED-WORLD: an unknown non-`x-` key is a
|
|
1157
|
+
parse error at every level (so a typo like `trcae`, or a second spelling like `retry.delayMs` /
|
|
1158
|
+
`dispatchRoute`, fails loudly instead of parsing and doing nothing), `x-` vendor keys are accepted
|
|
1159
|
+
only at their documented scopes (plan + step), and `fanouts[].registry` items must live in the same
|
|
1160
|
+
ItemKey domain the trace plane enforces — `trace.emit` can never decide whether a valid plan runs.
|
|
1161
|
+
Deferred options are on the loop-designer roadmap.
|
|
1162
|
+
|
|
1163
|
+
## All Commands (66)
|
|
1164
|
+
|
|
1165
|
+
*(66 MEASURED — reproducer: `grep -c "^ case '" src/cli.ts`, the dispatch cases.)*
|
|
992
1166
|
|
|
993
1167
|
```
|
|
994
1168
|
dz setup --target <name> [--preset <name>] [--select id,id,...] [--skills-dir <dir>] [--memory agentdb] [--no-memory] [--no-hooks] [--install-driver] [--force]
|
|
@@ -1000,7 +1174,7 @@ dz teach --reinforce "<dzId-or-exact-text>" [--project <dir>] # bump an existing
|
|
|
1000
1174
|
dz teach --from-json <file> [--project <dir>] [--no-mirror] [--harmonize] # bulk-import a `dz recall --all --json` export; prints a harmonize dry-run advisory
|
|
1001
1175
|
dz consolidate [--sessions-dir <dir>] [--project <dir>] [--no-mirror]
|
|
1002
1176
|
dz recall "<query>" [--limit <N>] [--domain <name>] [--semantic | --no-semantic] [--project <dir>] # hybrid lexical+vector when the vector tier is enabled; --domain BOOSTS same-domain lessons (never filters)
|
|
1003
|
-
dz recall --all [--json] [--stats]
|
|
1177
|
+
dz recall --all [--json] [--stats] [--include-domain <name,…>] # export the learned store (held-out domains are withheld unless named), or inspect learning stats/top uses
|
|
1004
1178
|
dz recall --books "<query>" [--book <slug>] # digitized-book KUs; --book narrows to one book
|
|
1005
1179
|
dz vector status [--project <dir>] [--json] # semantic tier: engine availability, mirrored vs lexical counts, pending queue
|
|
1006
1180
|
dz vector reindex [--project <dir>] [--json] # re-embed learned vectors with the CONFIGURED model + stamp the manifest (snapshot first; atomic — a mid-way failure restores the store). Warns about task types it does not own (e.g. book-knowledge → run `dz brain reindex`)
|
|
@@ -1044,6 +1218,7 @@ dz challenge --plan <plan.md> [--json] [--context-only] [--author <model>] # a
|
|
|
1044
1218
|
dz routing [--stage <s>] [--json] # inspect the learned cost-optimal routing store: what `args.models.<stage>='auto-cost'` believes per (stage, complexity-tier, model) — gated attempts/successes/rate (feeds feature-adr model selection)
|
|
1045
1219
|
dz bto-optimize --split|--plan|--select|--scope-check|--diff [--json] # deterministic engine behind /bto-optimize: hold-out split + hard-capped budget + no-regress-on-holdout winner selection (defeats judge-gaming); prose-only, diff-confirmed, never auto-writes
|
|
1046
1220
|
dz discrimination-check --test <f[,f]> [--base <ref>] [--name <filter>] [--runner <cmd>] [--json] # §42 test-discrimination gate for feature-adr Step-8: run the ADR's property test in an isolated git worktree at pre-feature base — it MUST go red without the fix; a green is a false green (HIGH finding, advisory, never auto-aborts)
|
|
1221
|
+
dz mutation-gate [--package <dir>] [--registry <file>] [--test-cmd "<cmd>"] [--only <id[,id]>] [--timeout <ms>] [--rebaseline per-entry|final] [--keep-scratch] [--json] # the mutation gate: for each NAMED protection in a declarative registry, copy the package to a scratch dir (shadow-repo layout, node_modules symlinked, git-initialized), verify the baseline is green, apply the entry's exact {find, replace} mutation, run the suite, REQUIRE red, restore — and require the red to be ATTRIBUTABLE to the protection: a mutated file that no longer parses is MUTATION_UNPARSEABLE, a failing count far above the entry's bound (maxFailing, default from observed) is OVER_FAILING, and a restored tree that does not reproduce green makes the entry INCONCLUSIVE (flaky suite). 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
|
|
1047
1222
|
dz delivery-check --slug <slug> [--context-only] [--findings <f.json>] [--strict] [--author <model>] [--json] # portable Step-10 Delivery Gate: the `manual` form that travels to every shell target — prints the 4-plane review brief (regressions ‖ security ‖ code-quality ‖ product-honesty) + artifact probes; --findings classifies a fed-back review into a fail-closed ready|blocked hand-off (only cross-validated BLOCKER/HIGH count) and writes features/<slug>/10_delivery_review.md; --strict exits 1 on blocked
|
|
1048
1223
|
dz skills-verify [--dir <project>] [--expect a,b] [--static] [--strict] [--timeout <s>] [--json] # does .claude/skills/ actually REGISTER? --static = instant layout scan (CI-safe, no session): flags dirs that can never register; default also starts a real session and reads the authoritative system/init listing. exit 0 pass / 1 fail / 2 inconclusive — an unobservable registration is NEVER a pass
|
|
1049
1224
|
dz compounding [--project <dir>] [--json] # honest learning-loop payoff report: pool write-only ratio, guard repeat-violation trajectory (rate per audit-half), cold-vs-warm replay readiness over unique untruncated prompt events, apply-leg staleness, and EVENT-CHAIN health of the two evidence logs (verified / defects / uncovered pre-chain prefix) — a gate without enough data says INSUFFICIENT_DATA, never a verdict
|
|
@@ -1053,7 +1228,7 @@ dz epoch-replay --judge <filled-work-order.json> [--out <file>] [--json] # bli
|
|
|
1053
1228
|
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
|
|
1054
1229
|
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
|
|
1055
1230
|
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
|
|
1056
|
-
dz backlog <sub> add "<idea>" | list | show <id> | goals [--validate] | roulette [--seed n] [--commit <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 (DUPLICATE≥0.92
|
|
1231
|
+
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)
|
|
1057
1232
|
dz sign --init --out <path> | --pack <dir> --key <path> # --init: generate the Ed25519 keypair (private OUTSIDE the repo, prints the public key for keys/dz.pub); else sign a pack's manifest + CycloneDX SBOM
|
|
1058
1233
|
dz sbom --pack <dir> [--out <file>] # emit the CycloneDX 1.5 SBOM for a pack standalone (file-level bill of materials); print to stdout or write to a file
|
|
1059
1234
|
dz guard check --op <publish|teach|consolidate|reindex> [--text <s>] [--json] [--force <reason>] # declarative constraint layer before self-mutating ops: HARD violation → block (exit 1), SOFT → warn; zero-config defaults, .dz/guard.json to customise; dz guard --init | dz guard log (append-only audit). dz publish runs it automatically (--no-guard "<reason>" = logged escape hatch)
|
|
@@ -1067,7 +1242,9 @@ dz sync-upstream [--package <dir>] [--list] [--all]
|
|
|
1067
1242
|
dz drift-check [--all] [--json] [--project <dir>] # CI gate: exit 1 on NEW shared-skill drift (baseline: .dz/drift-allowlist.json; --all incl .claude dogfood)
|
|
1068
1243
|
dz sync-canonical <skill> [--check] [--from <dir>] [--auto] [--project <dir>] # heal every copy from skills-meta/<skill> or --from; no canonical + --check = compare copies to each other (exit 1 on drift); no canonical + write = refuse unless --auto (LOUD, picks most-complete copy); --check writes nothing
|
|
1069
1244
|
dz scout [--topics <list>] [--since <date>] [--deep] [--output <file>] [--diff] [--report]
|
|
1070
|
-
dz workflow --
|
|
1245
|
+
dz workflow init --name <n> [--pattern pipeline|barrier|fanout|gate] [--o <plan.json>] | validate <plan.json> [--json] | render <plan.json> --o <script.js> [--check] [--force] | blobs [--check] # loop-plan/1 authoring (the ADR-005 templates are retired)
|
|
1246
|
+
dz workflow-lint <script.js> [--plan <plan.json>] [--require-plan|--legacy] [--json] # 17-rule deterministic gate; exit 0/1/3 — inconclusive is never a pass
|
|
1247
|
+
dz workflow-trace <runDir|--slug <s>|--run <id>> [--invariants <plan.json>] [--html <out.html>] [--json] # timeline + SEQ invariant runner over the loop's own trace.jsonl
|
|
1071
1248
|
dz plugin [--version <ver>]
|
|
1072
1249
|
dz downloads
|
|
1073
1250
|
dz migrate [--project <dir>]
|
|
@@ -1126,6 +1303,38 @@ distills new learnings. It's **opt-in** and **non-clobbering**: `--install` merg
|
|
|
1126
1303
|
existing `statusLine` config rather than overwriting it, and nothing changes until you run it.
|
|
1127
1304
|
Modeled on the Agentic QE statusline pattern (e.g. AQE's `🎓 12 patterns`).
|
|
1128
1305
|
|
|
1306
|
+
#### Live run segment — `dz statusline --fa-record`
|
|
1307
|
+
|
|
1308
|
+
A long-running pipeline can PREPEND its own segment to that line, so the bar shows what is in
|
|
1309
|
+
flight rather than only the standing pattern count. The `/feature-adr` pipeline records its
|
|
1310
|
+
Pattern-memory state at each step; a generated `loop-designer` loop records its current step on
|
|
1311
|
+
every trace flush:
|
|
1312
|
+
|
|
1313
|
+
```bash
|
|
1314
|
+
# the /feature-adr pipeline — reports the learning loop it is actually running
|
|
1315
|
+
dz statusline --fa-record --slug add-user-auth --step "Step 8 QE" --recalled 7 --stored 2 --mode full
|
|
1316
|
+
|
|
1317
|
+
# a generated loop — same file, different producer, so it says so
|
|
1318
|
+
dz statusline --fa-record --slug my-loop --step build --kind loop
|
|
1319
|
+
```
|
|
1320
|
+
|
|
1321
|
+
```
|
|
1322
|
+
📐 feature-adr Step 8 QE · 🎓 224 pool · ↑7 used · +2 new · ↻0 reinforced · 🎓 dz: 224 patterns · 🧠 3 sources
|
|
1323
|
+
🔁 loop build · 🎓 dz: 224 patterns · 🧠 3 sources
|
|
1324
|
+
```
|
|
1325
|
+
|
|
1326
|
+
`--kind <feature-adr|loop>` names the PRODUCER and defaults to `feature-adr`; an unrecognised value
|
|
1327
|
+
exits 1 rather than silently weakening panel arbitration. It is load-bearing in two places:
|
|
1328
|
+
|
|
1329
|
+
- **the label**: a loop renders `🔁 loop <step>` and shows **no** learning counters, because a loop
|
|
1330
|
+
never populates them — a `↑0 used` there would be a false statement about the Pattern-memory loop
|
|
1331
|
+
rather than a measurement of it;
|
|
1332
|
+
- **the arbitration**: each producer writes its own per-slug slot under
|
|
1333
|
+
`.dz/feature-adr/learning-state/`, and a fresh `feature-adr` state outranks any `loop` state, so a
|
|
1334
|
+
loop running alongside a live pipeline can no longer blank that pipeline's counters. Slots are
|
|
1335
|
+
discovered newest-first, nothing older than 30 minutes is surfaced, and the write path prunes at
|
|
1336
|
+
24 h. Use `--project <dir>` to pin the panel to a specific project root.
|
|
1337
|
+
|
|
1129
1338
|
### Usage estimate (`dz usage`)
|
|
1130
1339
|
|
|
1131
1340
|
`dz usage` prints a READONLY, never-throw ESTIMATE of Claude SESSION and WEEKLY token usage,
|
|
@@ -1457,6 +1666,18 @@ dz backlog add "add a compounding metric to strengthen dz recall" --effort 3
|
|
|
1457
1666
|
# A RELATED/DUPLICATE verdict now names the pair, so you can calibrate the 0.92 band on real data:
|
|
1458
1667
|
# dz backlog: RELATED — captured 67c5883e…
|
|
1459
1668
|
# top match 9286f5eb… @ cosine 0.793 (DUPLICATE band ≥ 0.92)
|
|
1669
|
+
# Dedup is TWO-SIGNAL (register-inflation fix, measured on the real store): the embedding compares a
|
|
1670
|
+
# BOUNDED 400-char excerpt (full-length embeds of long same-register texts scored unrelated pairs up
|
|
1671
|
+
# to 0.9195 while true paraphrases of the same ideas scored 0.35–0.61 — the signal was inverted), and
|
|
1672
|
+
# a DUPLICATE verdict additionally needs shared subject vocabulary (lexical containment ≥ 0.3):
|
|
1673
|
+
# near-duplicate demoted: 977e9dcb… @ cosine 0.941 cleared the band but shares no subject
|
|
1674
|
+
# vocabulary (containment 0.077 < 0.3) — kept as related
|
|
1675
|
+
# The same containment signal works the other way too: a re-capture of an existing idea at a
|
|
1676
|
+
# different LENGTH (containment ≥ 0.95, cosine ≥ 0.75) is a duplicate even below the 0.92 band
|
|
1677
|
+
# ("subset match"). Knobs: backlog.dedup.{corroborationFloor,subsetContainment,subsetCosineFloor}
|
|
1678
|
+
# in .dz/config.json. On first use after the fix the mirrored idea vectors are re-embedded once into
|
|
1679
|
+
# the bounded form ("re-embedded N idea vector(s)…"); a DUPLICATE absorption also keeps the full
|
|
1680
|
+
# incoming text in .dz/backlog/absorbed.jsonl, so a wrong verdict is reversible (re-add from there).
|
|
1460
1681
|
# An out-of-scale --effort is ECHOED, never silently clamped:
|
|
1461
1682
|
dz backlog add "an idea I mis-scaled" --effort 13
|
|
1462
1683
|
# → dz backlog: effort 13 → clamped to 5 (scale 1-5)
|
|
@@ -1484,6 +1705,19 @@ dz backlog roulette --seed 7
|
|
|
1484
1705
|
dz backlog roulette --commit 268d3cb1 # → 268d3cb1 · → in-progress
|
|
1485
1706
|
dz backlog roulette 268d3cb1 # → refused (exit 1): "an idea id alone does not start it"
|
|
1486
1707
|
|
|
1708
|
+
# 3c. FINISHED the work? Say so — or the roulette keeps re-drawing it forever. Most work happens
|
|
1709
|
+
# WITHOUT a --commit (spin, see the pick, just do it), so `ship` is the verb that closes the loop.
|
|
1710
|
+
# Short 8-char prefixes (what the roulette prints) resolve if unique; ambiguous/unknown = loud
|
|
1711
|
+
# exit-1 error, never a silent no-op. Batches are all-or-nothing.
|
|
1712
|
+
dz backlog ship 268d3cb1 --reason "shipped in harness-core 0.3.151"
|
|
1713
|
+
# → dz backlog ship: 268d3cb1… new → shipped add a compounding metric …
|
|
1714
|
+
# (shipping an already-shipped idea is a SAID no-op, exit 0 — safe in cleanup batches)
|
|
1715
|
+
dz backlog drop 9286f5eb --reason "superseded by 268d3cb1" # retire without shipping (→ dropped)
|
|
1716
|
+
dz backlog reopen 268d3cb1 # changed your mind → back to the pool (new)
|
|
1717
|
+
# reopen on an already-new idea is REFUSED (exit 1) — that is almost always the wrong id.
|
|
1718
|
+
# Terminal→terminal never happens silently: ship on a dropped idea (or drop on shipped) is refused;
|
|
1719
|
+
# go through reopen first. --dry-run previews any of the three without writing.
|
|
1720
|
+
|
|
1487
1721
|
# 4. Work it: stage an idea2prd hand-off (writes the PRD-pipeline input scaffold)
|
|
1488
1722
|
dz backlog enrich 268d3cb1 # → features/<slug>/ scaffold; run the idea2prd-manual skill on it
|
|
1489
1723
|
|
|
@@ -1505,9 +1739,55 @@ agentdb memory backend installed the dedup honestly degrades to exact-text and a
|
|
|
1505
1739
|
dz install @dzhechkov/skills-devops
|
|
1506
1740
|
dz install @dzhechkov/skills-web3 --target openclaude
|
|
1507
1741
|
dz install @lythos/skill-curator --target claude-code
|
|
1742
|
+
dz install @dzhechkov/skills-analyst-manual # npx-init pack — works too
|
|
1508
1743
|
```
|
|
1509
1744
|
|
|
1510
|
-
Runs `npm install`,
|
|
1745
|
+
Runs `npm install`, resolves where the package keeps its skills, and compiles them into the
|
|
1746
|
+
target platform directory. Works with any agentskills.io-compatible npm package, in **any of
|
|
1747
|
+
the three known layouts** (probed in order, first non-empty wins):
|
|
1748
|
+
|
|
1749
|
+
| Layout | Skills live at | Example packs |
|
|
1750
|
+
|---|---|---|
|
|
1751
|
+
| `flat` | `<pkg>/<skill>/SKILL.md` | skills-devops, skills-qe, skills-ecc |
|
|
1752
|
+
| `npx-template` | `<pkg>/templates/.claude/skills/<skill>/SKILL.md` | skills-analyst-manual, keysarium, skills-feature-adr |
|
|
1753
|
+
| `skills-dir` | `<pkg>/skills/<skill>/SKILL.md` | health-advisor, evidence-wiki |
|
|
1754
|
+
|
|
1755
|
+
Real npx-init-pack run (captured):
|
|
1756
|
+
|
|
1757
|
+
```bash
|
|
1758
|
+
$ dz install @dzhechkov/skills-analyst-manual
|
|
1759
|
+
Installing @dzhechkov/skills-analyst-manual...
|
|
1760
|
+
dz install @dzhechkov/skills-analyst-manual: 4 skill(s), 18 file(s) written, 0 skipped [layout: npx-template]
|
|
1761
|
+
analyst-manual-full: 1 written, 0 skipped
|
|
1762
|
+
explore: 3 written, 0 skipped
|
|
1763
|
+
goap-research-ed25519: 13 written, 0 skipped
|
|
1764
|
+
problem-solver-enhanced: 1 written, 0 skipped
|
|
1765
|
+
note: @dzhechkov/skills-analyst-manual also ships commands/hooks/agents — `npx -y @dzhechkov/skills-analyst-manual init` installs the full kit.
|
|
1766
|
+
```
|
|
1767
|
+
|
|
1768
|
+
The `[layout: …]` tag appears for non-flat layouts so the resolution is observable; classic
|
|
1769
|
+
flat packs print exactly what they always did. The `note:` line appears only when the pack
|
|
1770
|
+
ships companion assets (slash commands, hooks) that `dz install` does not install — for the
|
|
1771
|
+
full claude-code kit of such a pack, `npx -y <pkg> init` remains the richer path, while
|
|
1772
|
+
`dz install --target codex|cursor|opencode|…` compiles the same skills for the non-claude
|
|
1773
|
+
targets, which the pack's own installer does not do (MEASURED — its installer copies
|
|
1774
|
+
`templates/.claude/**` only; reproducer: `src/utils.js` `COMPONENTS` in
|
|
1775
|
+
`@dzhechkov/skills-analyst-manual`).
|
|
1776
|
+
|
|
1777
|
+
A package with **no** skills in any known layout now fails loudly — `exit 1` with the probed
|
|
1778
|
+
paths named (MEASURED — reproducer: `npx vitest run test/install-layouts.test.ts`, case
|
|
1779
|
+
T5.2; the pre-fix behavior was a misleading `exit 0` advisory):
|
|
1780
|
+
|
|
1781
|
+
```bash
|
|
1782
|
+
$ dz install @dz/broken-pack
|
|
1783
|
+
Installing @dz/broken-pack...
|
|
1784
|
+
dz install: no SKILL.md found in @dz/broken-pack. Probed: ., templates/.claude/skills, skills.
|
|
1785
|
+
If this package installs itself, try: npx -y @dz/broken-pack init
|
|
1786
|
+
```
|
|
1787
|
+
|
|
1788
|
+
When to use: first install of any skills pack. If you previously hit
|
|
1789
|
+
`no SKILL.md files found` on an npx-init pack (e.g. `@dzhechkov/skills-analyst-manual`) —
|
|
1790
|
+
that resolver bug is fixed; `dz install` now handles those packs directly.
|
|
1511
1791
|
|
|
1512
1792
|
### dz sync-upstream — check for upstream updates
|
|
1513
1793
|
|
|
@@ -2218,7 +2498,7 @@ invariants: HARD rules **block** the operation, SOFT rules warn. Zero config nee
|
|
|
2218
2498
|
cover the known rakes; `.dz/guard.json` (via `dz guard --init`) exists only if you want to tune a severity
|
|
2219
2499
|
or disable a rule.
|
|
2220
2500
|
```bash
|
|
2221
|
-
dz guard check --op publish # no-workspace-star · no-skill-drift · no-secrets · readme-consistency · readme-first · skills-registrable · lockfile-in-sync
|
|
2501
|
+
dz guard check --op publish # no-workspace-star · no-skill-drift · no-secrets · readme-consistency · readme-first · skills-registrable · lockfile-in-sync · no-stubs · licence-hold
|
|
2222
2502
|
dz guard check --op teach --text "the fix: export sk-abc..." # → BLOCK (exit 1): looks like a credential
|
|
2223
2503
|
dz guard log # append-only audit: every verdict + every forced override
|
|
2224
2504
|
```
|
|
@@ -2253,6 +2533,111 @@ zero specifiers, and then report every real dependency as "not recorded". The ru
|
|
|
2253
2533
|
`.dz/guard.json` cannot promote it to HARD, since a parser designed to admit "I may not understand this
|
|
2254
2534
|
file" must never be able to block a publish.
|
|
2255
2535
|
|
|
2536
|
+
**`licence-hold` (HARD, publish)** — the machine side of a licence precondition (ADR-001 of feature
|
|
2537
|
+
`hermes-claude-adaptation`, first holder: `@dzhechkov/cloudru-hub`). A pack that declares
|
|
2538
|
+
`package.json.licenseHold` is parked behind two belts: while it stays `private:true` the npm layer
|
|
2539
|
+
refuses it and this rule stays silent (other packs publish unblocked); the moment `private` is dropped
|
|
2540
|
+
with the hold unsatisfied, publish is HARD-blocked:
|
|
2541
|
+
|
|
2542
|
+
```
|
|
2543
|
+
[BLOCK] licence-hold: @dzhechkov/cloudru-hub: publishable (private flag removed) but the ADR-001
|
|
2544
|
+
licence hold is UNSATISFIED — LICENSE still carries the PENDING grant placeholder; LICENSE
|
|
2545
|
+
has no "Grant-Confirmation: <url>" line; package.json license "SEE LICENSE IN LICENSE" is
|
|
2546
|
+
not a clean SPDX id
|
|
2547
|
+
```
|
|
2548
|
+
|
|
2549
|
+
Satisfying the hold — a real LICENSE (no `<!-- PENDING:` placeholder, a `Grant-Confirmation: <url>`
|
|
2550
|
+
line), non-empty `THIRD_PARTY_NOTICES`, and a clean SPDX `license` field — makes the rule pass with the
|
|
2551
|
+
trigger field still in place. Discrimination MEASURED 2026-08-10 (reproducer: flip `private` in
|
|
2552
|
+
`packages/@dzhechkov/cloudru-hub/package.json`, run `dz publish --dry-run` → exit 1 BLOCKED; restore →
|
|
2553
|
+
pass; satisfied scratch copy → pass).
|
|
2554
|
+
|
|
2555
|
+
**`no-stubs` (SOFT, publish)** — a deterministic scan for unfinished-stub markers (`TODO` / `FIXME` /
|
|
2556
|
+
`HACK` / `XXX` / `PLACEHOLDER` / the phrase `implement later`) left in the files of the **current
|
|
2557
|
+
change-set** (backlog 0b403a0106103901, Karpathy-Michaels rule XI). A stub in code you are about to
|
|
2558
|
+
publish means the task shipped incomplete — and until this rule that was caught only by a reviewer's
|
|
2559
|
+
judgment (layer 4 on the cost-of-detection ladder); a grep is layer 1. Scope is the working-tree diff
|
|
2560
|
+
**on purpose**: MEASURED 2026-08-10, a whole-tree case-insensitive scan of this repo yields 32 src/lib
|
|
2561
|
+
hits + 25 test/fixture hits, the clear majority ancient and legitimate — a tree-wide gate would be
|
|
2562
|
+
switched off as noise within a day. The gate catches what *you* left in *this* change. Bare markers are
|
|
2563
|
+
matched **case-sensitively** with hard word boundaries (measured: relaxing case doubles the hits and
|
|
2564
|
+
adds only prose — `todo` keyword lists, "placeholder" in comments), so `hackathon`, `todos`, and a
|
|
2565
|
+
marker inside a hash never fire; in markdown, fenced blocks and backticked spans are treated as QUOTES
|
|
2566
|
+
of a marker, not stubs, so a doc explaining this very gate scans clean.
|
|
2567
|
+
|
|
2568
|
+
```bash
|
|
2569
|
+
$ printf '// %s: finish the retry path\n' 'TODO' >> src/retry.ts
|
|
2570
|
+
$ dz guard check --op publish
|
|
2571
|
+
dz guard (publish): ⚠ WARN [checked: … no-stubs …]
|
|
2572
|
+
[warn] no-stubs: src/retry.ts:1: stub marker "TODO" in a changed file — finish it, or waive the
|
|
2573
|
+
line with "no-stubs: <reason>" (or .dz/guard.json stubWaivers with a reason)
|
|
2574
|
+
$ echo $? # SOFT means SOFT: the publish path completes
|
|
2575
|
+
0
|
|
2576
|
+
```
|
|
2577
|
+
|
|
2578
|
+
A marker a change must legitimately carry (a fixture exercising another scanner, a demo) takes an
|
|
2579
|
+
explicit **waiver-with-reason** — inline on the line (`// … no-stubs: fixture exercises the S10 check`)
|
|
2580
|
+
or path-keyed in `.dz/guard.json` (`"stubWaivers": [{"path": "test/fixtures/x.json", "reason": "…"}]`,
|
|
2581
|
+
the same shape as `dz feature-adr-setup --guards`). A waiver **without** a reason is refused loudly and
|
|
2582
|
+
exempts nothing — an exemption you cannot explain is a silent allowlist:
|
|
2583
|
+
|
|
2584
|
+
```
|
|
2585
|
+
[warn] no-stubs: src/retry.ts:1: inline waiver ("no-stubs:") carries NO reason — refused; a waiver
|
|
2586
|
+
you cannot explain is a silent allowlist
|
|
2587
|
+
[warn] no-stubs: src/retry.ts:1: stub marker "TODO" in a changed file — …
|
|
2588
|
+
```
|
|
2589
|
+
|
|
2590
|
+
The rule's own source never trips it **structurally**: every marker in `no-stubs.ts` (and its tests) is
|
|
2591
|
+
assembled from string fragments at load time, so the file contains no literal for the scan to find — a
|
|
2592
|
+
tested property, not a path skip. The same check runs as a Step-8 QE-gate item in the feature-adr
|
|
2593
|
+
pipeline ("any unwaived match over the run's touched files = task incomplete").
|
|
2594
|
+
|
|
2595
|
+
The change-set includes files inside **brand-new untracked directories**: the gatherer runs
|
|
2596
|
+
`git status --porcelain -uall`, so a fresh module directory — the most stub-prone artifact there is —
|
|
2597
|
+
is scanned file-by-file instead of collapsing to one invisible `?? newdir/` line (FN-1, REPRODUCED:
|
|
2598
|
+
before `-uall` a marker in `newdir/stub.ts` published as PASS/0 findings). `.gitignore` semantics are
|
|
2599
|
+
unchanged — git never lists ignored paths, `-uall` or not (tested live).
|
|
2600
|
+
|
|
2601
|
+
**Fail-open, never fail-silent.** A changed scannable file the gatherer does NOT read — deleted,
|
|
2602
|
+
non-regular, over 1 MB, unreadable, or beyond the 400-file cap — still reports no findings (missing
|
|
2603
|
+
evidence is never guessed), but the skip now goes **on the record** as one aggregate note in the
|
|
2604
|
+
verdict, the `--json` output, and the audit log; it is information, never a violation, and cannot
|
|
2605
|
+
change the verdict or the exit code:
|
|
2606
|
+
|
|
2607
|
+
```
|
|
2608
|
+
dz guard (publish): ✓ PASS [checked: … no-stubs …]
|
|
2609
|
+
[note] no-stubs: 1 changed scannable file(s) not scanned (deleted/oversize/unreadable/beyond the
|
|
2610
|
+
file cap) — the stub scan is fail-open, so this is a coverage gap on the record, not a violation
|
|
2611
|
+
```
|
|
2612
|
+
|
|
2613
|
+
**Known limits** (conscious trade-offs, named rather than implied away — each is also documented at
|
|
2614
|
+
the top of `no-stubs.ts`):
|
|
2615
|
+
|
|
2616
|
+
- **Whole-line inline waiver (FN-2).** The `no-stubs: <reason>` token exempts the *entire line* it
|
|
2617
|
+
appears on — any line can be silenced by appending the token. The defence is auditability, not
|
|
2618
|
+
prevention: the token is a fixed greppable string, so every silencing is one grep away. That is a
|
|
2619
|
+
layer-4 defence on the cost-of-detection ladder, and it is named as such deliberately.
|
|
2620
|
+
- **Reason quality is not judged (FN-6).** A junk reason (`.`, `x`) satisfies the reason requirement.
|
|
2621
|
+
The design stops *forgetting* a reason, not *faking* one — a deterministic layer cannot judge honesty;
|
|
2622
|
+
that is review-plane work.
|
|
2623
|
+
- **Markdown fence model (FN-4).** Fence tracking is a single boolean toggle, not CommonMark: a
|
|
2624
|
+
mismatched `~~~`/backtick fence pair, an indented fence, an unclosed fence at EOF (everything after it
|
|
2625
|
+
reads as fenced ⇒ skipped), and a marker on the fence info-string line are all mis-scoped.
|
|
2626
|
+
- **Git-quoted paths (FN-3).** Paths git quotes (spaces, non-ASCII under the default
|
|
2627
|
+
`core.quotePath=true`) are not decoded, match no real file, and are not scanned.
|
|
2628
|
+
- **Extension allowlist (FN-8).** `STUB_SCAN_EXTENSIONS` is a TS-monorepo set: extensionless bin
|
|
2629
|
+
scripts, `Dockerfile`, `Makefile`, `.txt/.html/.css/.vue/.svelte/.c/.cpp/.php/.toml/.sql/.ps1/.kt/.swift`
|
|
2630
|
+
are unscanned — MED risk if this rule template ships into a polyglot repo (the list is exported and
|
|
2631
|
+
testable precisely so it can be extended there).
|
|
2632
|
+
- **Staged-but-not-worktree content (FN-5).** The gatherer reads the working tree; content staged in the
|
|
2633
|
+
index but reverted in the worktree scans as the worktree text — design-consistent for the `publish`
|
|
2634
|
+
op, which packs the worktree.
|
|
2635
|
+
- **Config waivers match the exact path string** — no normalization, no globs; a mis-spelled waiver
|
|
2636
|
+
simply does not match and the finding fires (errs toward firing — the safe side).
|
|
2637
|
+
- **A status listing beyond the raised 32 MB `maxBuffer`** makes the porcelain call throw, which drops
|
|
2638
|
+
the whole `change` fact — no-stubs and every promoted template rule go fail-open together for that
|
|
2639
|
+
run (the standing not-a-git-repo contract; the bound makes it a pathological-tree-only event).
|
|
2640
|
+
|
|
2256
2641
|
#### `dz guard promote` — when a LESSON has earned the right to become a rule
|
|
2257
2642
|
|
|
2258
2643
|
`dz compounding` MEASURED the uncomfortable half of the learning loop (reproducer: `dz compounding
|
|
@@ -2387,6 +2772,38 @@ cut hid. That last one is the subtle part: the boost never drops a hit, but prom
|
|
|
2387
2772
|
the top N does push the last one out of the printed list, so "nothing was dropped" would be true of
|
|
2388
2773
|
the ranked list and false of the one you are reading. The note names the difference instead.
|
|
2389
2774
|
|
|
2775
|
+
### Held-out domains — the export does not hand over everything
|
|
2776
|
+
|
|
2777
|
+
`dz recall --all --json` is the portable sharing form, which makes it the realistic path
|
|
2778
|
+
by which a learned store leaves a machine. Some domains should not travel by default:
|
|
2779
|
+
`health-research` (written by `@dzhechkov/health-advisor`) carries lessons drawn from one
|
|
2780
|
+
person's medical investigations.
|
|
2781
|
+
|
|
2782
|
+
```bash
|
|
2783
|
+
dz recall --all --json
|
|
2784
|
+
# … 178 patterns on stdout, health-research NOT among them
|
|
2785
|
+
# 1 lesson(s) in health-research were HELD BACK from this export — that domain carries
|
|
2786
|
+
# medical research and does not travel by default. To include it deliberately:
|
|
2787
|
+
# --include-domain health-research ← on stderr, so stdout stays parsable
|
|
2788
|
+
|
|
2789
|
+
dz recall --all --json --include-domain health-research # explicit opt-in
|
|
2790
|
+
```
|
|
2791
|
+
|
|
2792
|
+
**Why a domain tag and not a content scan.** The tag is set by the writer and compared
|
|
2793
|
+
after normalisation (`Health_Research` and `health research` are the same domain), so the
|
|
2794
|
+
check is decidable, language-independent, and provable by a test. `health-advisor` first
|
|
2795
|
+
tried to keep patient data out by INSPECTING the lesson text; seven rounds of
|
|
2796
|
+
cross-model review could not make that correct, because "is this about a person?" is a
|
|
2797
|
+
question about meaning. It then filtered each command that emits lesson text, and review
|
|
2798
|
+
produced five more such commands the moment four were closed. What finally held is
|
|
2799
|
+
neither: health lessons are written to a SEPARATE store and never reach this one. The
|
|
2800
|
+
hold-out remains as a second line — and note what it does NOT claim: it governs the
|
|
2801
|
+
export, not the local store, and it does not make any lesson safe to publish.
|
|
2802
|
+
|
|
2803
|
+
The hold-out always says how much it withheld. A silent one would let you believe you had
|
|
2804
|
+
exported the whole store, and would make a BROKEN hold-out look exactly like an empty
|
|
2805
|
+
domain.
|
|
2806
|
+
|
|
2390
2807
|
### Semantic recall (vector tier)
|
|
2391
2808
|
|
|
2392
2809
|
`dz recall` is **hybrid** when the vector tier is available and **exactly the old lexical command** when it is not — enabling it never changes behavior for projects that skip it.
|
|
@@ -2805,7 +3222,7 @@ npx @dzhechkov/p-replicator init
|
|
|
2805
3222
|
|
|
2806
3223
|
## Status
|
|
2807
3224
|
|
|
2808
|
-
`v0.
|
|
3225
|
+
`v0.4.2` — published on npm. Also available as [Claude Plugin](#claude-plugin). Part of [DZ Harness Hub](https://github.com/djd1m/dz-harness-hub).
|
|
2809
3226
|
|
|
2810
3227
|
## Claude Plugin
|
|
2811
3228
|
|
package/dist/bin.js
CHANGED
|
@@ -3,5 +3,15 @@
|
|
|
3
3
|
* `dz` executable entry point.
|
|
4
4
|
*/
|
|
5
5
|
import { runCli } from './cli.js';
|
|
6
|
-
|
|
6
|
+
const code = await runCli(process.argv.slice(2));
|
|
7
|
+
// `process.exit()` here TRUNCATED large output on a pipe, silently and at exactly the
|
|
8
|
+
// pipe buffer size. On a pipe (not a TTY, not a file) Node's stdout is ASYNCHRONOUS, so
|
|
9
|
+
// `process.exit` discards whatever has not flushed yet: `dz recall --all --json > file`
|
|
10
|
+
// wrote 122826 bytes while `dz recall --all --json | jq` got exactly 65536 and a parse
|
|
11
|
+
// error. That is data loss in the documented sharing path, and silent — the exit code
|
|
12
|
+
// was 0 and the JSON simply stopped mid-string.
|
|
13
|
+
//
|
|
14
|
+
// So: set the code and let the process end when the event loop drains, which is what
|
|
15
|
+
// flushes stdout. `process.exitCode` preserves the status without the race.
|
|
16
|
+
process.exitCode = code;
|
|
7
17
|
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAEjD,sFAAsF;AACtF,wFAAwF;AACxF,wFAAwF;AACxF,uFAAuF;AACvF,sFAAsF;AACtF,gDAAgD;AAChD,EAAE;AACF,qFAAqF;AACrF,4EAA4E;AAC5E,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -20,6 +20,13 @@ export interface CliIo {
|
|
|
20
20
|
* without spawning anything.
|
|
21
21
|
*/
|
|
22
22
|
readonly releaseRunner?: ReleaseExecRunner;
|
|
23
|
+
/**
|
|
24
|
+
* Test seam for `dz install`: overrides the `npm install` subprocess (production leaves
|
|
25
|
+
* it unset → real `execSync`, stdio piped). A stub runner that pre-stages a fixture
|
|
26
|
+
* package under `node_modules/` makes `cmdInstall`'s layout resolution testable
|
|
27
|
+
* offline, hermetically — mirrors the {@link CliIo.releaseRunner} idiom.
|
|
28
|
+
*/
|
|
29
|
+
readonly installRunner?: (command: string, cwd: string) => void;
|
|
23
30
|
}
|
|
24
31
|
/** Injected subprocess runner used by `dz release` (see {@link CliIo.releaseRunner}). */
|
|
25
32
|
export type ReleaseExecRunner = (cmd: string, opts: {
|
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;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkbH,2EAA2E;AAC3E,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACjE;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAAG,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KACvD;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAyyQ9E,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAoK5E"}
|