@dzhechkov/harness-core 0.8.30 → 0.8.31

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.
Files changed (129) hide show
  1. package/.dz-manifest.json +233 -93
  2. package/README.md +269 -0
  3. package/dist/agentdb-index.d.ts +45 -0
  4. package/dist/agentdb-index.d.ts.map +1 -1
  5. package/dist/agentdb-index.js +345 -85
  6. package/dist/agentdb-index.js.map +1 -1
  7. package/dist/agentdb-reindex-marker.d.ts +170 -0
  8. package/dist/agentdb-reindex-marker.d.ts.map +1 -0
  9. package/dist/agentdb-reindex-marker.js +293 -0
  10. package/dist/agentdb-reindex-marker.js.map +1 -0
  11. package/dist/agentdb-snapshot-rotation.d.ts +169 -0
  12. package/dist/agentdb-snapshot-rotation.d.ts.map +1 -0
  13. package/dist/agentdb-snapshot-rotation.js +322 -0
  14. package/dist/agentdb-snapshot-rotation.js.map +1 -0
  15. package/dist/agentdb-snapshot.d.ts +126 -0
  16. package/dist/agentdb-snapshot.d.ts.map +1 -0
  17. package/dist/agentdb-snapshot.js +195 -0
  18. package/dist/agentdb-snapshot.js.map +1 -0
  19. package/dist/apply-leg.d.ts +202 -0
  20. package/dist/apply-leg.d.ts.map +1 -0
  21. package/dist/apply-leg.js +975 -0
  22. package/dist/apply-leg.js.map +1 -0
  23. package/dist/book-kb.d.ts.map +1 -1
  24. package/dist/book-kb.js +57 -1
  25. package/dist/book-kb.js.map +1 -1
  26. package/dist/brain.d.ts +3 -0
  27. package/dist/brain.d.ts.map +1 -1
  28. package/dist/brain.js +1 -1
  29. package/dist/brain.js.map +1 -1
  30. package/dist/cadence.d.ts +30 -1
  31. package/dist/cadence.d.ts.map +1 -1
  32. package/dist/cadence.js +66 -2
  33. package/dist/cadence.js.map +1 -1
  34. package/dist/guard.d.ts +14 -0
  35. package/dist/guard.d.ts.map +1 -1
  36. package/dist/guard.js +36 -0
  37. package/dist/guard.js.map +1 -1
  38. package/dist/index.d.ts +23 -8
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +18 -5
  41. package/dist/index.js.map +1 -1
  42. package/dist/integration-probe-worker.d.ts.map +1 -1
  43. package/dist/integration-probe-worker.js +4 -6
  44. package/dist/integration-probe-worker.js.map +1 -1
  45. package/dist/integrations-verify.d.ts.map +1 -1
  46. package/dist/integrations-verify.js +3 -1
  47. package/dist/integrations-verify.js.map +1 -1
  48. package/dist/managed-hooks.d.ts +11 -2
  49. package/dist/managed-hooks.d.ts.map +1 -1
  50. package/dist/managed-hooks.js +33 -7
  51. package/dist/managed-hooks.js.map +1 -1
  52. package/dist/mutation-gate.d.ts +35 -1
  53. package/dist/mutation-gate.d.ts.map +1 -1
  54. package/dist/mutation-gate.js +49 -9
  55. package/dist/mutation-gate.js.map +1 -1
  56. package/dist/operations.d.ts.map +1 -1
  57. package/dist/operations.js +94 -0
  58. package/dist/operations.js.map +1 -1
  59. package/dist/patterns.d.ts.map +1 -1
  60. package/dist/patterns.js +23 -4
  61. package/dist/patterns.js.map +1 -1
  62. package/dist/repository-origin.d.ts +1 -1
  63. package/dist/repository-origin.d.ts.map +1 -1
  64. package/dist/repository-origin.js +7 -1
  65. package/dist/repository-origin.js.map +1 -1
  66. package/dist/round-exec.d.ts +41 -0
  67. package/dist/round-exec.d.ts.map +1 -0
  68. package/dist/round-exec.js +45 -0
  69. package/dist/round-exec.js.map +1 -0
  70. package/dist/round.d.ts +109 -0
  71. package/dist/round.d.ts.map +1 -0
  72. package/dist/round.js +148 -0
  73. package/dist/round.js.map +1 -0
  74. package/dist/run-records.d.ts +8 -0
  75. package/dist/run-records.d.ts.map +1 -1
  76. package/dist/run-records.js +69 -3
  77. package/dist/run-records.js.map +1 -1
  78. package/dist/setup.d.ts +8 -0
  79. package/dist/setup.d.ts.map +1 -1
  80. package/dist/setup.js +166 -3
  81. package/dist/setup.js.map +1 -1
  82. package/dist/sqlite-read-helpers.d.ts +60 -0
  83. package/dist/sqlite-read-helpers.d.ts.map +1 -0
  84. package/dist/sqlite-read-helpers.js +118 -0
  85. package/dist/sqlite-read-helpers.js.map +1 -0
  86. package/dist/statusline.d.ts +20 -3
  87. package/dist/statusline.d.ts.map +1 -1
  88. package/dist/statusline.js +40 -7
  89. package/dist/statusline.js.map +1 -1
  90. package/dist/store-counts.d.ts +30 -0
  91. package/dist/store-counts.d.ts.map +1 -1
  92. package/dist/store-counts.js +189 -0
  93. package/dist/store-counts.js.map +1 -1
  94. package/dist/usage.d.ts +55 -0
  95. package/dist/usage.d.ts.map +1 -1
  96. package/dist/usage.js +184 -33
  97. package/dist/usage.js.map +1 -1
  98. package/dist/vector-tier.d.ts +18 -1
  99. package/dist/vector-tier.d.ts.map +1 -1
  100. package/dist/vector-tier.js +26 -2
  101. package/dist/vector-tier.js.map +1 -1
  102. package/package.json +6 -6
  103. package/sbom.json +442 -92
  104. package/src/agentdb-index.ts +315 -32
  105. package/src/agentdb-reindex-marker.ts +330 -0
  106. package/src/agentdb-snapshot-rotation.ts +393 -0
  107. package/src/agentdb-snapshot.ts +222 -0
  108. package/src/apply-leg.ts +1046 -0
  109. package/src/book-kb.ts +64 -1
  110. package/src/brain.ts +11 -2
  111. package/src/cadence.ts +87 -2
  112. package/src/guard.ts +46 -0
  113. package/src/index.ts +58 -5
  114. package/src/integration-probe-worker.ts +4 -6
  115. package/src/integrations-verify.ts +3 -1
  116. package/src/managed-hooks.ts +32 -7
  117. package/src/mutation-gate.ts +87 -8
  118. package/src/operations.ts +89 -0
  119. package/src/patterns.ts +23 -4
  120. package/src/repository-origin.ts +7 -1
  121. package/src/round-exec.ts +85 -0
  122. package/src/round.ts +228 -0
  123. package/src/run-records.ts +77 -2
  124. package/src/setup.ts +198 -3
  125. package/src/sqlite-read-helpers.ts +128 -0
  126. package/src/statusline.ts +57 -9
  127. package/src/store-counts.ts +245 -1
  128. package/src/usage.ts +243 -29
  129. package/src/vector-tier.ts +45 -4
