@dzhechkov/harness-cli 0.3.254 → 0.3.257

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 CHANGED
@@ -9,7 +9,7 @@
9
9
  },
10
10
  {
11
11
  "path": "README.md",
12
- "sha256": "fc57c105e5031d2d6751ef08b64769dc463cd79c5cf7637b48bc8cb7190e5b3a"
12
+ "sha256": "7333dd44bcbeb6536e8ee0f0490a57fefca211e706535da7f44cea7012388213"
13
13
  },
14
14
  {
15
15
  "path": "coverage/coverage-final.json",
@@ -41,15 +41,15 @@
41
41
  },
42
42
  {
43
43
  "path": "dist/cli.d.ts.map",
44
- "sha256": "4268f56e38f72625c2c490add4b17ee12d7ff7db991a2090f426afbb026b98a9"
44
+ "sha256": "818293a250cdf1bd10b5d69267b714d9a8ab90017c1fa18de29fc24e28ad8a55"
45
45
  },
46
46
  {
47
47
  "path": "dist/cli.js",
48
- "sha256": "fe24568930cc226e0bad8b4ccba559e2f837bb4cb068c2cc37750b5a10c27a70"
48
+ "sha256": "9c37499ed55b571232b5718c863b83b31f7a79faab46a9dcbe3283b993b1862a"
49
49
  },
50
50
  {
51
51
  "path": "dist/cli.js.map",
52
- "sha256": "4a0b554fab78cd50fc46cff653411b2003b7dd9a4df1b16af6e9f5a0e24379ff"
52
+ "sha256": "6cf537925ccb4b1ffff84c8fd255b487438b78b56a46f9d91d33b25500ae520d"
53
53
  },
54
54
  {
55
55
  "path": "dist/index.d.ts",
@@ -73,7 +73,7 @@
73
73
  },
74
74
  {
75
75
  "path": "package.json",
76
- "sha256": "c6469d0f7539ce6c0a8176d0b795952a667df2b975c9f93c66e7cd6eba843383"
76
+ "sha256": "7abb07cdda09bea2b8e948cecdbaed4579371e8d0e8cee4436e7fcb20f430cdd"
77
77
  },
78
78
  {
79
79
  "path": "src/bin.ts",
@@ -81,7 +81,7 @@
81
81
  },
82
82
  {
83
83
  "path": "src/cli.ts",
84
- "sha256": "13d3946992186e019310c1c8666fd724ce74880b8fda19850eeb8b6e0399e3d7"
84
+ "sha256": "d64af623372238bb5f2ead34e733130d7b013c49058a26f4795f09586b2b5dda"
85
85
  },
86
86
  {
87
87
  "path": "src/index.ts",
@@ -89,12 +89,16 @@
89
89
  },
90
90
  {
91
91
  "path": "test/cli.test.ts",
92
- "sha256": "7d6ba26ec1188db3b3ac89f50b015ba1f0c6117b5c30d99b22da41da10c96c12"
92
+ "sha256": "555aed692218a73f23a343df2f2b38ce028e694dd9d4aff37e727096f88eb50e"
93
93
  },
94
94
  {
95
95
  "path": "test/epoch-replay-cli.test.ts",
96
96
  "sha256": "a5a48585b565288ca1ea96030b02b2ccb37a621ef7b3cfe54cd7aaa7164d6904"
97
97
  },
98
+ {
99
+ "path": "test/guard-promote-cli.test.ts",
100
+ "sha256": "f8e35085106a98be239104394539c3aec350123eed4a115abf14acc2cb6b5bb9"
101
+ },
98
102
  {
99
103
  "path": "tsconfig.json",
100
104
  "sha256": "e80ef2911c3347a713dc3dca6a5f6034d91e938e58e71345ea920dd9833bcdbb"
@@ -105,5 +109,5 @@
105
109
  }
106
110
  ]
107
111
  },
108
- "signature": "lRzsYJCin4HX25rutyyh0Veo7d29P+AOTtJyKdgPcBrzIY44kdm7AHYRYCKcTrH5esXg8nVfhxd1Uw74PjtZAg=="
112
+ "signature": "SGosjJne1+J5lgK/bAptsnGAciI95Bi4z2zHjB1QC8yWic0SGvKE3rj2mZqvjBfwmwzxvpmYBv/laFmWIQEtAw=="
109
113
  }
