@dzhechkov/harness-cli 0.3.256 → 0.3.258
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 +8 -8
- package/README.md +132 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +109 -4
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
- package/sbom.json +7 -7
- package/src/cli.ts +119 -3
package/.dz-manifest.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "README.md",
|
|
12
|
-
"sha256": "
|
|
12
|
+
"sha256": "a38e5ef6a741aec138af0de7bd3616d4356d613ba1616bd8b5417194c1ee5f03"
|
|
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": "
|
|
44
|
+
"sha256": "f954d1e2e3d9f5941481a2b2ccbf553bab892dfa9ba1e7aefb4bf7d1800e9203"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"path": "dist/cli.js",
|
|
48
|
-
"sha256": "
|
|
48
|
+
"sha256": "5fb105be335591fb20401a3b23bac9829777e7ba96c2a2480c29970f4ffa2774"
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
"path": "dist/cli.js.map",
|
|
52
|
-
"sha256": "
|
|
52
|
+
"sha256": "a4be3aac6dadec03c1fc85fc5354d9a286ac0a21b4983349c4e511cae49dec79"
|
|
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": "
|
|
76
|
+
"sha256": "b502ba368d29e25413ce35e8853bc5650c06f686202e51f997f67db0fac03224"
|
|
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": "
|
|
84
|
+
"sha256": "a369561502f08d9dd4993a294adcb3a38349f543959fa8de31cd1580778062b0"
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
87
|
"path": "src/index.ts",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
"path": "test/cli.test.ts",
|
|
92
|
-
"sha256": "
|
|
92
|
+
"sha256": "555aed692218a73f23a343df2f2b38ce028e694dd9d4aff37e727096f88eb50e"
|
|
93
93
|
},
|
|
94
94
|
{
|
|
95
95
|
"path": "test/epoch-replay-cli.test.ts",
|
|
@@ -109,5 +109,5 @@
|
|
|
109
109
|
}
|
|
110
110
|
]
|
|
111
111
|
},
|
|
112
|
-
"signature": "
|
|
112
|
+
"signature": "CXaYCYQIKEVpAB29MZ5rG0/VUWtihZaeJh86r6x8uFpzKrgzHnrzmg/MmTUW3R/rqeA5w12hcfyfr4kl85ZxBA=="
|
|
113
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
|
|
@@ -589,6 +632,93 @@ a guess dressed as a number. The authoritative calibration is `--calibrate` with
|
|
|
589
632
|
shown on claude.ai/settings/usage; absent that, limits set from your own observed peak mean "unusually
|
|
590
633
|
heavy **for you**", which is exactly what a pre-emptive routing switch needs.
|
|
591
634
|
|
|
635
|
+
### Where did the run's budget actually go? — `dz usage --by-stage`
|
|
636
|
+
|
|
637
|
+
**The itemized receipt.** A `/feature-adr` run reports ONE number. The recorded run
|
|
638
|
+
`wf_0576bd7d-797` spent `623290` tokens (MEASURED — reproducer:
|
|
639
|
+
`dz usage --by-stage --run wf_0576bd7d-797`, `totalTokens` field of the run record) — a restaurant
|
|
640
|
+
bill with no line items. `dz usage --by-stage` turns it into a receipt keyed by the workflow's own
|
|
641
|
+
stage labels, so *"where the budget burns"* stops being a feeling and becomes a number you can sort.
|
|
642
|
+
|
|
643
|
+
Why it matters, in four points:
|
|
644
|
+
|
|
645
|
+
1. **Visibility → control.** Per-stage rows (`code` · `qe:brutal` · `fleet:cov` · `delivery:*`),
|
|
646
|
+
each with its model, its weighted tokens, its call count and a USD estimate — sorted by spend, so
|
|
647
|
+
the expensive stage is the first line you read.
|
|
648
|
+
2. **Real numbers for auto-cost routing.** `args.models.<stage> = 'auto-cost'` picks models from a
|
|
649
|
+
STATIC assumptions table. The ledger exposes MEASURED per-stage aggregates
|
|
650
|
+
(`{stage, model, avgTokens, runs}`) — the missing sense organ for a system meant to optimize its
|
|
651
|
+
own cost. *Wiring into routing is deliberately out of scope for now: the reader exists, nothing
|
|
652
|
+
consumes it yet.*
|
|
653
|
+
3. **The reconciliation invariant guards the bookkeeping itself.** Per-stage sums MUST reconcile
|
|
654
|
+
with the run total: `accounted + unaccounted = run total`, as raw integer equality. A mismatch is
|
|
655
|
+
a **NAMED defect** (`Unaccounted` / `DoubleAttributed` / `ForeignSample` /
|
|
656
|
+
`MissingStageTranscript` / `MalformedRecord`), never a rounding remainder — the same discipline as
|
|
657
|
+
the event-chain ledger. Without it a by-stage table can quietly lie: it already caught a real run
|
|
658
|
+
where 12 agent transcripts had no stage entry at all.
|
|
659
|
+
4. **The honest limit, stated next to the benefits.** Totals are LOCAL TRANSCRIPT ESTIMATES — no
|
|
660
|
+
billing API is consulted. So the invariant catches **attribution** errors (a double-counted stage,
|
|
661
|
+
a missing one), **not pricing** errors. There is no "accurate to the cent" promise here, and the
|
|
662
|
+
USD column marks with `*` every row priced by the sonnet-class fallback.
|
|
663
|
+
|
|
664
|
+
#### Зачем это
|
|
665
|
+
|
|
666
|
+
Прогон `/feature-adr` отчитывается **одним** числом. У записанного прогона `wf_0576bd7d-797` это
|
|
667
|
+
`623290` токенов (MEASURED — воспроизводится: `dz usage --by-stage --run wf_0576bd7d-797`) — счёт из
|
|
668
|
+
ресторана без позиций. `dz usage --by-stage` превращает его в **детализированный счёт** по тем самым
|
|
669
|
+
меткам стадий, которые пайплайн уже проставляет, — и «где горит бюджет» перестаёт быть ощущением и
|
|
670
|
+
становится числом.
|
|
671
|
+
|
|
672
|
+
1. **Видимость → управляемость.** Строка на стадию (`code` · `qe:brutal` · `fleet:cov` ·
|
|
673
|
+
`delivery:*`) с моделью, взвешенными токенами, числом вызовов и оценкой в долларах, отсортированные
|
|
674
|
+
по расходу: дорогая стадия — первая строка, которую вы читаете.
|
|
675
|
+
2. **Живые данные для auto-cost роутинга.** Сейчас `args.models.<stage> = 'auto-cost'` выбирает
|
|
676
|
+
модель по СТАТИЧЕСКОЙ таблице предположений. Реестр отдаёт ИЗМЕРЕННЫЕ агрегаты по стадиям
|
|
677
|
+
(`{stage, model, avgTokens, runs}`) — недостающий орган чувств для системы, которая должна
|
|
678
|
+
оптимизировать собственную стоимость. *Подключение к роутингу сознательно вынесено за рамки:
|
|
679
|
+
читатель есть, потребителя пока нет.*
|
|
680
|
+
3. **Инвариант сверки страхует саму бухгалтерию.** Сумма по стадиям ОБЯЗАНА сходиться с итогом
|
|
681
|
+
прогона: `учтено + неучтённое = итог`, точное целочисленное равенство. Расхождение — это
|
|
682
|
+
**именованный дефект**, а не «остаток от округления»: та же дисциплина, что у event-chain-реестра.
|
|
683
|
+
Без него таблица по стадиям может тихо врать — и она уже поймала реальный прогон, где 12
|
|
684
|
+
транскриптов агентов не имели записи ни об одной стадии.
|
|
685
|
+
4. **Честная граница — рядом с пользой.** Итоги считаются по ЛОКАЛЬНЫМ транскриптам (никакого
|
|
686
|
+
биллингового API), поэтому инвариант ловит ошибки **атрибуции** (двойной счёт, потерянную стадию),
|
|
687
|
+
а НЕ ошибки **цены**. Обещания «до цента» здесь нет, а строки, посчитанные по резервному
|
|
688
|
+
sonnet-тарифу, помечены `*`.
|
|
689
|
+
|
|
690
|
+
```bash
|
|
691
|
+
dz usage --by-stage # the most recent workflow run
|
|
692
|
+
dz usage --by-stage --slug portable-gates # by feature slug
|
|
693
|
+
dz usage --by-stage --run wf_0576bd7d-797 # by run id
|
|
694
|
+
dz usage --by-stage --json # rows + reconciliation, machine-readable
|
|
695
|
+
dz usage --by-stage --write features/x/09_cost_ledger.jsonl # materialize the derived report
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
Real output (MEASURED — reproducer: the `--run wf_0576bd7d-797` command above, abridged):
|
|
699
|
+
|
|
700
|
+
```
|
|
701
|
+
usage --by-stage: run wf_0576bd7d-797 · slug recall-usage-instrumentation · feature-adr · completed
|
|
702
|
+
stage model weighted calls ~USD
|
|
703
|
+
adr:claude-fb claude-opus-4-8[1m] 253,649 11 $1.27
|
|
704
|
+
design:confirm-landed claude-opus-4-8[1m] 196,013 7 $0.9801
|
|
705
|
+
qcsd · codex:gpt-5.6:xhigh (usage-switched) claude-sonnet-5 109,122 7 $0.3274
|
|
706
|
+
usage:probe claude-haiku-4-5-20251001 76,441 6 $0.0764
|
|
707
|
+
reconciliation: accounted 1,112,167 + unaccounted 0 = run total 1,112,167 (epsilon 0.00%)
|
|
708
|
+
identity: holds (raw integer equality)
|
|
709
|
+
verdict: BALANCED
|
|
710
|
+
scope: local transcript ESTIMATES, not billed amounts — the reconciliation invariant catches
|
|
711
|
+
ATTRIBUTION errors (double-counted or missing stages), NOT pricing errors
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
**Three verdicts, and `INSUFFICIENT_DATA` is not one of the good ones.** `BALANCED` means measured
|
|
715
|
+
and reconciled; `DEFECT` names what is wrong; `INSUFFICIENT_DATA` means nothing was measured — never
|
|
716
|
+
read `!== 'DEFECT'` as success. Nothing is written unless you pass `--write`, and what it writes is a
|
|
717
|
+
regenerable report, not a store.
|
|
718
|
+
|
|
719
|
+
**When to use:** after an expensive run, before deciding which stage to re-route or downgrade; when
|
|
720
|
+
a run's cost surprises you; and any time a by-stage number is about to be quoted to someone.
|
|
721
|
+
|
|
592
722
|
### Do your skills actually register? — `dz skills-verify`
|
|
593
723
|
|
|
594
724
|
Shipping a skill pack is not the same as a skill **registering**. A layout test that asserts
|
|
@@ -845,6 +975,7 @@ dz vector harmonize [--apply] [--threshold <0..1>] [--json] # SEMANTIC me
|
|
|
845
975
|
dz teach --harmonize [--apply] [--threshold <0..1>] # alias of `dz vector harmonize`
|
|
846
976
|
dz statusline [--json] [--install] # compact Claude Code statusline: live self-learning pattern count + brain sources
|
|
847
977
|
dz usage [--json] [--project <dir>] | --calibrate --session <pct> --weekly <pct> [--model fable=<pct>] # ESTIMATE Claude usage from fixed reset windows; optional per-model weekly binding; exit 0 ALWAYS
|
|
978
|
+
--by-stage [--run <id> | --slug <s>] [--epsilon <0..1>] [--write <file.jsonl>] [--json] # per-stage cost ledger for ONE feature-adr run + reconciliation invariant (BALANCED | DEFECT | INSUFFICIENT_DATA)
|
|
848
979
|
dz claim-check [paths...] [--json] [--fail-on high|medium|none] [--project <dir>] # enforce the Integrity Rule: flag untagged/overstated accuracy claims; default scan = READMEs + features' 08_qe_report.md; exit 1 only at/above --fail-on (default high)
|
|
849
980
|
dz brain list [--json] # the durable cross-project knowledge brain
|
|
850
981
|
dz brain query "<q>" [--source <slug>] [--limit <N>] [--any] [--rerank] [--json] # cross-source recall (--any = OR match; --rerank reorders on-point first). Auto-broadens: if strict all-terms match yields 0 hits, it retries once as OR and labels the result "broadened" (text note + broadened:true in --json) instead of returning empty. Explicit --any is OR from the start (never labeled broadened).
|
|
@@ -880,7 +1011,7 @@ dz bto-optimize --split|--plan|--select|--scope-check|--diff [--json] # determ
|
|
|
880
1011
|
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
1012
|
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
1013
|
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
|
|
1014
|
+
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
1015
|
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
1016
|
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
1017
|
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
|
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;AAmXH,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;AAonO9E,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA4J5E"}
|
package/dist/cli.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
|
-
import { chmodSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmdirSync, rmSync, statSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { chmodSync, closeSync, existsSync, fstatSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readSync, readdirSync, readlinkSync, realpathSync, renameSync, rmdirSync, rmSync, statSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
7
7
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { execFileSync, execSync, spawn } from 'node:child_process';
|
|
10
10
|
import { homedir, tmpdir } from 'node:os';
|
|
11
11
|
import { createRequire } from 'node:module';
|
|
12
|
-
import { createSkill, getSkillInfo, getWorkflow, isTargetName, listSkills, runDoctor, runInit, benchmarkSkill, benchmarkSkills, scanMcp, reconcileCapabilities, RECONCILE_BANNER, buildRegistry, discoverSkillPackDirs, checkUpstream, compareSkills, checkAllUpstream, sweepSkillDrift, syncCanonicalSkill, checkUpgrades, discoverPackages, discoverSourcePackages, fetchAllDownloads, filterByCategory, pretrain, recommend, generatePlugin, publishPackages, runSetup, runMigrate, searchRegistry, runSync, runVerify, runInitAgentsMd, runInitGeminiMd, TARGET_NAMES, buildParityMatrix, TARGET_CAPABILITIES, TARGET_SHORT_LABELS, WORKFLOW_NAMES, importEcc, recordPattern, resolveLearningBackend, storeStats, consolidateSessions, pruneNoisePatterns, lessonDeltaReport, removePatternsByIds, snapshotStore, recallHybrid, teachGuard, mirrorPatternsToVector, mirrorEntriesToVector, patternVectorEntry, readMemoryLearningConfig, promotePatterns, quarantineExpiryCandidates, pruneQuarantinePatterns, clearAgentdbQuarantine, vectorMirrorEnabled, vectorTierStatus, resolveVectorEngine, reindexVectorStore, harmonizeVectorStore, importRvfCheckpoint, statuslineData, writeFeatureAdrState, computeUsage, deriveUsageCalibration, normalizeClaudeUsageModelKey, readUsageLimits, claimCheck, summarize, queryBookKnowledge, loadStorePatternsSync, patternRecordId, loadStoreRecords, recordToPattern, bundleSkills, brainHome, listBrain, promoteProjectToBrain, updateBrainSource, queryBrain, groundPrompt, expandKu, reindexBrainVectors, buildPrimer, exportBrainSlice, importBrainSlice, registerKusToBrain, RECALL_USAGE_LOG_RELATIVE, RECALL_USAGE_LOG_MAX_BYTES, parseRecallUsageLog, buildRecallUsageReport, buildManifest, buildSbom, resolveTrustRoot, decideVerifyPolicy, generateSigningKeypair, evaluateGuard, resolveRules, auditRecord, guardExitCode, DEFAULT_RULES, parsePnpmLockImporters,
|
|
12
|
+
import { createSkill, getSkillInfo, getWorkflow, isTargetName, listSkills, runDoctor, runInit, benchmarkSkill, benchmarkSkills, scanMcp, reconcileCapabilities, RECONCILE_BANNER, buildRegistry, discoverSkillPackDirs, checkUpstream, compareSkills, checkAllUpstream, sweepSkillDrift, syncCanonicalSkill, checkUpgrades, discoverPackages, discoverSourcePackages, fetchAllDownloads, filterByCategory, pretrain, recommend, generatePlugin, publishPackages, runSetup, runMigrate, searchRegistry, runSync, runVerify, runInitAgentsMd, runInitGeminiMd, TARGET_NAMES, buildParityMatrix, TARGET_CAPABILITIES, TARGET_SHORT_LABELS, WORKFLOW_NAMES, importEcc, recordPattern, resolveLearningBackend, storeStats, consolidateSessions, pruneNoisePatterns, lessonDeltaReport, removePatternsByIds, snapshotStore, recallHybrid, teachGuard, mirrorPatternsToVector, mirrorEntriesToVector, patternVectorEntry, readMemoryLearningConfig, promotePatterns, quarantineExpiryCandidates, pruneQuarantinePatterns, clearAgentdbQuarantine, vectorMirrorEnabled, vectorTierStatus, resolveVectorEngine, reindexVectorStore, harmonizeVectorStore, importRvfCheckpoint, statuslineData, writeFeatureAdrState, computeUsage, deriveCostLedger, renderCostLedger, verifyCostLedgerReport, writeCostLedgerJsonl, COST_LEDGER_SCOPE, deriveUsageCalibration, normalizeClaudeUsageModelKey, readUsageLimits, claimCheck, summarize, queryBookKnowledge, loadStorePatternsSync, patternRecordId, loadStoreRecords, recordToPattern, bundleSkills, brainHome, listBrain, promoteProjectToBrain, updateBrainSource, queryBrain, groundPrompt, expandKu, reindexBrainVectors, buildPrimer, exportBrainSlice, importBrainSlice, registerKusToBrain, RECALL_USAGE_LOG_RELATIVE, RECALL_USAGE_LOG_MAX_BYTES, parseRecallUsageLog, buildRecallUsageReport, EVENT_CHAIN_TAIL_BYTES, EMPTY_LOG_TAIL, readTailInfo, appendChainedLines, verifyEventChainText, buildManifest, buildSbom, resolveTrustRoot, decideVerifyPolicy, generateSigningKeypair, evaluateGuard, resolveRules, auditRecord, guardExitCode, DEFAULT_RULES, parsePnpmLockImporters,
|
|
13
13
|
// guard-promotion (feature guard-promotion, scout idea #1)
|
|
14
14
|
assembleCandidates, renderPromotionReport, renderPromotionAdr, normalizePromotionState, nextPromotionState, globMatch, promotionAdrRelPath, DEFAULT_WINDOW_DAYS, DEFAULT_PERIODS, MAX_CONTENT_FETCHES, BUILTIN_COVERAGE, decideProvenance, isInsideTree, signManifest, verifyManifest, listSignablePackFiles, assertKeyOutsideTree, decidePublishGate, collectPackageFacts, planReleaseGates, selectAffectedPackages, classifyGateExecutions, buildFailureIssue, buildReleaseNotes, releaseTagName, firstOutputLine, formatPublishError, MANIFEST_NAME, SBOM_NAME, buildArchitectureMap, renderMapHuman, findArchitectureDrift, renderDriftReport, scanWorkspacePackages, loadSubsystemManifest, loadProductVision, checkFeatureAgainstArchitecture, renderArchCheck, planProjectSkills, guidanceForStage, renderInjectionReport, analyzeCorpus, renderRakeReport, renderCriticSection, rakeAsLesson, rakeReward, DEFAULT_RAKE_THRESHOLDS, streamSessionEvents, findLatestTranscript, detectProcessRakes, buildRetro, renderRetro, retroLessonText, PROCESS_SIGNATURES, RETRO_DOMAIN, scanForSetup, buildSetupPlan, scaffoldFromSpec, renderScaffoldPreview, readExistingForScaffold, assembleChallengeContext, buildChallengeBrief, planDiscriminationCheck, classifyDiscrimination, pickAdversaryModel, CHALLENGE_QUESTIONS, loadOutcomes, renderOutcomes, statsForKey, selectAutoCost, recordProvisional, finalizeOutcome, COST_LADDER, splitScenarios, budgetPlan, selectWinner, proseScopeOk, renderProseDiff, readScenarioIds, DEFAULT_MAX_JUDGE_RUNS, collectDeliveryFacts, planDeliveryCheck, renderDeliveryBrief, classifyDelivery, isUsablePlaneResult, renderDeliveryReview, scanSkillsLayout, parseInitFacts, verifyRegistration, buildContentProbePrompt, classifyContentProbe, renderContentProbe, findNonRegistrableSkillDirs, assembleCompoundingReport,
|
|
15
15
|
// Cold-vs-warm EPOCH RUNNER (feature epoch-replay) — orchestrates + scores, never calls a model.
|
|
@@ -79,6 +79,7 @@ Usage:
|
|
|
79
79
|
dz statusline [--json] [--install] [--project <dir>] (live self-learning panel for Claude Code's status bar; reads the CC JSON payload from STDIN)
|
|
80
80
|
dz statusline --fa-record --slug <s> --step "<label>" [--recalled <n>] [--stored <n>] [--mode <m>] (feature-adr: record live per-run learning state → 📐 panel segment)
|
|
81
81
|
dz usage [--json] [--project <dir>] | dz usage --calibrate --session <pct> --weekly <pct> [--model fable=<pct>] [--project <dir>] (ESTIMATE Claude usage from fixed reset windows; optional per-model weekly binding; exit 0 ALWAYS; pct=null when limits unconfigured)
|
|
82
|
+
dz usage --by-stage [--run <runId> | --slug <slug>] [--epsilon <0..1>] [--write <file.jsonl>] [--json] (per-stage cost ledger for ONE feature-adr run + the reconciliation invariant: accounted + unaccounted = run total; verdict BALANCED | DEFECT | INSUFFICIENT_DATA; local transcript ESTIMATES — catches ATTRIBUTION errors, not pricing errors)
|
|
82
83
|
dz claim-check [paths...] [--json] [--fail-on high|medium|none] [--project <dir>] (enforce the Integrity Rule: flag untagged/overstated accuracy claims; default scan = root README.md + every discovered package's README.md + features/*/08_qe_report.md + docs/**/*.md (historical feature artifacts are NOT scanned — pass paths explicitly); exit 1 only at/above --fail-on, default high)
|
|
83
84
|
dz pretrain [--project <dir>]
|
|
84
85
|
dz recommend "<task description>"
|
|
@@ -1129,6 +1130,57 @@ function cmdUsageCalibrate(options, optionLists, cwd, write) {
|
|
|
1129
1130
|
return 0;
|
|
1130
1131
|
}
|
|
1131
1132
|
}
|
|
1133
|
+
/**
|
|
1134
|
+
* `dz usage --by-stage` — the per-stage cost ledger for one feature-adr run (feature `cost-ledger`).
|
|
1135
|
+
*
|
|
1136
|
+
* A run reports ONE number; this turns it into an itemized receipt keyed by the workflow's OWN
|
|
1137
|
+
* `stageLabel()` strings, plus the reconciliation line that guards the bookkeeping itself. Derived
|
|
1138
|
+
* post-hoc from the transcripts already on disk — no workflow edit, killed runs included.
|
|
1139
|
+
*
|
|
1140
|
+
* Exit code is 0 ALWAYS, matching the rest of `dz usage`; the VERDICT (`BALANCED` / `DEFECT` /
|
|
1141
|
+
* `INSUFFICIENT_DATA`) is the signal, and `INSUFFICIENT_DATA` is not success.
|
|
1142
|
+
*/
|
|
1143
|
+
function cmdUsageByStage(options, flags, write) {
|
|
1144
|
+
const runId = options.get('run');
|
|
1145
|
+
const slug = options.get('slug');
|
|
1146
|
+
const epsilonRaw = options.get('epsilon');
|
|
1147
|
+
const epsilon = epsilonRaw === undefined ? undefined : Number(epsilonRaw);
|
|
1148
|
+
const report = deriveCostLedger({
|
|
1149
|
+
...(runId !== undefined ? { runId } : {}),
|
|
1150
|
+
...(slug !== undefined ? { slug } : {}),
|
|
1151
|
+
...(epsilon !== undefined && Number.isFinite(epsilon) ? { epsilon } : {}),
|
|
1152
|
+
});
|
|
1153
|
+
if (report === null) {
|
|
1154
|
+
// An ABSENT run is never a balanced empty report (ADR-003).
|
|
1155
|
+
const detail = runId !== undefined ? `run ${runId}` : slug !== undefined ? `slug ${slug}` : 'any workflow run';
|
|
1156
|
+
if (flags.has('json')) {
|
|
1157
|
+
write(JSON.stringify({ verdict: 'INSUFFICIENT_DATA', reason: `no workflow run record found for ${detail}`, rows: [], estimated: true, scope: COST_LEDGER_SCOPE }));
|
|
1158
|
+
}
|
|
1159
|
+
else {
|
|
1160
|
+
write(`usage --by-stage: INSUFFICIENT_DATA — no workflow run record found for ${detail}`);
|
|
1161
|
+
write(`usage --by-stage: scope: ${COST_LEDGER_SCOPE}`);
|
|
1162
|
+
}
|
|
1163
|
+
return 0;
|
|
1164
|
+
}
|
|
1165
|
+
// The verifier re-derives the identities from the EMITTED report — a builder bug must surface as
|
|
1166
|
+
// a finding, not as a plausible table.
|
|
1167
|
+
const verifyDefects = verifyCostLedgerReport(report);
|
|
1168
|
+
const outPath = options.get('write');
|
|
1169
|
+
let wrote = null;
|
|
1170
|
+
if (outPath !== undefined && outPath.length > 0)
|
|
1171
|
+
wrote = writeCostLedgerJsonl(resolve(outPath), report);
|
|
1172
|
+
if (flags.has('json')) {
|
|
1173
|
+
write(JSON.stringify({ ...report, verifyDefects, ...(wrote === null ? {} : { wrote, writePath: resolve(outPath ?? '') }) }));
|
|
1174
|
+
return 0;
|
|
1175
|
+
}
|
|
1176
|
+
write(renderCostLedger(report));
|
|
1177
|
+
for (const d of verifyDefects)
|
|
1178
|
+
write(` verifier: ${d.kind}: ${d.detail}`);
|
|
1179
|
+
if (wrote !== null) {
|
|
1180
|
+
write(` ${wrote ? 'wrote' : 'FAILED to write'} ${resolve(outPath ?? '')} (derived report — regenerable, never read back)`);
|
|
1181
|
+
}
|
|
1182
|
+
return 0;
|
|
1183
|
+
}
|
|
1132
1184
|
/**
|
|
1133
1185
|
* `dz usage` — print an ESTIMATE of Claude session + weekly usage from fixed reset windows,
|
|
1134
1186
|
* aggregated READONLY from the local transcript store (see {@link computeUsage}). `--json` emits
|
|
@@ -1154,6 +1206,8 @@ function cmdUsage(options, optionLists, flags, cwd, write) {
|
|
|
1154
1206
|
try {
|
|
1155
1207
|
if (flags.has('calibrate'))
|
|
1156
1208
|
return cmdUsageCalibrate(options, optionLists, cwd, write);
|
|
1209
|
+
if (flags.has('by-stage'))
|
|
1210
|
+
return cmdUsageByStage(options, flags, write);
|
|
1157
1211
|
const u = computeUsage(projectRoot);
|
|
1158
1212
|
const lim = readUsageLimits(projectRoot);
|
|
1159
1213
|
const modelLimits = lim.weeklyTokenLimitByModel;
|
|
@@ -4686,11 +4740,50 @@ function runGuardEvaluation(root, op, text, overrideReason) {
|
|
|
4686
4740
|
try {
|
|
4687
4741
|
const rec = auditRecord(result, new Date().toISOString(), overrideReason !== undefined ? { reason: overrideReason } : undefined);
|
|
4688
4742
|
mkdirSync(join(root, '.dz'), { recursive: true });
|
|
4689
|
-
|
|
4743
|
+
const auditPath = join(root, '.dz', 'guard-audit.jsonl');
|
|
4744
|
+
// event-chain (ADR-001): seq + prevHash derived from the LAST LINE ONLY — this file is the
|
|
4745
|
+
// evidence base `dz guard promote` decides on, and a rewrite that loses or duplicates a record
|
|
4746
|
+
// must not be able to look intact. A tail that cannot be read starts a MARKED segment rather
|
|
4747
|
+
// than blocking the audit: the verdict is never held hostage to a broken log.
|
|
4748
|
+
writeFileSync(auditPath, appendChainedLines([rec], readLogTail(auditPath)), { flag: 'a' });
|
|
4690
4749
|
}
|
|
4691
4750
|
catch { /* audit is best-effort, never blocks the verdict */ }
|
|
4692
4751
|
return result;
|
|
4693
4752
|
}
|
|
4753
|
+
/**
|
|
4754
|
+
* The tail facts of an append-only log, read from its END — O(1) in the file size, which is what
|
|
4755
|
+
* lets the chain be extended on every append without a full-file scan (FR-2). Anything unreadable
|
|
4756
|
+
* yields {@link EMPTY_LOG_TAIL}; the caller then starts a marked segment rather than blocking.
|
|
4757
|
+
*/
|
|
4758
|
+
function readLogTail(path) {
|
|
4759
|
+
let fd;
|
|
4760
|
+
try {
|
|
4761
|
+
if (!existsSync(path))
|
|
4762
|
+
return EMPTY_LOG_TAIL;
|
|
4763
|
+
fd = openSync(path, 'r');
|
|
4764
|
+
const size = fstatSync(fd).size;
|
|
4765
|
+
if (!Number.isFinite(size) || size <= 0)
|
|
4766
|
+
return EMPTY_LOG_TAIL;
|
|
4767
|
+
const want = Math.min(size, EVENT_CHAIN_TAIL_BYTES);
|
|
4768
|
+
const buf = Buffer.alloc(want);
|
|
4769
|
+
readSync(fd, buf, 0, want, size - want);
|
|
4770
|
+
return readTailInfo(buf.toString('utf-8'), { partial: want < size });
|
|
4771
|
+
}
|
|
4772
|
+
catch {
|
|
4773
|
+
// A read FAILURE is not an empty file (Codex re-QE LOW): EMPTY_LOG_TAIL means "there is
|
|
4774
|
+
// nothing", which lets the writer open an UNMARKED genesis on a file we merely failed to
|
|
4775
|
+
// read. An unreadable tail must force a marked reset, per the AM-6 contract.
|
|
4776
|
+
return { ...EMPTY_LOG_TAIL, unreadable: true };
|
|
4777
|
+
}
|
|
4778
|
+
finally {
|
|
4779
|
+
if (fd !== undefined) {
|
|
4780
|
+
try {
|
|
4781
|
+
closeSync(fd);
|
|
4782
|
+
}
|
|
4783
|
+
catch { /* nothing to do */ }
|
|
4784
|
+
}
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4694
4787
|
// ── `dz guard promote` (feature guard-promotion, scout idea #1) ─────────────────────────────────
|
|
4695
4788
|
const PROMOTIONS_DIR = join('features', 'guard-promotion', 'promotions');
|
|
4696
4789
|
const PROMOTION_STATE_FILE = join('.dz', 'promotion-state.json');
|
|
@@ -6019,7 +6112,19 @@ function cmdCompounding(options, flags, cwd, write) {
|
|
|
6019
6112
|
catch {
|
|
6020
6113
|
/* no audit yet */
|
|
6021
6114
|
}
|
|
6022
|
-
|
|
6115
|
+
// The evidence logs themselves, verbatim: the report verifies their hash chains (feature
|
|
6116
|
+
// event-chain). Handing over the TEXT rather than a pre-computed verdict keeps one definition of
|
|
6117
|
+
// "the chain is intact" — a second copy here is how a gate and its report start disagreeing.
|
|
6118
|
+
const evidenceLogs = [];
|
|
6119
|
+
for (const rel of ['.dz/recall-usage.jsonl', '.dz/guard-audit.jsonl']) {
|
|
6120
|
+
try {
|
|
6121
|
+
evidenceLogs.push({ log: rel, text: readFileSync(join(root, ...rel.split('/')), 'utf-8') });
|
|
6122
|
+
}
|
|
6123
|
+
catch {
|
|
6124
|
+
/* absent log — reported by its own gate above, not invented here */
|
|
6125
|
+
}
|
|
6126
|
+
}
|
|
6127
|
+
const report = assembleCompoundingReport({ lessons, usage, guard, nowTs: new Date().toISOString(), evidenceLogs });
|
|
6023
6128
|
if (json)
|
|
6024
6129
|
write(JSON.stringify({ ...report, exitCode: 0 }, null, 2));
|
|
6025
6130
|
else
|