package/README.md CHANGED
@@ -15,6 +15,10 @@ including `execSync(` and `execFile(`, and fails when the list and census differ
15
15
  whitespace-collapsed text matches exactly (case-sensitive), optionally within one metadata domain,
16
16
  and reports whether that existing lesson is quarantined.
17
17
 
18
+ Карантин: источник правды — лексический стор; зеркало — проекция; `dz vector reindex`
19
+ пересобирает зеркало из лексических записей и восстанавливает паритет меток. Прямая правка
20
+ зеркала не меняет авторитетное состояние и при следующем перестроении будет утрачена.
21
+
18
22
  `countLearningStoreRowsReadonly()` reports the mirror as TWO figures, deliberately not one.
19
23
  `vectorRows` stays the whole mirror (lessons + backlog ideas + book units) because the store guard
20
24
  reads it as an integrity signal against a recorded high-water mark; narrowing it would present a
@@ -246,6 +250,10 @@ compatibility path.
246
250
 
247
251
  ### Mutation registry: entry-scoped refusal and declared gaps
248
252
 
253
+ Every new mutable registry entry must carry an `observed` count measured by running
254
+ `dz mutation-gate --only <id>`. Legacy entries without that field are tracked as debt: the current
255
+ ceiling lives in `test/observed-debt-ceiling.json` and may move only downward.
256
+
249
257
  Run outcomes distinguish **green**, **tests-failed**, **runner-infrastructure**, and
250
258
  **unknown-nonzero**. The existing API keeps its names: the exit code identifies green;
251
259
  `classifyRunFailure(output)` classifies nonzero runs as `assertions` (tests-failed),
@@ -520,6 +528,52 @@ protection by making at least one named test red; each
520
528
  protection, when deleted from the source, turns at least one named test red. Design record:
521
529
  `features/destructive-command-guard/03_adr/001-narrow-by-decidability.md`.
522
530
 