package/README.md CHANGED
@@ -456,6 +456,8 @@ $ dz compounding
456
456
  ↓ readme-first: 49 → 4
457
457
  COLD-VS-WARM REPLAY: 2 unique prompt event(s); 5 needed — queries are recorded as of 2026-07-28
458
458
  INSTRUMENTATION: last apply-leg record … — live
459
+ EVIDENCE CHAIN .dz/recall-usage.jsonl: verified · 3 chained · 133 pre-chain (uncovered)
460
+ EVIDENCE CHAIN .dz/guard-audit.jsonl: verified · 3 chained · 82 pre-chain (uncovered)
459
461
  ```
460
462
 
461
463
  Three honesty rules are load-bearing:
@@ -469,6 +471,47 @@ The prompt queries that make replay possible stay on your machine: `.dz/recall-u
469
471
  git-ignored, entries are truncated at 200 chars and flagged when truncated (a prefix is not a prompt,
470
472
  so flagged rows never count as replayable).
471
473
 
474
+ #### Is the evidence itself intact? — the event chain
475
+
476
+ Every number above is computed from two JSONL files, and a compaction bug already inflated one of
477
+ them once (read totals grew `2 → 4 → 6` across three compactions, fixed 2026-07-28). So each record
478
+ appended to `.dz/recall-usage.jsonl` and `.dz/guard-audit.jsonl` now carries a sequence number and a
479
+ hash of the line before it, and both `dz compounding` and `dz doctor` verify the chain:
480
+
481
+ ```
482
+ $ dz compounding | grep 'EVIDENCE CHAIN'
483
+ EVIDENCE CHAIN .dz/recall-usage.jsonl: verified · 3 chained · 133 pre-chain (uncovered)
484
+
485
+ $ dz doctor # silent while clean; on damage:
486
+ [XX] evidence chain (.dz/guard-audit.jsonl) - 1 defect(s): BrokenLink@L3 —
487
+ learning verdicts computed from this log are unsafe
488
+ ```
489
+
490
+ Defects are named, not lumped: `BrokenLink` (an edited or lost record), `DuplicateSeq` (a duplicated
491
+ record, or two writers racing), `NonMonotonicSeq` (an unrecorded restart), `TornTail` (a partial
492
+ write), `DoubleCounted` (a rewrite that emits more events than it read — the `2 → 4 → 6` class),
493
+ plus three that keep a rewrite from certifying itself: `LedgerImbalance`, `MalformedLedger` and
494
+ `ClaimInterrupted`.
495
+
496
+ Two rules make the check hard to fool, both learned from cross-model review:
497
+
498
+ - **compaction refuses to launder.** A rewrite that re-chains a damaged file would turn corruption
499
+ into a clean chain — so compaction verifies its input first and REFUSES a defective one. The log
500
+ then grows past its size cap, on purpose: the cap is a convenience, the evidence is the product.
501
+ - **a rewrite cannot silently eat a concurrent append.** The whole-file rewrite takes an exclusive
502
+ lock and re-reads the live file immediately before the rename; an append that landed in between
503
+ aborts the attempt and is folded into the retry instead of being overwritten.
504
+
505
+ **Honest scope, stated everywhere it appears:** this is corruption detection for *our own* bugs —
506
+ compaction, torn writes, races. FNV-1a is not cryptography and the threat model has no adversary:
507
+ anyone who can edit the log can recompute the chain. **When to use:** read the line before you quote
508
+ any `dz compounding` number, and after any crash that interrupted a write.
509
+
510
+ Three properties make it safe to run on a per-prompt hook: chain fields come from the **last line
511
+ only** (no full-file scan per append); records written before chaining existed stay valid and are
512
+ reported as an uncovered `pre-chain` prefix rather than flagged; and a tail that cannot be read
513
+ **never blocks the write** — the writer starts a fresh, explicitly marked segment.
514
+
472
515
  ### Did the lessons actually change outcomes? — `dz epoch-replay`
473
516
 
474
517
  `dz compounding` says a cold-vs-warm replay **can** be run. `dz epoch-replay` **runs** it and reports
@@ -880,7 +923,7 @@ dz bto-optimize --split|--plan|--select|--scope-check|--diff [--json] # determ
880
923
  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)
881
924
  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
882
925
  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
