@dzhechkov/harness-core 0.8.36 → 0.8.37
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 +195 -75
- package/README.md +235 -8
- package/dist/agentdb-index.d.ts +87 -7
- package/dist/agentdb-index.d.ts.map +1 -1
- package/dist/agentdb-index.js +416 -57
- package/dist/agentdb-index.js.map +1 -1
- package/dist/apply-leg.d.ts +19 -1
- package/dist/apply-leg.d.ts.map +1 -1
- package/dist/apply-leg.js +187 -36
- package/dist/apply-leg.js.map +1 -1
- package/dist/codex-rollouts.d.ts +118 -0
- package/dist/codex-rollouts.d.ts.map +1 -0
- package/dist/codex-rollouts.js +297 -0
- package/dist/codex-rollouts.js.map +1 -0
- package/dist/cost-ledger.d.ts +56 -4
- package/dist/cost-ledger.d.ts.map +1 -1
- package/dist/cost-ledger.js +176 -20
- package/dist/cost-ledger.js.map +1 -1
- package/dist/cross-family-control.d.ts +345 -0
- package/dist/cross-family-control.d.ts.map +1 -0
- package/dist/cross-family-control.js +802 -0
- package/dist/cross-family-control.js.map +1 -0
- package/dist/debt-ratchet.d.ts +53 -0
- package/dist/debt-ratchet.d.ts.map +1 -0
- package/dist/debt-ratchet.js +107 -0
- package/dist/debt-ratchet.js.map +1 -0
- package/dist/embedding-config.d.ts +42 -0
- package/dist/embedding-config.d.ts.map +1 -1
- package/dist/embedding-config.js +106 -10
- package/dist/embedding-config.js.map +1 -1
- package/dist/feature-adr-checkpoints.d.ts +6 -0
- package/dist/feature-adr-checkpoints.d.ts.map +1 -1
- package/dist/feature-adr-checkpoints.js +29 -0
- package/dist/feature-adr-checkpoints.js.map +1 -1
- package/dist/feature-adr-decision-recall.d.ts +2 -2
- package/dist/feature-adr-decision-recall.d.ts.map +1 -1
- package/dist/feature-adr-decision-recall.js +5 -3
- package/dist/feature-adr-decision-recall.js.map +1 -1
- package/dist/feature-adr-envelope.d.ts +96 -0
- package/dist/feature-adr-envelope.d.ts.map +1 -0
- package/dist/feature-adr-envelope.js +183 -0
- package/dist/feature-adr-envelope.js.map +1 -0
- package/dist/feature-adr-routing.d.ts +64 -0
- package/dist/feature-adr-routing.d.ts.map +1 -1
- package/dist/feature-adr-routing.js +122 -2
- package/dist/feature-adr-routing.js.map +1 -1
- package/dist/feature-adr-stage-canon.d.ts +79 -0
- package/dist/feature-adr-stage-canon.d.ts.map +1 -0
- package/dist/feature-adr-stage-canon.js +117 -0
- package/dist/feature-adr-stage-canon.js.map +1 -0
- package/dist/index.d.ts +19 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/loop-blobs.generated.js +4 -4
- package/dist/loop-blobs.generated.js.map +1 -1
- package/dist/mutation-gate.d.ts +51 -0
- package/dist/mutation-gate.d.ts.map +1 -1
- package/dist/mutation-gate.js +295 -0
- package/dist/mutation-gate.js.map +1 -1
- package/dist/qe-bridge.d.ts.map +1 -1
- package/dist/qe-bridge.js +4 -2
- package/dist/qe-bridge.js.map +1 -1
- package/dist/qe-findings.d.ts +107 -0
- package/dist/qe-findings.d.ts.map +1 -0
- package/dist/qe-findings.js +417 -0
- package/dist/qe-findings.js.map +1 -0
- package/dist/recap.d.ts +1 -1
- package/dist/recap.d.ts.map +1 -1
- package/dist/recap.js +4 -2
- package/dist/recap.js.map +1 -1
- package/dist/round.d.ts +74 -1
- package/dist/round.d.ts.map +1 -1
- package/dist/round.js +112 -4
- package/dist/round.js.map +1 -1
- package/dist/run-records.d.ts +60 -0
- package/dist/run-records.d.ts.map +1 -1
- package/dist/run-records.js +244 -2
- package/dist/run-records.js.map +1 -1
- package/dist/score.d.ts +44 -1
- package/dist/score.d.ts.map +1 -1
- package/dist/score.js +78 -5
- package/dist/score.js.map +1 -1
- package/package.json +1 -1
- package/sbom.json +374 -74
- package/src/agentdb-index.ts +423 -60
- package/src/apply-leg.ts +187 -36
- package/src/codex-rollouts.ts +374 -0
- package/src/cost-ledger.ts +232 -24
- package/src/cross-family-control.ts +960 -0
- package/src/debt-ratchet.ts +143 -0
- package/src/embedding-config.ts +131 -10
- package/src/feature-adr-checkpoints.ts +29 -0
- package/src/feature-adr-decision-recall.ts +6 -4
- package/src/feature-adr-envelope.ts +242 -0
- package/src/feature-adr-routing.ts +139 -2
- package/src/feature-adr-stage-canon.ts +141 -0
- package/src/index.ts +60 -6
- package/src/loop-blobs.generated.ts +4 -4
- package/src/mutation-gate.ts +316 -0
- package/src/qe-bridge.ts +4 -2
- package/src/qe-findings.ts +463 -0
- package/src/recap.ts +10 -3
- package/src/round.ts +165 -6
- package/src/run-records.ts +282 -2
- package/src/score.ts +115 -6
package/README.md
CHANGED
|
@@ -11,6 +11,52 @@ The serial paths in `test/serial-suites.txt` are regenerated from
|
|
|
11
11
|
`test/serial-suites-census.test.ts`, which scans test sources for process and timing markers,
|
|
12
12
|
including `execSync(` and `execFile(`, and fails when the list and census differ.
|
|
13
13
|
|
|
14
|
+
### Full-suite worker ceiling (`CORE_MAX_WORKERS`, `vitest.config.ts`)
|
|
15
|
+
|
|
16
|
+
The root `test` block caps `maxWorkers` at `CORE_MAX_WORKERS` (2, `minWorkers: 1`), so
|
|
17
|
+
`npx vitest run` with no flags is safe by default. **The ceiling lives on the root `test` block,
|
|
18
|
+
not on the `parallel` project's `poolOptions`** — an earlier version of this config set
|
|
19
|
+
`poolOptions.forks.maxForks` on the `parallel` project instead, and that was a false guarantee: a
|
|
20
|
+
fix-round measurement (2026-09-16) compared process names (`node (vitest N)`, polled from
|
|
21
|
+
`/proc/<pid>/cmdline`) over the same 30-file parallel set and saw names `vitest 1`..`vitest 7`
|
|
22
|
+
(14 workers observed) under the project-level `poolOptions`, against never more than
|
|
23
|
+
`vitest 1`/`vitest 2` under either a `--maxWorkers=2` CLI flag or `maxWorkers` on the root `test`
|
|
24
|
+
block. Vitest 3.2.4 simply does not honour `poolOptions.forks.maxForks` set on a project the way it
|
|
25
|
+
honours the root-level knob (or the equivalent CLI flag) — full proof in
|
|
26
|
+
`features/core-suite-memory-ceiling/07_code_changes/change_manifest.md`, section "Фикс-раунд 1".
|
|
27
|
+
|
|
28
|
+
The number itself is not "8 minus a guess" — it is arithmetic from a MEASURED trace (see the
|
|
29
|
+
comment above the constant in `vitest.config.ts`): the memory pressure is NOT the embedding model
|
|
30
|
+
loaded inside the vitest worker (that guess is REFUTED), it is a CHILD process that some tests
|
|
31
|
+
spawn per file (an embedding daemon, or a `dz teach` invocation). On 2026-09-16 three full-suite
|
|
32
|
+
runs were traced with the same instruments, and each number below
|
|
33
|
+
says WHICH run produced it, because two of the three runs did not have a ceiling that actually
|
|
34
|
+
bound:
|
|
35
|
+
|
|
36
|
+
| run | ceiling | tree peak | minimum free | result |
|
|
37
|
+
|---|---|---|---|---|
|
|
38
|
+
| 06:24–06:29 | `--maxWorkers=2` CLI flag (binds) | 5721 MB | 2995 MB | green, 7018 passed, 281 s |
|
|
39
|
+
| 06:46–06:49 | `poolOptions` on the `parallel` project (does NOT bind — effectively unbounded) | 8207 MB | 804 MB | green, but see below |
|
|
40
|
+
| 07:01–07:06 | root `test.maxWorkers` (binds), **no flags** | 5383 MB | 3804 MB | green, 333 files, 7024 passed, 275 s |
|
|
41
|
+
|
|
42
|
+
The last row is the profile of the shipped configuration — the command a person actually types.
|
|
43
|
+
The middle row is the DEFECT being measured, not this configuration, and it is where the
|
|
44
|
+
per-process-class peaks come from: a `vitest` process 2324 MB, an embedding-daemon child spawned by
|
|
45
|
+
a test 2321 MB, a child `dz teach --from-json` 1786 MB, with up to 4 daemon children alive at once
|
|
46
|
+
(3917 MB combined). Those per-class numbers are real, but quoting them as the memory profile of the
|
|
47
|
+
2-worker run would be a misattribution — a Codex round-2 finding, fixed here.
|
|
48
|
+
|
|
49
|
+
The load-bearing fact stays: the memory is NOT the embedding model inside the vitest worker, it is
|
|
50
|
+
in the CHILD processes the tests spawn, and the ceiling bounds how many worker-plus-child pairs are
|
|
51
|
+
alive together. `CORE_MAX_WORKERS` must not be raised without a fresh trace of the last shape.
|
|
52
|
+
|
|
53
|
+
`vitest.config.ts` also fails LOUD at config-load time if `CORE_MAX_WORKERS` is ever set to
|
|
54
|
+
something other than a positive integer (0, negative, or fractional) — a Codex fix-round finding
|
|
55
|
+
that a ceiling accepting those values is not a ceiling at all.
|
|
56
|
+
|
|
57
|
+
`test/mutation-registry.json`'s `maxWorkers` is kept equal to this same constant
|
|
58
|
+
(`test/suite-worker-ceiling.test.ts` reddens if either drifts from the other).
|
|
59
|
+
|
|
14
60
|
`findExactLesson(records, text, domain?)` finds the earliest lesson whose trimmed,
|
|
15
61
|
whitespace-collapsed text matches exactly (case-sensitive), optionally within one metadata domain,
|
|
16
62
|
and reports whether that existing lesson is quarantined.
|
|
@@ -192,6 +238,49 @@ evidence; **high-volume** (`gpt-5.6-luna`) for mechanics. Eco lowers each select
|
|
|
192
238
|
Codex tier by one level; these are capability assignments, not measured prices.
|
|
193
239
|
Claude-primary cells and the cross-family QE rule retain their existing behavior.
|
|
194
240
|
|
|
241
|
+
## Experiment envelope (`feature-adr-envelope.ts`, ADR-001 envelope-before-dispatch)
|
|
242
|
+
|
|
243
|
+
The feature-adr conveyor writes an OUTCOME per run (grade, some tokens) but never used to write the
|
|
244
|
+
DECISION behind it — what kind of task this was, how big, at what priority, which model arms the
|
|
245
|
+
router considered, which one it picked, and who judged it. `buildExperimentEnvelope` assembles that
|
|
246
|
+
as one plain-data object, built exactly ONCE per run (right after the Step-0 router, once `tier` and
|
|
247
|
+
`taskKind` are known, and before Step 1 dispatches anything), then threaded byte-for-byte into every
|
|
248
|
+
place the run reports itself:
|
|
249
|
+
|
|
250
|
+
- every autowritten run-cost ledger row (`.dz/feature-adr/run-cost-ledger.jsonl`, field `envelope`);
|
|
251
|
+
- every captured training pair (`.dz/fa-training/<slug>/<stage>.jsonl`, field `envelope`, alongside
|
|
252
|
+
the narrower legacy `budgetMode` — not instead of it);
|
|
253
|
+
- the round state opened via `dz round open --envelope <json>`, copied into the round's ledger row
|
|
254
|
+
by `closeRound` on `dz round close`.
|
|
255
|
+
|
|
256
|
+
Shape (`ExperimentEnvelope`): `schema:1`, `runId`, `attempt` (integer ≥ 1), `taskKind` (one of
|
|
257
|
+
`feature|bugfix|refactor|tooling|docs|research`), `tier` (`S|M|L|XL`), `priority`
|
|
258
|
+
(`speed|balance|quality|unset`), `treeSha` (40-hex or `null` + `treeShaReason`), `arms` (`{mode:
|
|
259
|
+
string[], stages: {stage: string[]}}` — what the routing tables OFFERED), `chosen` (`{mode, stages:
|
|
260
|
+
{stage: spec}}` — what was actually resolved), `policy` (`{name, version, propensity}`), `evaluator`
|
|
261
|
+
(`{family, model, source: 'planned'|'actual'}`). `validateExperimentEnvelope(value)` returns
|
|
262
|
+
`{ok:true}` or `{ok:false, reason}` naming the FIRST invalid field.
|
|
263
|
+
|
|
264
|
+
**The writer refuses an automated row without one (FR-5, D2).** In `run-records.ts`,
|
|
265
|
+
`decideRecordWrite` for `kind:'ledger'` refuses (`exit 2`) an `auto:true` row that carries no
|
|
266
|
+
`envelope`, and refuses ANY row (auto or manual) whose present `envelope` fails validation. A manual
|
|
267
|
+
row without `auto`/`envelope` is unaffected — the old shape still writes exactly as before (C-3).
|
|
268
|
+
Read it back with `jq '.envelope' .dz/feature-adr/run-cost-ledger.jsonl`.
|
|
269
|
+
|
|
270
|
+
**`args.priority` (FR-4).** A learning-stratum LABEL, one level above `budget`/`deliveryGate` — an
|
|
271
|
+
explicit knob always wins over the preset:
|
|
272
|
+
|
|
273
|
+
| `priority` | `budget` preset | `deliveryGate` |
|
|
274
|
+
|---|---|---|
|
|
275
|
+
| `speed` | `eco` | `false` |
|
|
276
|
+
| `balance` | `normal` | `false` |
|
|
277
|
+
| `quality` | `normal` | `true` |
|
|
278
|
+
| `unset` (default) | whatever `args.budget` says | whatever `args.deliveryGate` says |
|
|
279
|
+
|
|
280
|
+
`PRIORITY_PRESETS` + `resolvePriority(raw)` + `applyPriorityPreset(priority, explicit)` live next to
|
|
281
|
+
`BUDGET_PRESETS` in `feature-adr-routing.ts`; an unknown priority is a startup error naming the valid
|
|
282
|
+
list, never a silent `unset`. Setting `priority` alone (no other routing knob) turns routing on.
|
|
283
|
+
|
|
195
284
|
## What it provides
|
|
196
285
|
|
|
197
286
|
### Evidence-gated companion integrations
|
|
@@ -224,7 +313,9 @@ explicit skills-only short circuit. `--no-verify` cannot authorize emission. A C
|
|
|
224
313
|
| `no-stubs` | `scanStubs`, `checkNoStubs`, `scannableStubPath`, `STUB_MARKERS`, `STUB_PHRASES`, `STUB_SCAN_EXTENSIONS` | Pure unfinished-stub scanner behind the SOFT `no-stubs` publish rule (backlog 0b403a0106103901, Karpathy-Michaels rule XI): bare markers (`TODO`/`FIXME`/`HACK`/`XXX`/`PLACEHOLDER`) case-SENSITIVE with hard word boundaries (`hackathon`/`todos`/a marker inside a hash never fire; MEASURED: relaxing case doubles this repo's hits and adds only prose) + the `implement later` phrase case-insensitive. SCOPE = the CHANGE-SET (the working-tree `git status --porcelain -uall` diff — `-uall` so a brand-new untracked DIRECTORY is scanned file-by-file instead of collapsing to one invisible `?? newdir/` line; `.gitignore` semantics unchanged), never the whole tree — MEASURED: a tree-wide scan is 32+25 hits of mostly ancient legitimate markers, i.e. noise that gets a gate switched off. Markdown gets PROSE scoping (fenced blocks + backticked spans are QUOTES, not stubs). Waiver-with-REASON only, per line (`no-stubs: <reason>`) or per path (`.dz/guard.json` `stubWaivers`, the feature-adr-setup --guards shape); a reasonless waiver is REFUSED as its own finding and exempts nothing. Self-exemption is STRUCTURAL: every marker in the module and its tests is assembled from string fragments, so the gate's own source scans clean — a tested property, not a path skip. Fail-open on missing evidence (no change fact / ungathered contents ⇒ nothing reported) but never fail-SILENT: skipped scannable files (deleted/oversize/unreadable/beyond the file cap) surface as ONE aggregate `notes` entry in the `GuardResult` + audit record — information that can never move the verdict. KNOWN LIMITS are documented at the top of `no-stubs.ts` instead of implied away (whole-line inline waiver token = layer-4 auditability defence; reason QUALITY not judged; boolean fence model, not CommonMark; git-quoted paths undecoded; TS-monorepo extension allowlist; worktree-not-index reads; exact-string config-waiver paths). Mutation-defended (`no-stubs-bare-marker-fires` observed 10 red, `no-stubs-skipped-note-emitted` observed 2 red) |
|
|
225
314
|
| `feature-adr-setup` (P3) | `renderGuardsConfig`, `renderGuardsRunner` | Scaffolds deterministic guard tests into a TARGET project: `guards.config.json` + a zero-dependency `check.mjs` runner (loc-cap, secret-scan, frozen-file sha256 pins, waivers-with-reasons) — `dz feature-adr-setup --guards` |
|
|
226
315
|
| `usage` | `computeUsage`, `TOKEN_WEIGHTS`, `readUsageLimits`, `deriveUsageCalibration` | Read-only Claude usage ESTIMATE behind `dz usage`. Tokens are COST-WEIGHTED input-equivalents (input 1x, cache-write 1.25x / 1h 2x, cache-read 0.1x, output 5x) — a flat sum is 89-99.7% cache-read (MEASURED) and tracks conversation length, not work. Scans subagent transcripts too (`<session>/subagents/*.jsonl`), follows no symlinks, reads only regular files (symlinked FILES and DIRECTORY components alike are skipped), and caps the walk BY RECENCY so a huge history cannot discard current usage. `pct` stays `null` while limits are unconfigured — an unconfigured estimate is never dressed up as a number |
|
|
227
|
-
| `cost-ledger` | `deriveCostLedger`, `buildCostLedger`, `verifyCostLedgerReport`, `stageCostAggregates`, `renderCostLedger`, `writeCostLedgerJsonl`, `COST_LEDGER_SCOPE` | Per-stage cost ledger behind `dz usage --by-stage`. A feature-adr run reports ONE number; this joins the workflow's own `stageLabel()` strings to the per-agent transcripts the harness already writes, so a run becomes an itemized receipt. POST-HOC DERIVER, not a writer — no workflow edit, and a KILLED run is still derivable. The invariant: `accounted + unaccounted === runTotal` and `accounted + doubleAttributed === Σ stages`, RAW integer equality (rounding happens exactly once, per sample, at extraction), re-derived from the emitted report by `verifyCostLedgerReport` — the writer clamps, the verifier enforces. A mismatch is a NAMED defect (`Unaccounted`, `DoubleAttributed`, `ForeignSample`, `MissingStageTranscript`, `MalformedRecord`), never a rounding remainder, so `epsilon` defaults to 0. The run total comes from the run's transcript DIRECTORY LISTING, NOT the record's own `totalTokens` — that field is exactly `Σ workflowProgress[].tokens` in 29 of 29 recorded runs (MEASURED), so an invariant against it can never fail. Both sides share ONE estimator with `dz usage` (`weightedTokensOf`). `stageCostAggregates` is a pure feed-forward reader for auto-cost routing that EXCLUDES non-reconciling runs; wiring it into routing is deliberately out of scope. HONEST SCOPE, printed by every surface: local transcript ESTIMATES, not billed amounts — it catches ATTRIBUTION errors, NOT pricing errors; `hasKnownPricing` marks rows priced by the sonnet-class fallback. `INSUFFICIENT_DATA` is a distinct verdict, never collapsed into `BALANCED` |
|
|
316
|
+
| `cost-ledger` | `deriveCostLedger`, `buildCostLedger`, `verifyCostLedgerReport`, `stageCostAggregates`, `renderCostLedger`, `writeCostLedgerJsonl`, `COST_LEDGER_SCOPE` | Per-stage cost ledger behind `dz usage --by-stage`. A feature-adr run reports ONE number; this joins the workflow's own `stageLabel()` strings to the per-agent transcripts the harness already writes, so a run becomes an itemized receipt. POST-HOC DERIVER, not a writer — no workflow edit, and a KILLED run is still derivable. The invariant: `accounted + unaccounted === runTotal` and `accounted + doubleAttributed === Σ stages`, RAW integer equality (rounding happens exactly once, per sample, at extraction), re-derived from the emitted report by `verifyCostLedgerReport` — the writer clamps, the verifier enforces. A mismatch is a NAMED defect (`Unaccounted`, `DoubleAttributed`, `ForeignSample`, `MissingStageTranscript`, `MalformedRecord`), never a rounding remainder, so `epsilon` defaults to 0. The run total comes from the run's transcript DIRECTORY LISTING, NOT the record's own `totalTokens` — that field is exactly `Σ workflowProgress[].tokens` in 29 of 29 recorded runs (MEASURED), so an invariant against it can never fail. Both sides share ONE estimator with `dz usage` (`weightedTokensOf`). `stageCostAggregates` is a pure feed-forward reader for auto-cost routing that EXCLUDES non-reconciling runs (now also `INCOMPLETE_INVENTORY` runs — the `!== 'BALANCED'` gate already excludes it, no second branch to forget); wiring it into routing is deliberately out of scope. HONEST SCOPE, printed by every surface: local transcript ESTIMATES, not billed amounts — it catches ATTRIBUTION errors, NOT pricing errors; `hasKnownPricing` marks rows priced by the sonnet-class fallback. `INSUFFICIENT_DATA` is a distinct verdict, never collapsed into `BALANCED`. **measurement-integrity (ADR-001 D1/D2):** every row also carries `stageCanonical` (the verbatim `stage` classified against `feature-adr-stage-canon.ts`'s one ordered table — see that module below — `'unknown'` when no rule matches, never silently folded into `infra`) plus `attempt`/`attempts` (a label repeated N times in one run is N separate rows, each tagged `attempt: i` of `attempts: N`, instead of one row silently summing them). The report gains `byCanonicalStage` (every canonical stage + `unknown` + `unattributed`, `{tokens, agents, attempts}`) and `reconciliation.orphanTranscripts` (`{count, tokens, ids, method}` — transcripts present in the run directory with NO `workflowProgress[]` entry; `method: 'per-transcript'` is an exact sum over each orphan's own samples, `'count-fallback'` is the best estimate when only ids are known). A run whose ONLY problem is a named orphan (nothing else defective) reports verdict `INCOMPLETE_INVENTORY` — outranks `BALANCED`, outranked by `DEFECT` — never the old `Unaccounted`/`DEFECT` pair that used to swallow the orphan into the generic bucket |
|
|
317
|
+
| `feature-adr-stage-canon` | `CANONICAL_STAGES`, `STAGE_LABEL_RULES`, `canonicalStage` | measurement-integrity ADR-001 D1: the canonical stage taxonomy — 11 pipeline stages (`router`, `requirements`, `research`, `adr`, `ideation`, `ddd`, `architecture`, `plan`, `code`, `qe`, `fleet`) + `infra` for the bookkeeping/plumbing labels around them. `canonicalStage(label)` classifies ONE verbatim `stageLabel()` string against ONE ordered prefix table (first match wins; a `label · model` suffix is matched on the part before ` · `) and returns `{stage, label, known}` — the input label is NEVER rewritten, only classified next to it. An unrecognised label is `{stage:'unknown', known:false}`, never silently `infra`. The completeness fixture (`test/feature-adr-stage-canon.test.ts`) is 47 labels copied verbatim from a live recorded run (`wf_5a7755c7-f92`) — Step 0's assessment counted 48 on the same record; a live reproducer counted 47, and the one-label gap does not change which prefixes are needed. Pure — no filesystem, no clock; the `core-boundary` ratchet pins it at zero `node:fs` imports |
|
|
318
|
+
| `codex-rollouts` | `parseCodexRollout`, `matchCodexRollouts` | measurement-integrity ADR-001 D3: a pure reader for Codex CLI rollout logs (`~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl`) — 130 of 156 recorded Codex ledger rows carry `tokens: null` even though the spend is sitting on disk, because the pipeline dispatches `codex exec` without an explicit session id. `parseCodexRollout(text, fileName?)` extracts `{id, cwd, model, startedAt, endedAt, totals}` from one file's TEXT (never opens a file itself — the CLI does that); it accepts BOTH the schema Step 0 documented (`type:"token_count"`, `payload.info.total_token_usage`) AND the schema actually observed live on this machine 2026-09-16, `cli_version 0.154.0` (`type:"token_usage_record"`, `payload.usage`; `model` on `turn_context`, not `session_meta`) — a reader that understood only a shape nothing on disk still emits would fail at the exact thing it exists to fix. `matchCodexRollouts(rollouts, {from, to, cwd?, model?})` joins a stage's time window to the rollout that produced its spend by INTERVAL OVERLAP, never "nearest in time" (two reviews back to back would misattribute) — `0` matches is `{status:'none'}`, `1` is `{status:'one', rollout}`, `>1` is `{status:'ambiguous', candidates}`, never a first-pick. Pure — the `core-boundary` ratchet pins it at zero `node:fs` imports |
|
|
228
319
|
| `compounding` | `mulberry32`, `bootstrapDelta`, `decidePromotion`, `assembleCompoundingReport`, `assembleLessonToRuleFunnel` | Pure learning-loop payoff engine behind `dz compounding`: seeded deterministic bootstrap (conservative nearest-rank lower-95), promotion that refuses non-finite/malformed input and anything under 5 samples per arm, and dz-native measurements (pool write-only ratio, guard trajectory by RATE, replay readiness over unique untruncated prompt events). Its lesson-to-rule funnel reports UTC calendar-month `eligible → attempted → accepted → executions` counts from prospective promotion-run and anchored guard-audit evidence. Zero alone is not a finding: only a non-empty predecessor followed by an empty named successor in three consecutive measured months produces one; unavailable evidence remains `NOT MEASURED` with its reason. Compaction keeps the newest query-bearing rows verbatim and aggregates ONLY the rest (read totals are invariant across compactions). Also reports EVENT-CHAIN health of the evidence logs it computed from (`evidenceLogs` in, `instrumentation.chains` out) — verified / defect kinds / uncovered pre-chain prefix, with no logs handed in producing no line at all rather than a vacuous "clean" |
|
|
229
320
|
| `event-chain` | `fnv1a32`, `nextChainFields`, `appendChainedLines`, `chainRewrite`, `guardedRewrite`, `verifyEventChain`, `EVENT_CHAIN_SCOPE` | Pure hash-chain over the two learning-evidence logs (`.dz/recall-usage.jsonl`, `.dz/guard-audit.jsonl`): each appended record carries `seq` + `prevHash` (FNV-1a over the previous line AS WRITTEN, so key order cannot make writer and verifier disagree), derived from the LAST LINE ONLY so a per-prompt hook stays O(1). `verifyEventChain` names eight classes — `BrokenLink`, `DuplicateSeq`, `NonMonotonicSeq`, `TornTail`, `DoubleCounted`, `LedgerImbalance`, `MalformedLedger`, `ClaimInterrupted`. The last four exist because a rewriter must not be able to certify itself: the compaction ledger's arithmetic (`Σ weight + dropped === source`, `dropped ∈ [0, source]`) is enforced with NO clamps in the verifier (the clamp belongs to the writer), a damaged ledger line is a defect rather than a silently-disabled check, and a claim that never reached its `throughSeq` — because the segment restarted or the file ended — is reported instead of escaping through the discontinuity. `guardedRewrite` is the concurrency guard for any whole-file rewrite: exclusive lock, plus a re-read of the live file after computing the new text and BEFORE the rename, so a concurrent append aborts the attempt and is folded into a bounded retry rather than overwritten (it narrows the read→rename window; it cannot close it, and says so). Records written before chaining existed stay LEGAL and are counted as an uncovered `preChainPrefix`; an unreadable tail never blocks a write (fresh MARKED segment — an unreadable tail WINDOW is distinguished from an empty file — and the appender starts on a new line so one torn write cannot eat the next record); an unmarked restart is reported once and then re-anchored, so one incident is one defect instead of a cascade. HONEST SCOPE, carried in every result and printed by every surface: corruption detection for our own bugs — FNV-1a is not cryptography, its collisions are constructible, the threat model has no adversary, and a regression test fails if the module regrows tamper-proofing vocabulary |
|
|
230
321
|
| `feature-adr-checkpoints` | `checkpointInputHash`, `decideCheckpointResume`, `parseCheckpointRead`, `serializeCheckpoint`, `fnv1a64`, `CKPT_SCHEMA_VERSION`, `STAGE_ARTIFACTS`, `DESIGN_SUBSTAGES`, `designStageKey`, `decideDesignFanResume`, `parseArtifactProbe` | The PURE half of feature-adr's durable per-stage checkpoints (`features/<slug>/.fa-state/checkpoints.jsonl`): a dead L/XL run — or the standard stop-after-plan re-invoke — resumes completed stages instead of re-spending them. Resume = INPUT-identity (64-bit salted FNV over a schema-versioned JSON tuple incl. upstream stage results) + presence of EVERY tier-required artifact; a stale-input hash never resumes in ANY mode (`force` relaxes only the artifact probe — the tested load-bearing property). HONEST SCOPE: it does NOT fingerprint the working tree (a crash-resume legitimately sees the dead run's uncommitted writes) — after manual edits use `resume:'never'` and re-QE. Null results are never persisted or resumable; a stage-identifiable corrupt record ERASES its older entry (last-wins holds for corruption too); the code stage's persist predicate is now an ALLOWLIST (`codeCheckpointPersistAllowed` + `codeStageResultShapeValid`, ADR-003 Condition 3): ONLY `landed` on a barrier-required run and `synchronous` on a non-barrier run may be checkpointed — inconclusive, not-landed, garbage and a mislabeled `synchronous` are all refused, and the `landing-v2` hash token makes every pre-protocol code checkpoint stale. **Since 0.5.3 the design fan is checkpointed PER SIBLING** (`design:requirements` / `adr` / `qcsd` / `architecture` via `designStageKey`), so one dead agent no longer discards three finished siblings, and a fix to one step's instructions invalidates that step alone. What may be CONSUMED is judged separately from what may be WRITTEN: `decideDesignFanResume` returns a named reason (`substage-missing` / `artifact-missing` / `probe-not-established` / `ok`) and the workflow REFUSES at the Step-5/6 boundary rather than planning off a partial design. The artifact half is judged against a POST-RUN probe that never prints filenames (`[ -f <exact rel> ]` per required artifact) — a listing is a list of filenames, and a file whose NAME ends in a newline was measured satisfying the requirement for the real file. `parseArtifactProbe` then validates the WHOLE transcript, because the probe is relayed by a model: an agent that merely NARRATES the expected output emits the token byte-identically. Inconclusive is never a pass. The workflow mirrors this inline (wiring-guarded); RU: чекпоинт после каждой дорогой стадии — упавший ран возобновляется, а не пере-тратит завершённое; веер проектирования — по каждому участнику отдельно, а неполный веер получает отказ, а не запись в лог |
|
|
@@ -1062,12 +1153,17 @@ the second case, so a broken store no longer looks like plain "fewer lessons".
|
|
|
1062
1153
|
|
|
1063
1154
|
## Embedder cache (`agentdb-index.ts` — `resolveAgentdbEmbedder`)
|
|
1064
1155
|
|
|
1065
|
-
`resolveAgentdbEmbedder(projectRoot)`
|
|
1066
|
-
|
|
1067
|
-
(`features/agentdb-embedder-cache/00_complexity_assessment.md`), because the model+dim for a
|
|
1068
|
-
project never changes within one process.
|
|
1069
|
-
|
|
1070
|
-
`
|
|
1156
|
+
`resolveAgentdbEmbedder(projectRoot, dbPath?)` builds the `@huggingface/transformers` pipeline
|
|
1157
|
+
**directly** — MEASURED 2026-09-14 at 2-3.6s per call
|
|
1158
|
+
(`features/agentdb-embedder-cache/00_complexity_assessment.md`), because the model+dim+dtype for a
|
|
1159
|
+
project never changes within one process. Feature `embed-daemon-memory` (ADR-001 D1) moved this off
|
|
1160
|
+
agentdb's own `EmbeddingService` class: the same `pipeline(text, { pooling: 'mean', normalize: true })`
|
|
1161
|
+
call `EmbeddingService.embed` makes internally, called straight from core, so a process building
|
|
1162
|
+
BOTH the write path (`indexPatternsToAgentdb`) and the read path (`searchAgentdbPatterns`) — or the
|
|
1163
|
+
embed daemon, when it can reach this same cache (see below) — stands up **one** pipeline instance,
|
|
1164
|
+
not one per code path. Cached at module scope, keyed by `${agentdbDir}|${model}|${dim}|${dtype}` (so
|
|
1165
|
+
a `DZ_EMBED_MODEL`/`.dz/config.json` change — a different `resolveEmbedModel` result, or a different
|
|
1166
|
+
dtype — gets its own entry rather than reusing a stale pipeline):
|
|
1071
1167
|
|
|
1072
1168
|
- Repeat calls for the same key return the **same object**, not a re-initialized one — MEASURED
|
|
1073
1169
|
2026-09-14 (`test/agentdb-embedder-cache.test.ts`, live model): cold call `2117ms`, warm call
|
|
@@ -1081,6 +1177,41 @@ project never changes within one process. It is now cached at module scope, keye
|
|
|
1081
1177
|
tests and future warm-start use only — `vector-tier.ts`/`backlog.ts` call sites are unaffected.
|
|
1082
1178
|
- `getAgentdbEmbedderCacheStats()` returns `{ entries, initializations }` (`entries` = currently
|
|
1083
1179
|
cached successful pipelines, `initializations` = pipelines actually started since the last reset).
|
|
1180
|
+
- **COMPAT FALLBACK** (dtype `fp32` only): when `@huggingface/transformers`/`@xenova/transformers`
|
|
1181
|
+
cannot be resolved directly from the project (nor via `agentdb`'s own declared dependency), this
|
|
1182
|
+
falls back to agentdb's `EmbeddingService` — the pre-T2 behaviour — so a project whose only route
|
|
1183
|
+
to an embedder is through agentdb's own installed copy still works. A requested `dtype: 'q8'` never
|
|
1184
|
+
takes this fallback (NFR-4): a quantized store with no reachable transformers install is a hard
|
|
1185
|
+
`{error}` naming the model/dtype, never a silent fp32 downgrade.
|
|
1186
|
+
|
|
1187
|
+
### dtype: `fp32` vs `q8` (`memory.embed.dtype`, ADR-001 D2)
|
|
1188
|
+
|
|
1189
|
+
A single fp32 instance of the default model (`Xenova/paraphrase-multilingual-MiniLM-L12-v2`) costs
|
|
1190
|
+
~1.2 GB RSS once warm (816 MB immediately, ~1219 MB 1-2s after the first embed — a second, native
|
|
1191
|
+
weight read inside `onnxruntime`, library behaviour, not something this package controls). The
|
|
1192
|
+
quantized `q8` variant (`{ dtype: 'q8' }` at pipeline construction, needs `model_quantized.onnx` in
|
|
1193
|
+
the transformers cache) costs ~0.55 GB — roughly half — at a MEASURED (2026-09-16, 14-lesson RU/EN
|
|
1194
|
+
fixture, `features/embed-daemon-memory/07_code_changes/measure-q8-parity.mjs`) cosine parity of
|
|
1195
|
+
min=0.9900/mean=0.9929 against fp32 for the SAME text, and top-1 query agreement 5/5.
|
|
1196
|
+
|
|
1197
|
+
- `memory.embed.dtype` in `.dz/config.json` (`'fp32'` default, `'q8'` opt-in) selects the dtype for a
|
|
1198
|
+
**new** index or a `dz vector reindex` — it does **not** retroactively change an existing store.
|
|
1199
|
+
- The **store's manifest** (`<dbFile>.embed-manifest.json`) records the dtype it was actually built
|
|
1200
|
+
with; every query is embedded with the **manifest's** dtype (`resolveStoreEmbedDtype`), never
|
|
1201
|
+
blindly with the configured one — a manifest with no `dtype` field (every store written before
|
|
1202
|
+
this feature) reads as `fp32`, so existing stores are unaffected.
|
|
1203
|
+
- `guardEmbedSpace` now checks dtype the same way it already checks model/dim: a store built at one
|
|
1204
|
+
dtype and configured for the other is refused with `embedding dtype mismatch: index built with
|
|
1205
|
+
<m>, configured <c>; run <reindexHint>` — never a silent mixed-dtype read (store fp32, query q8),
|
|
1206
|
+
which the ADR names as the concrete risk a default flip would have created.
|
|
1207
|
+
- Switching a store to `q8` is exactly `dz vector reindex` after setting `memory.embed.dtype: 'q8'`
|
|
1208
|
+
— the ONLY point the dtype actually changes; an ordinary incremental index always embeds new rows
|
|
1209
|
+
in the store's EXISTING dtype, never the config's, so two partial writes can never leave one store
|
|
1210
|
+
split across two embedding spaces.
|
|
1211
|
+
- `q8` needs `model_quantized.onnx` already in the transformers cache — a fresh install with no
|
|
1212
|
+
cached weights would need network access on first use; confirm the file is present under the
|
|
1213
|
+
transformers cache dir (or that the machine has network access) before flipping `memory.embed.dtype`
|
|
1214
|
+
to `q8` and running `dz vector reindex`.
|
|
1084
1215
|
|
|
1085
1216
|
## Consistent pre-reindex snapshot + rollback (`agentdb-snapshot.ts`)
|
|
1086
1217
|
|
|
@@ -1277,9 +1408,105 @@ had NO mutual exclusion, and only the 10-minute grace period above stood between
|
|
|
1277
1408
|
`rotatePreReindexSnapshots`, which always takes the snapshot lock. Exporting the unlocked primitive
|
|
1278
1409
|
would hand outside callers a way to rotate with no mutual exclusion at all.
|
|
1279
1410
|
|
|
1411
|
+
## Findings ledger + machine-readable QE verdict (`qe-findings.ts`, ADR-001 `qe-findings-record`)
|
|
1412
|
+
|
|
1413
|
+
`readQeGrade` (`score.ts`) used to read only PROSE — a report fixed after a `Grade: C` round-1
|
|
1414
|
+
review, ending `Grade: B`, read back as `ambiguous`, and a report whose only "Grade" mention was a
|
|
1415
|
+
stray round-1 line read as a confidently-WRONG `unique C` even when its final verdict was `B`
|
|
1416
|
+
(MEASURED, `00_complexity_assessment.md`: 41 of 100 feature reports came back ambiguous; `dz score`
|
|
1417
|
+
returned `C` for a report whose stated outcome was `B`). This feature adds ONE machine-readable
|
|
1418
|
+
surface on top of the prose, never replacing it:
|
|
1419
|
+
|
|
1420
|
+
- **A verdict line**: `QE-VERDICT: <A|A-|A+|B|B+|B-|C|C+|C-|D>` (`QE_VERDICT_RE`, `qe-findings.ts`).
|
|
1421
|
+
`readQeGrade` checks it FIRST: exactly one → `{status:'unique', source:'verdict-line'}`; more than
|
|
1422
|
+
one → `{status:'ambiguous', source:'verdict-line'}` (never "last wins", even when both name the
|
|
1423
|
+
same grade — two lines is a fact about the report); zero → the pre-existing prose scan runs
|
|
1424
|
+
exactly as before, tagged `source:'prose'` (or `'none'`). `GradeReading` gained the `source` field;
|
|
1425
|
+
every prior caller of `readQeGrade`/`extractQeGrade` is unaffected (NFR-1).
|
|
1426
|
+
- **A Findings ledger table** under the exact header `QE_FINDINGS_HEADER` = `| Finding | Severity |
|
|
1427
|
+
Status | Round | Author | Title |`. `parseQeFindings(md)` returns `{status:'absent'}` when no such
|
|
1428
|
+
table exists (406 pre-existing reports; the common case, and the ONLY case for anything written
|
|
1429
|
+
before this feature), or `{status:'present', hollow, rows, refused, summary}`. Three closed
|
|
1430
|
+
dictionaries — Severity `BLOCKER|CRITICAL|HIGH|MEDIUM|LOW|INFO`, Status
|
|
1431
|
+
`confirmed|fixed|partial|refuted|named-limit|open`, Author `codex|claude|lead` — plus Round (an
|
|
1432
|
+
integer ≥ 1) and a whitespace-free Finding id. **A row outside any dictionary is REFUSED
|
|
1433
|
+
(`{line, text, reason}`), never coerced to the nearest known value** — coercion would make the
|
|
1434
|
+
resulting severity/status tally unprovable (ADR-001 D2). **A second table is refused WHOLE**, its
|
|
1435
|
+
header the anchor, reason `duplicate table` — its rows are never parsed individually. **A
|
|
1436
|
+
header-only table is `hollow: true`** — worse than no table at all (ADR-001 D3, the same principle
|
|
1437
|
+
`readMutationEvidence`'s `present-unproven` already applies to the mutation-gate table).
|
|
1438
|
+
- `qe-findings.ts` is PURE (no `node:fs`) — file reads stay in the CLI, guarded by the same
|
|
1439
|
+
`core-boundary.ts` IO ratchet every other core module answers to.
|
|
1440
|
+
- `scoreRun` (`score.ts`) now returns `gradeSource` and `findings` (a lighter `{status, hollow?,
|
|
1441
|
+
summary?, refused?}` projection of `parseQeFindings`'s full result) — both ADDITIVE, the same
|
|
1442
|
+
optional-field discipline `mutationEvidence` already uses. `renderScorecard`/`renderFindingsLine`
|
|
1443
|
+
print a one-line findings summary (`findings: 3 HIGH / 2 MEDIUM; 1 refused (line 84: severity
|
|
1444
|
+
"Major" not in dictionary)`) only when a table exists — the common case (no table) stays silent.
|
|
1445
|
+
- `dz feature-adr-record --kind ledger --stage full` enriches the row with `findings`/`gradeSource`
|
|
1446
|
+
computed by this parser over the row's own `features/<slug>/08_qe_report.md` (fill-only-null,
|
|
1447
|
+
best-effort — a missing/unreadable report never blocks the write). See the CLI README for the
|
|
1448
|
+
producer-side prompt wiring (Step 8's `QE-VERDICT:` + table instruction) and the six September
|
|
1449
|
+
reports hand-marked from their own prose as the real-corpus proof (`qe-findings-corpus.test.ts`).
|
|
1450
|
+
|
|
1280
1451
|
## Status
|
|
1281
1452
|
|
|
1282
|
-
`
|
|
1453
|
+
`next` — staged, not yet versioned or published. Feature `measurement-integrity` (ADR-001, tier M): five
|
|
1454
|
+
measurement holes in the SDD pipeline get an explicit status instead of a convenient number. **D1/D2** land in
|
|
1455
|
+
`cost-ledger.ts` and the new `feature-adr-stage-canon.ts` (see the module table above) — canonical stage
|
|
1456
|
+
taxonomy + `INCOMPLETE_INVENTORY`/`orphanTranscripts`. **D3** is the new `codex-rollouts.ts` (module table
|
|
1457
|
+
above) — a pure Codex rollout-log reader. **D3/D4** land in `run-records.ts`: `decideRecordWrite` gains an
|
|
1458
|
+
OPT-IN `enrich?: LedgerEnrichInput` (`{rollouts?, window?, cwd?, prices?}`) — a ledger row with a codex-family
|
|
1459
|
+
`coder`/`reviewer` and `tokens: null`, given a time window, is enriched via `matchCodexRollouts`:
|
|
1460
|
+
`status:'one'` fills `tokens`/`minutes`/`tokensSource:'codex-rollout'`/`rolloutId`; `'none'`/`'ambiguous'`
|
|
1461
|
+
stamp `tokensSource:'codex-rollout:'+status` with NO number (NFR-3 — never a guess); no `window` at all
|
|
1462
|
+
stamps `tokensSource:'unavailable'` rather than attempting nothing silently. Independently, ANY ledger row
|
|
1463
|
+
given a `prices` table gets a `prices: {snapshotAt, table: {model: {prompt, completion, cachedInput}},
|
|
1464
|
+
unknown?: [model,…]}` snapshot for every model it names (`coder`/`reviewer`/`envelope.chosen.stages`) — a
|
|
1465
|
+
longest-prefix match against the CALLER'S OWN table (never `cost-scoring.ts`'s live constant), so a future
|
|
1466
|
+
repricing never rewrites a historical row (ADR-001 D4). Omitting `enrich` entirely is byte-identical to
|
|
1467
|
+
before this feature. **D5** lands in `round.ts`: `closeRound` gains `grade?`/`reviewSidecar?
|
|
1468
|
+
(RoundReviewSidecar: {gradedBy, elapsedMs, grade?})`. `grade` is now MANDATORY for `outcome ∈
|
|
1469
|
+
{shipped,refuted}` (refusal exit 2, `'grade required for a finished review'`) and a warned-and-DROPPED no-op
|
|
1470
|
+
for `blocked|abandoned` (the close still succeeds; `result.warnings` names why nothing was written).
|
|
1471
|
+
`RoundLedgerRow.grade` is `string | null` (was always `null`). When `--reviewer` is absent, `reviewer` /
|
|
1472
|
+
`reviewMinutes` (`elapsedMs / 60000`, 1 decimal) / `reviewSource:'qe-bridge'` are filled from the sidecar; a
|
|
1473
|
+
`--grade` that disagrees with the sidecar's OWN grade is refused naming both. The CLI (`dz round close
|
|
1474
|
+
--grade`) reads the sidecar from `features/<slug>/.fa-state/qe-bridge/signoff-*.json`, latest by `emittedAt`
|
|
1475
|
+
— `round.ts` itself opens no file. `dz feature-adr-record --kind ledger` grows `--window-from/--window-to`
|
|
1476
|
+
+ `--codex-sessions <dir>` (default `~/.codex/sessions`) to drive the FR-5 enrichment; every ledger write
|
|
1477
|
+
always carries the FR-6 price snapshot.
|
|
1478
|
+
|
|
1479
|
+
`plan-inherits-requirements`: the pure halves of the
|
|
1480
|
+
feature-adr plan-repair round now live here and are body-pinned against the workflow's inline copies by the
|
|
1481
|
+
drift guard — `shellQuote` (POSIX single-quote escaping), `planBackupCmd` / `planRestoreCmd` /
|
|
1482
|
+
`planArchiveBackupCmd` (backup before the ONE repair round, proven restore on rejection, archive into
|
|
1483
|
+
`.fa-state/` on acceptance), `planSnapshotCmd` (byte length, POSIX `cksum`, the `EXPECTED_CODE_TARGETS` lines
|
|
1484
|
+
and the task-heading lines), `snapshotBlock` / `snapshotNumber` (whole-line markers, first start to last end —
|
|
1485
|
+
a plan line spelling a marker lands inside its block) and `parsePlanSnapshot` (null = the probe never completed;
|
|
1486
|
+
the caller rejects on null, never reads it as "nothing to compare"). `planCompletenessGateCmd` gained
|
|
1487
|
+
`opts.requireRequirements`, which emits `--require-requirements` so the K2 gate's new C8 (every id declared in
|
|
1488
|
+
`01_requirements.md` is referenced by the plan) fails per id instead of warning with a count.
|
|
1489
|
+
Also in this staged release (feature `coder-reads-and-recall`): the decision-recall kind union gained
|
|
1490
|
+
`'code-implementation'` (stage `step-7`, bandit context `feature-adr-decision-code-implementation`) so the
|
|
1491
|
+
Step-7 coder receives the same ≤3-lesson recall block the Step-6 planner already gets, bundled into the code
|
|
1492
|
+
stage's checkpoint composite exactly like `planComposite` — a resumed stage restores the recalled prompt for
|
|
1493
|
+
the training-pair capture instead of re-spending recall. Measured motive: after the by-name input directive,
|
|
1494
|
+
Claude coders opened `01_requirements.md` in 5 of 7 runs (39 % before), while 37 of 48 post-directive coders
|
|
1495
|
+
were Codex, whose file reads are invisible to the transcript instrument.
|
|
1496
|
+
|
|
1497
|
+
`0.8.37` — this release (night 16→17.09). Five changes live in this package, each through the full pipeline with a
|
|
1498
|
+
cross-family Codex review: **qe-findings** — every Step-8 report now carries one machine-readable `QE-VERDICT:` line
|
|
1499
|
+
and a `## Findings ledger` table in a closed vocabulary (`parseQeFindings`, `readQeGrade` with its source; masks for
|
|
1500
|
+
fenced code, blockquotes incl. CommonMark lazy continuation, HTML comments/blockquotes; a near-miss table is refused
|
|
1501
|
+
loudly, never read as absent); **cross-family-control** — `diffFamilyFindings`/`aggregateByFamily` for `dz
|
|
1502
|
+
control-review`: two independent reviews over one tree, automatic pairs are CANDIDATES (maximum-cardinality
|
|
1503
|
+
matching), confirmed overlap only by adjudication, incomplete rows excluded from measured figures;
|
|
1504
|
+
**measurement-integrity** — canonical stages, `INCOMPLETE_INVENTORY`, per-turn Codex rollout deltas, price
|
|
1505
|
+
snapshots, `round close --grade` mandatory for shipped/refuted; **experiment-envelope** — every automatic ledger row
|
|
1506
|
+
carries `envelope.{taskKind,priority,arms,chosen,evaluator}` (verified live: 1 of 1 new auto rows); **qe-bridge** —
|
|
1507
|
+
the reviewer prompt demands ONE grade letter with no +/− suffix (a live `B-` was refused as no-grade-marker).
|
|
1508
|
+
|
|
1509
|
+
`0.8.36` — (night 15→16.09). Three changes live in this package: `recallHybrid` orders equal-scoring
|
|
1283
1510
|
hits through ONE comparator (score desc → evidence rank → `dzId` asc, NaN last), so the embed daemon and
|
|
1284
1511
|
`dz recall` agree; the apply-leg test helpers prove a daemon stop by OBSERVING `/proc` until nothing serves the
|
|
1285
1512
|
root and gate every SIGKILL on a freshly-read identity plus containment under the test root (three-valued —
|
package/dist/agentdb-index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { type SnapshotRotationReport } from './agentdb-snapshot-rotation.js';
|
|
15
15
|
import { type SnapshotMethod } from './agentdb-snapshot.js';
|
|
16
|
+
import { type EmbedDtype } from './embedding-config.js';
|
|
16
17
|
/** One record to index. `text` is stored as `approach` AND embedded (`${taskType}: ${text}`). */
|
|
17
18
|
export interface AgentdbRow {
|
|
18
19
|
readonly taskType: string;
|
|
@@ -26,7 +27,15 @@ export interface AgentdbRow {
|
|
|
26
27
|
}
|
|
27
28
|
/** Outcome of {@link indexPatternsToAgentdb}. `generationBumped`/`generationReason` are present only
|
|
28
29
|
* when a store write actually happened (`indexed > 0`) — FR-4: a failed counter write NEVER fails
|
|
29
|
-
* the indexing call itself, it is only reported so a caller (`dz doctor`, telemetry) can see it.
|
|
30
|
+
* the indexing call itself, it is only reported so a caller (`dz doctor`, telemetry) can see it.
|
|
31
|
+
*
|
|
32
|
+
* Fix-round 1 (CRITICAL, item 1a): `indexed`/`generationBumped`/`generationReason` and `error` are
|
|
33
|
+
* NOT mutually exclusive. A failure AFTER the row commit (today, only `writeEmbedManifest` throwing)
|
|
34
|
+
* reports the REAL `indexed` count and the REAL bump outcome alongside `error` — it never collapses
|
|
35
|
+
* back to `{indexed: 0, error}` once rows are already on disk. Collapsing to `indexed: 0` after a
|
|
36
|
+
* real commit was the CRITICAL finding: a caller reading `indexed === 0` as "nothing happened" would
|
|
37
|
+
* skip its own rescue-bump logic even though the store had genuinely changed — an under-bump C-1
|
|
38
|
+
* forbids. */
|
|
30
39
|
export interface AgentdbIndexResult {
|
|
31
40
|
readonly indexed: number;
|
|
32
41
|
readonly error?: string | undefined;
|
|
@@ -72,7 +81,17 @@ export declare function ensureAgentdbSchema(projectRoot: string, dbPath?: string
|
|
|
72
81
|
* to decide validity, only to convert an already-validated string.
|
|
73
82
|
*/
|
|
74
83
|
export declare function readStoreGeneration(projectRoot: string, dbPath?: string): number;
|
|
75
|
-
|
|
84
|
+
/** Fix-round 1, item 5: `String(err)` itself can throw if `err` carries a poisoned `toString` (or
|
|
85
|
+
* `Error.prototype.message` getter). `bumpStoreGeneration`'s "never throws" contract (FR-4) is
|
|
86
|
+
* ABSOLUTE, so every place in this function that turns a caught error into a string goes through
|
|
87
|
+
* this ONE protected helper — never a bare `err instanceof Error ? err.message : String(err)`.
|
|
88
|
+
* Exported test-only (same convention as {@link needsRescueBump}/{@link resetAgentdbEmbedderCache}).
|
|
89
|
+
*/
|
|
90
|
+
export declare function safeErrorMessage(err: unknown): string;
|
|
91
|
+
export declare function bumpStoreGeneration(projectRoot: string, dbPath?: string,
|
|
92
|
+
/** T2: the ONLY signature extension the plan permits — injectable wall clock, default `Date.now`,
|
|
93
|
+
* so AC-3 (a rolled-back system clock) can be reproduced without touching the real clock. */
|
|
94
|
+
now?: () => number): {
|
|
76
95
|
readonly ok: true;
|
|
77
96
|
readonly generation: number;
|
|
78
97
|
} | {
|
|
@@ -131,17 +150,60 @@ type Embedder = {
|
|
|
131
150
|
export declare function resetAgentdbEmbedderCache(): void;
|
|
132
151
|
/** `entries` = cached keys right now — a SUCCESSFUL pipeline or an IN-FLIGHT initialization (the promise is
|
|
133
152
|
* cached before it settles, FR-4; a failed one is evicted, FR-3); `initializations` = pipelines actually
|
|
134
|
-
* started since the last reset. (Codex round-1, 2026-09-14: the earlier wording said "successful" only.)
|
|
153
|
+
* started since the last reset. (Codex round-1, 2026-09-14: the earlier wording said "successful" only.)
|
|
154
|
+
* `pipelinesBuilt` (fix round 1, F6) = the count of REAL pipeline-construction primitives that actually
|
|
155
|
+
* ran (`pipeline()` or `EmbeddingService.initialize()`), never merely the number of times the resolver
|
|
156
|
+
* was entered — see {@link embedderCachePipelinesBuilt}'s own doc comment for why the two can diverge. */
|
|
135
157
|
export declare function getAgentdbEmbedderCacheStats(): {
|
|
136
158
|
entries: number;
|
|
137
159
|
initializations: number;
|
|
160
|
+
pipelinesBuilt: number;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* C-3 (`embed-daemon-memory`): the SAME resolution order the daemon's own `resolveDeps` uses
|
|
164
|
+
* (`.claude/helpers/dz-embed-daemon.mjs`) — project `package.json` first, then `agentdb`'s own
|
|
165
|
+
* declared dependency (possibly hoisted elsewhere) — so core and the daemon agree on which install
|
|
166
|
+
* of transformers they find, in a monorepo or a plain install alike. Each candidate root is
|
|
167
|
+
* confirmed by {@link findAncestorWithModule} BEFORE `require.resolve` is trusted (see its own doc
|
|
168
|
+
* comment for why the plain try/catch this replaced was not safe under this package's test runner).
|
|
169
|
+
*
|
|
170
|
+
* Exported (fix round 1, F4, same convention as {@link safeErrorMessage}/{@link resetAgentdbEmbedderCache}):
|
|
171
|
+
* `embedder-single-owner.test.ts`'s live-dep skip gate needs the SAME resolution order the production
|
|
172
|
+
* code uses to decide, BEFORE running, whether a live embedder failure is a dependency gap (named skip)
|
|
173
|
+
* or a real defect (must fail) — a text-matching heuristic on the error message cannot tell those apart.
|
|
174
|
+
*/
|
|
175
|
+
export declare function resolveTransformersModule(projectRoot: string): {
|
|
176
|
+
url: string;
|
|
177
|
+
} | {
|
|
178
|
+
error: string;
|
|
138
179
|
};
|
|
139
180
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
181
|
+
* D2 (`embed-daemon-memory`): the dtype a QUERY/write is embedded with is the STORE's own dtype
|
|
182
|
+
* (its manifest) when the store already exists, falling back to the CONFIGURED dtype only for a
|
|
183
|
+
* store that does not exist yet (its first-ever write picks up the config). This is the ONE place
|
|
184
|
+
* that decision is made — {@link resolveAgentdbEmbedder} calls it so every caller (search, an
|
|
185
|
+
* ordinary incremental index) agrees; `reindexAgentdbRows` is the sole exception (T2/plan): it
|
|
186
|
+
* stamps the manifest with the NEW configured dtype BEFORE it re-embeds, so by the time this
|
|
187
|
+
* function runs during a reindex the manifest already names the new dtype — config and manifest
|
|
188
|
+
* necessarily agree at that point, which is what makes reindex "the one place dtype changes".
|
|
143
189
|
*/
|
|
144
|
-
export declare function
|
|
190
|
+
export declare function resolveStoreEmbedDtype(projectRoot: string, dbPath?: string): EmbedDtype | {
|
|
191
|
+
error: string;
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Resolve the shared embedder from the PROJECT (same dynamic-resolution discipline as
|
|
195
|
+
* {@link indexPatternsToAgentdb}); every dz call site uses the same resolved model/dtype so query
|
|
196
|
+
* and row vectors stay in the same space. Cached per process — see {@link embedderCache} above.
|
|
197
|
+
*
|
|
198
|
+
* Fix round 1 (F1, doc correction — the prior wording was misleading): `dbPath` is passed straight
|
|
199
|
+
* to {@link resolveStoreEmbedDtype}, which calls {@link resolveAgentdbPath}`(projectRoot, dbPath)` —
|
|
200
|
+
* and THAT function already returns the project's DEFAULT store path (`<project>/.dz/agentdb.db`,
|
|
201
|
+
* or `AGENTDB_PATH`) when `dbPath` is omitted, not "no path". So an omitted `dbPath` still reads the
|
|
202
|
+
* default store's OWN manifest when one exists; the CONFIGURED dtype is used only as the fallback
|
|
203
|
+
* for a store that has no manifest yet (i.e. does not exist, or predates this feature) — never as
|
|
204
|
+
* the default behaviour for "no dbPath given".
|
|
205
|
+
*/
|
|
206
|
+
export declare function resolveAgentdbEmbedder(projectRoot: string, dbPath?: string): Promise<Embedder>;
|
|
145
207
|
/**
|
|
146
208
|
* Cosine similarity in [-1, 1] over two embeddings. Exported (was file-private) so
|
|
147
209
|
* `harmonizeVectorStore` scores near-duplicate pairs with the IDENTICAL math the semantic search
|
|
@@ -248,6 +310,24 @@ export declare function bumpAgentdbUses(projectRoot: string, dzIds: readonly str
|
|
|
248
310
|
bumped: number;
|
|
249
311
|
error?: string;
|
|
250
312
|
};
|
|
313
|
+
/**
|
|
314
|
+
* Fix-round 1 (CRITICAL, item 1b — the belt): whether {@link reindexAgentdbRows} must run its own
|
|
315
|
+
* rescue bump, given the DELETE's own observed `changes` count and the nested
|
|
316
|
+
* {@link indexPatternsToAgentdb} call's result. Exported test-only (same convention as
|
|
317
|
+
* {@link resetAgentdbEmbedderCache}) so the DECISION can be exercised directly and deterministically,
|
|
318
|
+
* independent of forcing a real concurrent bump-lock race.
|
|
319
|
+
*
|
|
320
|
+
* `!nestedBumped && (deleteChanges > 0 || indexed.indexed > 0 || indexed.error !== undefined)`:
|
|
321
|
+
* - `deleteChanges > 0` — the DELETE genuinely removed rows; the store changed regardless of the
|
|
322
|
+
* nested call's outcome.
|
|
323
|
+
* - `indexed.indexed > 0` — the nested call committed rows itself but its OWN bump failed
|
|
324
|
+
* (`generationBumped: false`) or was never attempted.
|
|
325
|
+
* - `indexed.error !== undefined` — the nested call's post-write state is UNKNOWN (item 1a: an error
|
|
326
|
+
* here may still carry accurate `indexed`/`generationBumped` facts, but a caller must not assume a
|
|
327
|
+
* future error path will). C-1: when in doubt, bump — an extra bump only over-invalidates a cache
|
|
328
|
+
* (safe), a missed one serves stale data (not safe).
|
|
329
|
+
*/
|
|
330
|
+
export declare function needsRescueBump(deleteChanges: number, indexed: AgentdbIndexResult): boolean;
|
|
251
331
|
export declare function reindexAgentdbRows(projectRoot: string, rows: readonly AgentdbRow[], opts?: {
|
|
252
332
|
dbPath?: string;
|
|
253
333
|
taskTypes?: readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentdb-index.d.ts","sourceRoot":"","sources":["../src/agentdb-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,OAAO,EAAqC,KAAK,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAChH,OAAO,EAAiD,KAAK,cAAc,EAAuB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"agentdb-index.d.ts","sourceRoot":"","sources":["../src/agentdb-index.ts"],"names":[],"mappings":"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"}
|