531
+ ## Apply-leg module (`apply-leg.ts`) — the third self-learning leg, shipped by `dz setup`
532
+
533
+ Self-learning is COLLECT (session hooks → store) → RANK (`dz teach`/`dz recall`/`dz consolidate`) →
534
+ APPLY (a `UserPromptSubmit` hook injects ranked lessons back into the next prompt). Before this
535
+ module, `runSetup` shipped the first two legs; the third existed only as two hand-committed files
536
+ in this repo's own `.claude/helpers/` — every OTHER project that ran `dz setup --memory agentdb`
537
+ got collection and ranking but never automatic recall injection (MEASURED 2026-09-12: a clean
538
+ scratch install on 0.8.10/0.8.22, with or without `--memory agentdb`, wrote no `UserPromptSubmit`
539
+ hook entry at all).
540
+
541
+ `apply-leg.ts` is the versioned SOURCE of that leg, in the same shape `AGENTDB_WRITER_VERSION`/
542
+ `generateAgentdbWriter` already used for the session-hook writer:
543
+
544
+ - `APPLY_LEG_VERSION` / `applyLegVersionOf(content)` — the `// dz-apply-leg-version: N` stamp
545
+ (line 2 of both generated files) and its parser. Unlike `writerVersionOf` (floors an absent stamp
546
+ at `0`), `applyLegVersionOf` returns `-1` for "never installed" so `applyLegStatus` can tell that
547
+ apart from "installed at v0".
548
+ - `recallHookSource(coreDistDir)` / `embedDaemonSource()` — the two generated files, byte-for-byte
549
+ identical to the pre-existing hand-committed hub copies except for the version stamp and (recall
550
+ hook only) the resolve-candidate list. `coreDistDir` is baked in as the FIRST candidate
551
+ `loadCoreModule` tries — an absolute path the CALLER resolves (the installing CLI's own
552
+ `@dzhechkov/harness-core`, or the hub's own `harnessCoreDistDir()` for its own copies) — replacing
553
+ a hard-coded `/usr/lib/node_modules/...` guess that failed on any other npm prefix (nvm,
554
+ `/usr/local`, a differently-rooted global install).
555
+ - `applyLegHookEntries()` — the exact `UserPromptSubmit`/`SessionStart` hook-registry entries
556
+ `runSetup` merges into `.claude/settings.json` (a swallowed non-zero exit on the recall hook so a
557
+ broken body never blocks a prompt; a detached `nohup` spawn for the daemon so `SessionStart` never
558
+ waits on the ~1.5 s model load).
559
+ - `applyLegStatus(root)` — the ONE measurement `dz doctor` and `dz parity` both read: do both helper
560
+ files exist, at what version, and does `settings.json` actually reference them? Neither surface
561
+ may declare the leg "installed" from a static capability table again (ADR-001 Decision 3) — a
562
+ project with `memory.backend=agentdb` configured and nothing else gets a NAMED red row from
563
+ `dz doctor` (`apply-leg installed`, `ok:false`) and a `manual` cell from `dz parity`, never a
564
+ silent `✓`.
565
+
566
+ `runSetup`'s "Install apply-leg" step (agentdb backend only — jsonl reports `skipped` with the
567
+ named reason: the embed daemon needs agentdb's transitive transformers dependency) also creates an
568
+ EMPTY, schema-only `.dz/agentdb.db` via `ensureAgentdbSchema` (`agentdb-index.ts`, reusing
569
+ `REASONING_BANK_SCHEMA` verbatim — never a second, duplicated schema string) when the file does not
570
+ already exist, so `dz teach` has somewhere to mirror into before any session has ever ended.
571
+
572
+ The hub regenerates its OWN `.claude/helpers/recall-hook.cjs`/`dz-embed-daemon.mjs` from this same
573
+ generator (with the hub's own `coreDistDir`, via `harnessCoreDistDir()`) — a twins test
574
+ (`test/apply-leg-twins.test.ts`) keeps the two byte-identical, the same discipline `feature-adr`'s
575
+ workflow twins test applies to its own generated scripts.
576
+
523
577
  ## Run a plan without the Claude host
524
578
 
525
579
  `runWorkflow` (`workflow-run.ts`) is the PURE scheduler behind `dz workflow run`: it INTERPRETS a
@@ -708,6 +762,221 @@ rule is forced SOFT even under hostile HARD configuration, and observations do n
708
762
  the verdict reducer. Source comments, comment density, and prose classification are outside this
709
763
  decision domain: justification is neither scored nor offered as a trimming target.
710
764
 
765
+ ## Reads from a read-only-mounted store (ADR-001, `store-readonly-reads`)
766
+
767
+ `dz recall`, `dz recall --books`, and `dz brain query`/`dz brain ground` read the pattern store
768
+ (`patterns.sqlite`) and the book KB (`books.sqlite`) through `@dzhechkov/memory`'s
769
+ `openSqliteReadOnly` ladder rather than the writer's `SqliteBackend.open`/`openDb`. Observable
770
+ consequences: these commands now work when their store's directory is mounted read-only (e.g. a
771
+ sandboxed runtime) — falling back to a temporary copy when the file cannot be opened in place —
772
+ and, on the common case (a writable directory), the read no longer runs `CREATE TABLE`/FTS-rebuild
773
+ DDL on every invocation. `recallPatterns`/`loadStorePatternsSync` keep their existing
774
+ graceful-empty contract on any open failure (they fall through to the JSON store); `dz recall
775
+ --books` keeps its throw-vs-`{error}` distinction (an unreadable store still exits non-zero naming
776
+ the cause — see `books-recall-honesty` coverage in `book-kb.ts`). A residual (`readonly-residuals`):
777
+ the post-open `busy_timeout` pragma on both readonly wrappers now goes through
778
+ `applyReadonlyPragmas`, which closes the connection and cleans up a tmp-copy before rethrowing if
779
+ the pragma itself throws, instead of leaking both on that failure; and `recallPatterns`/
780
+ `loadStorePatternsSync` distinguish "native `better-sqlite3` unavailable" (silent JSON fallback,
781
+ unchanged) from "the store file itself is unreadable" (corrupt file, permission failure), printing
782
+ one `dz: <path> unreadable (<cause>) — falling back to the JSON store` line on stderr per process in
783
+ the second case, so a broken store no longer looks like plain "fewer lessons".
784
+
785
+ ## Consistent pre-reindex snapshot + rollback (`agentdb-snapshot.ts`)
786
+
787
+ The pre-reindex snapshot `reindexAgentdbRows` takes before every reindex used to be a bare
788
+ `copyFileSync(dbFile, backupPath)` — one file, no `-wal` sidecar. A WAL-mode sqlite database can
789
+ hold committed rows in `-wal` that never reached the main file (autocheckpoint disabled, or simply
790
+ a writer connection still open between commits), so copying only the main file silently drops them
791
+ — the "undo point" a rollback relies on could already be missing exactly the rows a rollback is
792
+ meant to restore. MEASURED (scratch repro, 2026-09-13, real `better-sqlite3`): a schema + one row
793
+ checkpointed, then a second row inserted on a connection kept open (`wal_autocheckpoint = 0`) —
794
+ `copyFileSync` alone produces a backup with 1 row; `VACUUM INTO` on a fresh read-only connection to
795
+ the SAME live db produces 2.
796
+
797
+ - `snapshotSqliteDatabase(Database, dbFile, backupPath, opts?)` — default strategy: opens `dbFile`
798
+ READ-ONLY and runs `VACUUM INTO '<backupPath>'` (the path is escaped as a single-quoted sqlite
799
+ string literal). One output file, every committed transaction including `-wal` frames, and the
800
+ live database is untouched — MEASURED: the main file's hash and the `-wal` file's size are
801
+ identical before and after the call. On any failure (older sqlite without `VACUUM INTO`, a
802
+ locked/foreign file, no free disk) — or when `opts.strategy: 'copy+wal'` forces it — falls back to
803
+ `copyFileSync(dbFile, backupPath)` plus a copy of `dbFile-wal` to `backupPath-wal` when the WAL
804
+ sibling exists and is non-empty. The outcome always names how it actually happened:
805
+ `{ method: 'vacuum-into' | 'copy+wal' | 'copy', note?: string }` — `note` carries the fallback
806
+ reason, so a caller/report never claims a stronger guarantee than it got. **Refuses an existing,
807
+ non-empty `backupPath` before any write** (fix round AM-4, Codex review Grade C) — throws
808
+ `snapshot target exists and is non-empty: <path>` rather than silently clobbering whatever the
809
+ path already held; the target is left byte-identical. Also clears any `backupPath-wal`/`-shm`
810
+ sidecar BEFORE either strategy writes anything, and again right after a successful `VACUUM INTO`
811
+ (AM-1) — a leftover sidecar from an earlier, unrelated snapshot family reusing the same path must
812
+ never sit next to (and later be mistaken for part of) a fresh snapshot. The `-wal` size probe now
813
+ calls `statSync` directly and treats only a confirmed `ENOENT` as "no WAL, method: copy" (AM-2) —
814
+ any other stat error (`EACCES`, `EIO`, a raced deletion) aborts the whole snapshot with a thrown
815
+ exception instead of silently degrading to a weaker, falsely-honest-looking `copy`.
816
+ - `restoreSqliteSnapshot(dbFile, backupPath, method)` — the paired rollback. `method` is the EXACT
817
+ `SnapshotMethod` the paired `snapshotSqliteDatabase` call returned (AM-1, fix round) — never
818
+ re-derived from whether `backupPath-wal` happens to exist on disk, which a stale sidecar from an
819
+ unrelated earlier snapshot at the same path could satisfy and cause the wrong generation of `-wal`
820
+ to be restored. Copies `backupPath` over `dbFile`; when `method === 'copy+wal'`, also restores
821
+ `backupPath-wal` to `dbFile-wal` — otherwise (`'vacuum-into'` or `'copy'`) removes any LIVE
822
+ `dbFile-wal` instead. MEASURED: skipping that removal leaves a reopened "restored" db replaying
823
+ the stale WAL's frames (a since-superseded write) on top of the reverted main file — rows come
824
+ back EMPTY instead of the restored set. `dbFile-shm` is always removed (its offsets are only valid
825
+ for the `-wal` that no longer matches). **The caller must close its write connection to `dbFile`
826
+ before calling this** — it is a plain file copy, not a sqlite-mediated rollback, and a live handle
827
+ can reintroduce exactly the frames being undone. Returns `{ ok: true }` or `{ ok: false, error }`
828
+ (AM-3, fix round) — a failing restore (e.g. the destination path unwritable) is reported, never
829
+ silently swallowed as if the rollback had succeeded.
830
+
831
+ `reindexAgentdbRows` wires both in: sqlite now resolves (`require.resolve('better-sqlite3')` +
832
+ dynamic `import`) BEFORE any snapshot is attempted, so an unavailable dependency aborts with
833
+ `DEPS_MISSING` and no new `pre-reindex-*` file on disk (previously a snapshot could be taken and
834
+ then immediately discarded by a deps-missing error — a mixed-signal failure). `opts.backupPath`,
835
+ when given, must resolve INSIDE `dirname(dbFile)` (AM-5, fix round — checked via `resolve` +
836
+ `relative`, so neither a `..`-escaping relative path nor a foreign absolute path can steer the
837
+ snapshot outside the db's own directory); violating it aborts with no snapshot attempted at all. The
838
+ result gains `snapshotMethod?` / `snapshotNote?`, named whenever a snapshot ran (including when a
839
+ LATER best-effort step, like copying the sibling embed-manifest, fails) — "absence of a receipt is
840
+ not success". On a reindex failure, the result also gains `rollback: 'restored' | 'failed'` and
841
+ `rollbackError?` (AM-3, fix round) — `rollback()` now closes over `restoreSqliteSnapshot`'s
842
+ `{ ok, error }` outcome instead of a bare `copyFileSync` it used to fire-and-forget, and a failed
843
+ restore is folded into the top-level `error` string as `"<reindex error>; rollback failed: <why>"`
844
+ rather than reported as if the rollback had quietly succeeded. `rollback()` only ever runs after
845
+ every write connection this function opened has already been closed (the DELETE's own
846
+ `finally { db.close() }`, and `indexPatternsToAgentdb`'s own). Test:
847
+ `opts.snapshotStrategy?: 'vacuum-into' | 'copy+wal'` forces the fallback path for deterministic
848
+ coverage of `method: 'copy+wal'` without needing an actually-broken sqlite.
849
+
850
+ ## Pre-reindex snapshot rotation (`agentdb-snapshot-rotation.ts`)
851
+
852
+ `reindexAgentdbRows` (`agentdb-index.ts`) copies the store to `<db>.pre-reindex-<ms>.bak` (+
853
+ `.embed-manifest.json`/`-shm`/`-wal` siblings) before every reindex, as an undo point — and nothing
854
+ had ever pruned them: 13 snapshots / 50 MB observed on the owner's own hub. `agentdb-snapshot-rotation.ts`
855
+ is the fix, split PURE/effect (NFR-2):
856
+
857
+ - `listPreReindexSnapshots(dbFile)` — reads the directory next to `dbFile`, groups matches of the
858
+ STRICT regex `^<basename>\.pre-reindex-(\d+)\.bak(\.embed-manifest\.json|-shm|-wal)?$` into
859
+ families by their `<ms>` timestamp. Nothing else in the directory is a candidate — `agentdb.db.bak`
860
+ and `other.pre-reindex-1.bak` next to `agentdb.db` are left alone. Symlinks are never followed and
861
+ never rotated (`lstatSync`, never `stat`): a matching NAME that resolves to a symlink is excluded
862
+ entirely, not "rotated by its link size". An orphaned sibling with no `.bak` (e.g. a lone `-shm`)
863
+ still forms its own one-file family under its own `<ms>`.
864
+ - `planSnapshotRotation(families, { keep, protectMs, now, graceMs })` — pure decision, zero fs: the
865
+ newest `keep` families survive; the family just created by THIS call (`protectMs`) is rescued even
866
+ beyond `keep` and even at `keep=0` — the boundary case named by the requirement — but is NOT
867
+ double-counted when it already falls inside the top-`keep` slice (the ordinary case, since a fresh
868
+ backup is normally the newest family already). **Grace period (fix-round AM-3):** ANY family
869
+ younger than `graceMs` (default 10 minutes; `ms > now - graceMs`) is rescued too, even past `keep`
870
+ — a snapshot from a DIFFERENT process/run than the one calling this must never look "old" just
871
+ because nobody named it via `protectMs`. There is no CLI flag to shorten or disable it; `now`/
872
+ `graceMs` exist only so tests can be deterministic.
873
+ - `rotatePreReindexSnapshots(dbFile, { keep = 3, protectPath })` — the fs-effect wrapper: list, plan,
874
+ `unlinkSync` each file of every removed family. Three fix-round hardenings, all closing a real
875
+ Codex-review Grade-D finding:
876
+ - **`keep` is validated before anything is read or deleted** (AM-1): `Number.isSafeInteger(keep)
877
+ && keep >= 0`, else the call returns `{ kept: [], removed: [], errors: ['invalid keep: …'] }` and
878
+ touches nothing. The bug this closes: `Math.max(0, NaN)` is `NaN`, and `sorted.slice(0, NaN)` is
879
+ `[]` — an EMPTY kept slice, so a `NaN`/negative `keep` used to delete every existing family.
880
+ - **A scan error blocks deletion, not just gets logged** (AM-4): a `readdirSync`/`lstatSync`
881
+ failure other than ENOENT lands in `report.scanErrors: string[]` and this call removes NOTHING —
882
+ an incomplete candidate list can never be safely read as "these are all the old ones".
883
+ - **Within a family, siblings unlink first and `.bak` last, and only if every sibling
884
+ succeeded** (AM-2): a failed sibling unlink leaves the `.bak` — the one file that alone still
885
+ proves the snapshot existed — in place, and names the family's `<ms>` in
886
+ `report.partialFamilies: number[]`, rather than guessing the family is gone.
887
+ - A per-file failure still lands in `report.errors[]` and never stops the rest of the rotation or
888
+ the caller's own success — "no receipt is not success", so every removed file is named, never
889
+ just counted.
890
+ - An absurd `<ms>` in a matching filename (not a safe non-negative integer, or beyond `Date`'s
891
+ representable `±8.64e15`) is never grouped into a candidate family (AM-5) — it never reaches
892
+ `new Date(ms)`, which throws `RangeError` past that bound.
893
+
894
+ `reindexAgentdbRows` calls this automatically on its SUCCESS path only (`opts.keepSnapshots ?? 3`),
895
+ adding a `snapshots?: SnapshotRotationReport` field to its result; an `error` return never rotates
896
+ anything (old snapshots may be the only working copy left at that moment). `reindexBrainVectors`
897
+ (`brain.ts`) forwards the same field verbatim, so `dz brain reindex` reports it too.
898
+
899
+ For rotation WITHOUT running a reindex — the owner's hub forbids a live reindex there today, and
900
+ had 13 unrotated snapshots regardless — see `dz brain snapshots [--keep N] [--prune]` in the CLI
901
+ README.
902
+
903
+ ## Snapshot lock + reindex-in-progress marker (`agentdb-reindex-marker.ts`)
904
+
905
+ **Recovery-required marker (lead edit after Codex re-review, 2026-09-13).** When a reindex fails AND its rollback
906
+ fails too, the marker is rewritten (owner token, atomic tmp+rename) with `requiresRecovery: true`. Such a marker never
907
+ expires: rotation keeps protecting its family and prints a note, and every new reindex of that store is refused with
908
+ `recovery required: … restore <snapshot> manually, then remove marker <path>`. Every marker mutation (create, stale
909
+ replacement, clear, recovery flag) runs under the same `agentdb-snapshot` lock, so compare-and-delete cannot
910
+ interleave with another owner. A snapshot that throws inside the locked section clears its own marker before the
911
+ error propagates.
912
+
913
+ Snapshot creation (`reindexAgentdbRows`), rotation (`rotatePreReindexSnapshots`) and restore
914
+ (`restoreSqliteSnapshot` via rollback) are three writers of ONE directory — before this feature they
915
+ had NO mutual exclusion, and only the 10-minute grace period above stood between a concurrent
916
+ `rotate --keep 0` and the very snapshot family a live reindex was relying on as its undo point.
917
+
918
+ - `withAgentdbSnapshotLock(dbFile, fn, opts?)` — a thin, `dbFile`-addressed wrapper over
919
+ `withNamedLockSync`: the lock lives at `<dirname(dbFile)>/.dz/locks/agentdb-snapshot.lock`, a pure
920
+ function of the database's OWN directory, never of `process.cwd()` — a project store and the home
921
+ brain each get their own lock. All three snapshot writers now run their file operations
922
+ (`VACUUM INTO`/copy, unlink, restore) under this lock; a `NamedLockTimeoutError` propagates as an
923
+ explicit `error` (`reindexAgentdbRows`: `"snapshot lock busy: …"`, no snapshot, no db change;
924
+ `rotatePreReindexSnapshots`: `{ removed: [], errors: ['lock busy: …'] }`) — never a silent skip.
925
+ The critical section stays SHORT and SYNCHRONOUS by design: re-embedding (the network/CPU-bound
926
+ part of a reindex) runs OUTSIDE the lock, exactly as the store-lock/named-lock lesson requires.
927
+ - **The lock is never acquired twice in one call stack** (NFR-2): `rotatePreReindexSnapshotsUnlocked`
928
+ is the pure fs-effect primitive with no lock of its own; the PUBLIC `rotatePreReindexSnapshots`
929
+ wraps it in one lock acquisition, and `reindexAgentdbRows`'s own success-path rotation wraps it in
930
+ its OWN separate acquisition — never through the public wrapper, which would try to take the same
931
+ named lock a second time while the first was still logically "in flight" for this call.
932
+ - `writeReindexMarker(dbFile, { ms, pid, startedAt, backupPath? })` / `clearReindexMarker(dbFile,
933
+ token)` — a `<dbFile>.reindex-inprogress.json` marker written at the start of `reindexAgentdbRows`,
934
+ INSIDE the same locked critical section as the snapshot itself (never before the lock is even
935
+ attempted, so a busy lock leaves the directory byte-identical — no snapshot AND no marker). Removed
936
+ in `finally` on every path EXCEPT one (below). `ms` is recomputed from the actual `backupPath`'s
937
+ filename, not from whatever internal counter built the default one — a non-standard `backupPath`
938
+ (no `.pre-reindex-<n>.bak` suffix) names no family, so the marker carries `ms: null` plus the
939
+ literal `backupPath` for an operator to identify it by.
940
+ - **Marker OWNERSHIP (fix-round, 2026-09-13).** `writeReindexMarker` creates the file EXCLUSIVELY
941
+ (`openSync(path, 'wx')`) and stamps it with a random 16-hex-char `token`. A LIVE marker already at
942
+ that path — a genuinely concurrent reindex of the SAME store — refuses the call outright:
943
+ `{ ok: false, error: 'reindex already in progress (marker <path>)' }`, with NO snapshot ever taken
944
+ for the refused attempt (nothing was deleted, so there is nothing to roll back). A marker at or past
945
+ the TTL is replaced. `clearReindexMarker` is compare-and-delete: it removes the marker ONLY when the
946
+ caller's `token` matches the one on disk — a process can never tear down a marker it does not own —
947
+ returning `{ cleared: false, reason }` otherwise (an absent marker is treated as an idempotent
948
+ `{ cleared: true }`).
949
+ - **A rollback that cannot re-take the lock leaves the marker in place (fix-round, 2026-09-13).** If
950
+ the forward reindex fails and needs to roll back, and the rollback's OWN lock re-acquisition times
951
+ out, the marker is deliberately NOT cleared — its family may be the only intact copy of the
952
+ pre-reindex state, and clearing the marker would let a concurrent `dz brain snapshots --prune`
953
+ delete it out from under an operator who has not yet acted. The returned `error` names BOTH paths
954
+ explicitly (`"…; snapshot at <backupPath> was not confirmed restored; marker at <path> is left in
955
+ place — requires manual recovery"`), and `rollback: 'failed'` / `rollbackError` surface the
956
+ underlying reason (typically `lock busy: …`). Recovery is manual: inspect the snapshot at the named
957
+ path, restore it by hand if needed, then remove the marker file directly.
958
+ - `readLiveReindexMarkers(dbFile, now?)` — a marker younger than `REINDEX_MARKER_TTL_MS` (60 min)
959
+ rescues its `ms` from rotation, even at `keep=0` and `graceMs=0` (a `ms: null` marker protects
960
+ nothing — there is no family to protect); a marker at or past the TTL is abandoned — removal is
961
+ attempted and the outcome is reported HONESTLY in the rotation report's `notes: string[]` field:
962
+ `"… ignored and removed"` only once the removal actually succeeded, `"… ignored, removal failed:
963
+ <err>"` when it did not (fix-round, 2026-09-13 — the previous wording always said "removed" even
964
+ when the underlying `rmSync` failed). **`pid` is recorded for operator debugging only and is NEVER
965
+ consulted for liveness** — the same "pid is not authority" lesson `store-lock.ts`/`named-lock.ts`
966
+ already encode for lock staleness; a marker with an obviously-dead `pid` and a fresh `startedAt` is
967
+ still treated as live.
968
+ - **Stale threshold: 5 minutes (fix-round, 2026-09-13).** `withAgentdbSnapshotLock` defaults
969
+ `staleMs` to `AGENTDB_SNAPSHOT_LOCK_STALE_MS` (300 000 ms) rather than named-lock's ordinary 30s
970
+ default — MEASURED: `VACUUM INTO` on an 8.45 MB agentdb store took 96 ms, so 5 minutes leaves
971
+ roughly 3000x headroom while staying inside named-lock's own 600 000 ms environment-override
972
+ ceiling. **A database whose snapshot genuinely takes longer than 5 minutes needs external
973
+ coordination** (a bigger default is not the fix); a caller doing something unusual may still pass
974
+ its own `staleMs`.
975
+ - **`rotatePreReindexSnapshotsUnlocked` is package-internal only (fix-round, 2026-09-13).** It is no
976
+ longer exported from this package's public barrel — the public rotation API is
977
+ `rotatePreReindexSnapshots`, which always takes the snapshot lock. Exporting the unlocked primitive
978
+ would hand outside callers a way to rotate with no mutual exclusion at all.
979
+
711
980
  ## Status
712
981
 
713
982
  `dz guard check --op publish` now warns when either release line disagrees with the core/CLI package versions, and a registry-confirmed live core or CLI publish synchronizes the first such line in both release READMEs: each README is rewritten atomically; the pair is not one transaction (dry-run and bump-only never write them).
@@ -11,6 +11,8 @@
11
11
  *
12
12
  * @packageDocumentation
13
13
  */
14
+ import { type SnapshotRotationReport } from './agentdb-snapshot-rotation.js';
15
+ import { type SnapshotMethod } from './agentdb-snapshot.js';
14
16
  /** One record to index. `text` is stored as `approach` AND embedded (`${taskType}: ${text}`). */
15
17
  export interface AgentdbRow {
16
18
  readonly taskType: string;
@@ -29,6 +31,33 @@ export interface AgentdbIndexResult {
29
31
  }
30
32
  /** Resolve the shared store path: explicit opt → AGENTDB_PATH env → `<project>/.dz/agentdb.db`. */
31
33
  export declare function resolveAgentdbPath(projectRoot: string, dbPath?: string): string;
34
+ /**
35
+ * Create (or verify) an EMPTY AgentDB-schema store at `resolveAgentdbPath(projectRoot, dbPath)`,
36
+ * without indexing any rows (AM-4, feature `setup-installs-apply-leg`, dz-harness-hub issue #10
37
+ * defect 4).
38
+ *
39
+ * WHY THIS EXISTS: before this, `.dz/agentdb.db` came into being only as a side effect of the
40
+ * SessionEnd/PreCompact writer's first `dz consolidate` — so a project that had run
41
+ * `dz setup --memory agentdb` but not yet completed one full session had `memory.backend=agentdb`
42
+ * configured with NO database file at all, and any lesson taught in that window before the first
43
+ * consolidate had nothing to mirror into (the apply leg's daemon reads THIS file — see
44
+ * `dz-embed-daemon.mjs`). `dz setup`'s "Install apply-leg" step now calls this directly so the
45
+ * store exists from the moment setup finishes, not from the moment a session happens to end.
46
+ *
47
+ * SYNCHRONOUS deliberately: `runSetup` is a synchronous function (a `child_process.execSync`
48
+ * install already precedes every write it does), and creating an empty schema needs only
49
+ * `better-sqlite3` — never the async `EmbeddingService` {@link indexPatternsToAgentdb} loads for a
50
+ * real write. Reuses {@link REASONING_BANK_SCHEMA} verbatim — the ONE schema string every writer in
51
+ * this module execs — so this path can never drift into declaring a second, competing schema.
52
+ *
53
+ * Best-effort, like every setup step: a project without `better-sqlite3` installed yet (or one
54
+ * whose native binary is unusable) gets `{ok:false, error}` and setup reports it in the step detail
55
+ * rather than throwing — the writer/daemon still self-heal on the next session either way.
56
+ */
57
+ export declare function ensureAgentdbSchema(projectRoot: string, dbPath?: string): {
58
+ readonly ok: boolean;
59
+ readonly error?: string;
60
+ };
32
61
  /**
33
62
  * Index `rows` into the shared AgentDB vector store. Returns `{indexed:0}` for an empty input and
34
63
  * `{indexed:0, error}` when `agentdb`/`better-sqlite3` cannot be resolved from the project.
@@ -192,6 +221,12 @@ export declare function reindexAgentdbRows(projectRoot: string, rows: readonly A
192
221
  dbPath?: string;
193
222
  taskTypes?: readonly string[];
194
223
  backupPath?: string;
224
+ keepSnapshots?: number;
225
+ /** Force the fallback snapshot path — test-only injection for AC-2 (FR-2). */
226
+ snapshotStrategy?: 'vacuum-into' | 'copy+wal';
227
+ /** agentdb-snapshot-lock: test/tuning-only override for the snapshot-lock acquisition deadline
228
+ * — omitted, the lock uses its ordinary default timeout. */
229
+ lockTimeoutMs?: number;
195
230
  }): Promise<{
196
231
  reembedded: number;
197
232
  model?: string;
@@ -200,5 +235,15 @@ export declare function reindexAgentdbRows(projectRoot: string, rows: readonly A
200
235
  error?: string;
201
236
  /** Task types left in the OLD embedding space because this reindex does not own them. */
202
237
  staleTaskTypes?: string[];
238
+ /** Pre-reindex snapshot rotation outcome — present ONLY on a successful reindex (FR-6). */
239
+ snapshots?: SnapshotRotationReport;
240
+ /** How the pre-reindex snapshot was actually taken — always named when a snapshot ran (FR-2). */
241
+ snapshotMethod?: SnapshotMethod;
242
+ /** Present only for a fallback method — the reason `vacuum-into` did not run (FR-2). */
243
+ snapshotNote?: string;
244
+ /** AM-3: present whenever a rollback was attempted — 'restored' is the only success signal. */
245
+ rollback?: 'restored' | 'failed';
246
+ /** AM-3: present only when `rollback === 'failed'` — why the restore did not fully complete. */
247
+ rollbackError?: string;
203
248
  }>;
204
249
  //# sourceMappingURL=agentdb-index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agentdb-index.d.ts","sourceRoot":"","sources":["../src/agentdb-index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agentdb-index.d.ts","sourceRoot":"","sources":["../src/agentdb-index.ts"],"names":[],"mappings":"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"}