883
- 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 — a gate without enough data says INSUFFICIENT_DATA, never a verdict
926
+ 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
884
927
  dz epoch-replay --mock [--n <N>] [--effect <-1..1>] [--tie-rate <0..1>] [--seed <N>] [--slice <name>] [--margin <0..0.5>] [--json] # $0 synthetic run through the REAL verdict math; labelled SYNTHETIC, same seed = byte-identical
885
928
  dz epoch-replay --emit [--project <dir>] [--limit <N>] [--seed <N>] [--margin <0..0.5>] [--out <file>] [--json] # cold-vs-warm work order: replayable instances + PRE-REGISTERED blind A/B assignment + the PRE-REGISTERED non-superiority margin + a sha256 integrity digest + emittedAt/corpus fingerprint (raw prompts — defaults into the git-ignored .dz/epoch-replay/)
886
929
  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
@@ -890,6 +933,7 @@ dz backlog <sub> add "<idea>" | list | show <id> | goals [--validate] | roul
890
933
  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
891
934
  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
892
935
  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)
936
+ dz guard promote [--dry-run | --apply] [--window-days <N>] [--periods <N>] [--json] # lesson → guard-rule promotion: ranks lessons by firings × cost, SHADOW-replays each candidate over real commits, and proposes a rule only after TWO consecutive wins AND two window-lengths of REAL elapsed time since first observation (a window with zero firings resets the counter; a thin window is skipped, never a loss; commit dates are author-supplied, so elapsed time is measured by the local clock in .dz/promotion-state.json). Proposes by default (--dry-run writes nothing — and so never starts that clock; --apply installs it SOFT — a promoted rule can never block, and a same-id/different-body clash is a CONFLICT that exits 1 rather than claiming success); promotions AND refusals are recorded in features/guard-promotion/promotions/
893
937
  dz feature-adr-setup --guards [--loc-cap <n>] [--apply] # P3: scaffold DETERMINISTIC guard tests into the project — guards.config.json + a zero-dependency check.mjs runner (LOC cap, secret scan, frozen-file sha256 pins, waivers-with-reasons); wire `node architecture/guards/check.mjs` into CI
894
938
  dz publish [--filter <name>] [--bump-only] [--claim-check <off|warn|error>] (dry-run by default; pass --yes/--confirm to go live; claim-check gate defaults to warn — surfaces README claim findings, never blocks)
895
939
  dz parity [--target <name>] [--json] # honest feature×target map COMPUTED from the capability model — full / manual (via which form) / absent, per target
@@ -2085,6 +2129,79 @@ zero specifiers, and then report every real dependency as "not recorded". The ru
2085
2129
  `.dz/guard.json` cannot promote it to HARD, since a parser designed to admit "I may not understand this
2086
2130
  file" must never be able to block a publish.
2087
2131
 
2132
+ #### `dz guard promote` — when a LESSON has earned the right to become a rule
2133
+
2134
+ `dz compounding` MEASURED the uncomfortable half of the learning loop (reproducer: `dz compounding
2135
+ --json` on this repo, 2026-07-29): 27 of 154 lessons had ever been injected — ~82 % write-only —
2136
+ while the lessons that *did* become guard rules collapsed their own violation rate
2137
+ (`no-workspace-star` 31 → 0, `readme-first` 49 → 4). Rules compound; notes-to-self do not.
2138
+ `dz guard promote` is the elevator between them — the cost-of-detection ladder made executable.
2139
+
2140
+ ```bash
2141
+ dz guard promote --dry-run # inspect only: computes and prints, writes NOTHING
2142
+ dz guard promote # writes the proposal + refusal documents (never .dz/guard.json)
2143
+ dz guard promote --apply # installs the promoted rule(s) — SOFT severity, always
2144
+ dz guard promote --window-days 30 --periods 4 # widen the evidence window for a rarer violation
2145
+ ```
2146
+ ```
2147
+ dz guard promote — lesson → guard-rule promotion (two consecutive shadow wins required)
2148
+
2149
+ corpus: 1 lesson(s) · 0 quarantined · 13 change(s) over 4 × 7d window(s)
2150
+
2151
+ RANKED CANDIDATES (score = firings × cost, cost = 1 + lesson uses — cost is a PROXY, not a token figure):
2152
+ ★ [ 12] promoted-pairing-package-json-changelog-md PROMOTE
2153
+ promote: 2 consecutive shadow win(s) over 2 evaluated period(s), 12 real firing(s)
2154
+ periods (oldest→newest): –0/0 –0/0 W7/7 W5/6
2155
+ evidence: 24f0d72ab2be: package.json changed without any **/CHANGELOG.md
2156
+
2157
+ WROTE: features/guard-promotion/promotions/001-promoted-pairing-package-json-changelog-md.md
2158
+ Nothing was written to .dz/guard.json — re-run with --apply to install the promoted rule(s).
2159
+ ```
2160
+
2161
+ **A candidate must win twice, on real history.** Each lesson is reduced to a fixed *rule template*
2162
+ (`pairing-check` = X changed without Y · `absence-check` · `format-match`), then **shadow-replayed
2163
+ over actual commits** in consecutive time windows. A window in which the check would have fired on a
2164
+ real commit is a *win*; a window with zero firings is a *loss* and **resets the counter**; a window
2165
+ with fewer than 5 commits is *skipped*, never counted against it. Two consecutive wins are required,
2166
+ and every win cites a commit sha you can `git show`. Windows are wall-clock, so re-running the
2167
+ command can never manufacture a win — the counter is recomputed from history, never accumulated.
2168
+
2169
+ **And it must have been watched for two real window-lengths.** Commit timestamps are author-supplied
2170
+ (`GIT_COMMITTER_DATE`, a rebase, a repo import, clock skew), so history that *looks* like two windows
2171
+ can be laid down in one afternoon. A second clock closes that: promotion also requires
2172
+ `now − firstSeen ≥ 2 × --window-days` of real elapsed time, measured by the local clock and
2173
+ journalled in `.dz/promotion-state.json` the first time the candidate is recorded. Consequences worth
2174
+ knowing up front: a brand-new repo waits 14 days for its first promotion however strong the evidence,
2175
+ and a `--dry-run`-only workflow never promotes, because the run that would start the clock is exactly
2176
+ the one that writes nothing. (The `wait` reason spells both out.) This is a guard against accidental
2177
+ self-gaming, not a cryptographic one — the state file is local and editable.
2178
+
2179
+ **It refuses out loud.** Rule code is never synthesised from lesson text — a lesson that fits no
2180
+ template is listed as not-promotable *with the reason*, and the refusals are recorded in
2181
+ `features/guard-promotion/promotions/` alongside the promotions. A candidate already covered by an
2182
+ existing rule is refused as a duplicate naming that rule; a quarantined lesson (an unproven
2183
+ hypothesis) is refused but still told what it *would* become, so the list reads as a roadmap:
2184
+ ```
2185
+ ✗ [ 0] promoted-pairing-package-json-pnpm-lock-yaml NOT-PROMOTABLE
2186
+ not-promotable: quarantined (an unproven hypothesis must not become an enforced rule) — it WOULD
2187
+ classify as pairing-check, and is already covered by 'lockfile-in-sync'; confirm it with
2188
+ `dz teach --reinforce` to make it eligible
2189
+ ```
2190
+
2191
+ **A promoted rule can never block.** It is written `soft`, and `resolveRules` forces SOFT for every
2192
+ template-backed rule — a hand-edited `"severity": "hard"` in `.dz/guard.json` is ignored. It is a real
2193
+ rule, though, not an inert config entry: it fires in `dz guard check --op publish` from the next run.
2194
+
2195
+ **`--apply` compares rule BODIES, not ids.** Re-applying an identical rule is a no-op and exits 0.
2196
+ An existing `.dz/guard.json` rule that shares the derived id but has a different body is a
2197
+ **conflict**: nothing is written, the clash is printed on a `✗ CONFLICT` line (and in the JSON
2198
+ `conflicts[]`), and the command exits **1** — a zero exit for work that was deliberately not done
2199
+ would be the same kind of lie the feature exists to remove.
2200
+
2201
+ *When to use it:* after a stretch of work that taught you something mechanical ("X must change with
2202
+ Y"), run `dz guard promote --dry-run` at session end. If a candidate has two wins, `--apply` it and
2203
+ that class of mistake becomes a layer-1 check instead of something you have to remember.
2204
+
2088
2205
  ### `dz feature-adr-setup --guards` — when a project rule should be a TEST, not a reviewer's memory
2089
2206
 
2090
2207
  A 700-line cap enforced by reviewer judgment catches one file and misses its sibling in the same change;
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;AAwVH,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;CAC5C;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;AAopN9E,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA4J5E"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA6WH,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;CAC5C;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;AAyjO9E,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA4J5E"}