trajectories 0.0.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/LICENSE +201 -0
  3. package/README.md +288 -2
  4. package/dist/cli.js +30210 -0
  5. package/dist/convert.d.ts +31 -0
  6. package/dist/convert.js +431 -0
  7. package/dist/deepagents_checkpoint.py +362 -0
  8. package/dist/index.d.ts +7 -0
  9. package/dist/index.js +8402 -0
  10. package/dist/log-baseline.d.ts +26 -0
  11. package/dist/log-baseline.js +104 -0
  12. package/dist/log-content.d.ts +16 -0
  13. package/dist/log-content.js +80 -0
  14. package/dist/log-io.d.ts +10 -0
  15. package/dist/log-io.js +121 -0
  16. package/dist/log-read.d.ts +24 -0
  17. package/dist/log-read.js +117 -0
  18. package/dist/log-reconcile.d.ts +5 -0
  19. package/dist/log-reconcile.js +38 -0
  20. package/dist/log-records.d.ts +35 -0
  21. package/dist/log-records.js +85 -0
  22. package/dist/log-recovery.d.ts +18 -0
  23. package/dist/log-recovery.js +123 -0
  24. package/dist/log-stage.d.ts +14 -0
  25. package/dist/log-stage.js +138 -0
  26. package/dist/log-state.d.ts +89 -0
  27. package/dist/log-state.js +92 -0
  28. package/dist/log-switch.d.ts +3 -0
  29. package/dist/log-switch.js +98 -0
  30. package/dist/log-types.d.ts +129 -0
  31. package/dist/log-types.js +8 -0
  32. package/dist/log.d.ts +8 -0
  33. package/dist/log.js +62 -0
  34. package/dist/migrate.d.ts +29 -0
  35. package/dist/migrate.js +173 -0
  36. package/dist/normalization-runtime.d.ts +1 -0
  37. package/dist/normalization-runtime.js +3150 -0
  38. package/dist/portable.d.ts +9 -0
  39. package/dist/portable.js +26 -0
  40. package/dist/readers/canonical.d.ts +13 -0
  41. package/dist/readers/canonical.js +54 -0
  42. package/dist/readers/cline.d.ts +10 -0
  43. package/dist/readers/cline.js +107 -0
  44. package/dist/readers/cursor.d.ts +20 -0
  45. package/dist/readers/cursor.js +374 -0
  46. package/dist/readers/deepagents.d.ts +41 -0
  47. package/dist/readers/deepagents.js +163 -0
  48. package/dist/readers/fx.d.ts +11 -0
  49. package/dist/readers/fx.js +573 -0
  50. package/dist/readers/github-copilot.d.ts +8 -0
  51. package/dist/readers/github-copilot.js +216 -0
  52. package/dist/readers/grok-build.d.ts +12 -0
  53. package/dist/readers/grok-build.js +391 -0
  54. package/dist/readers/guards.d.ts +4 -0
  55. package/dist/readers/guards.js +121 -0
  56. package/dist/readers/pi-compaction.d.ts +7 -0
  57. package/dist/readers/pi-compaction.js +112 -0
  58. package/dist/readers/pi-context.d.ts +13 -0
  59. package/dist/readers/pi-context.js +64 -0
  60. package/dist/store.d.ts +25 -0
  61. package/dist/store.js +218 -0
  62. package/dist/types.d.ts +91 -0
  63. package/dist/types.js +1 -0
  64. package/dist/writers/claude-code.d.ts +5 -0
  65. package/dist/writers/claude-code.js +51 -0
  66. package/dist/writers/cline.d.ts +3 -0
  67. package/dist/writers/cline.js +77 -0
  68. package/dist/writers/codex.d.ts +3 -0
  69. package/dist/writers/codex.js +32 -0
  70. package/dist/writers/cursor.d.ts +3 -0
  71. package/dist/writers/cursor.js +197 -0
  72. package/dist/writers/deepagents.d.ts +3 -0
  73. package/dist/writers/deepagents.js +116 -0
  74. package/dist/writers/entropy.d.ts +5 -0
  75. package/dist/writers/entropy.js +33 -0
  76. package/dist/writers/fx.d.ts +3 -0
  77. package/dist/writers/fx.js +135 -0
  78. package/dist/writers/github-copilot.d.ts +3 -0
  79. package/dist/writers/github-copilot.js +71 -0
  80. package/dist/writers/grok-build.d.ts +3 -0
  81. package/dist/writers/grok-build.js +43 -0
  82. package/dist/writers/helpers.d.ts +17 -0
  83. package/dist/writers/helpers.js +75 -0
  84. package/dist/writers/omp.d.ts +3 -0
  85. package/dist/writers/omp.js +7 -0
  86. package/dist/writers/opencode.d.ts +3 -0
  87. package/dist/writers/opencode.js +65 -0
  88. package/dist/writers/pi.d.ts +3 -0
  89. package/dist/writers/pi.js +45 -0
  90. package/docs/cline-native-format.md +43 -0
  91. package/docs/copilot-native-format.md +78 -0
  92. package/docs/cursor-native-format.md +103 -0
  93. package/docs/deepagents-native-format.md +98 -0
  94. package/docs/evidence-api.md +170 -0
  95. package/docs/fx-native-format.md +87 -0
  96. package/docs/harness-parity-bootstrap.md +78 -0
  97. package/docs/harness-support-parity.md +107 -0
  98. package/docs/inspirations.md +103 -0
  99. package/docs/ledger-migration.md +141 -0
  100. package/docs/pi-compaction-context.md +75 -0
  101. package/docs/pi-provider-context.md +76 -0
  102. package/docs/research/2026-10-06-huihua-and-oar.md +176 -0
  103. package/docs/research/ledger/README.md +96 -0
  104. package/docs/research/ledger/confer/2026-09-13-round-10/README.md +61 -0
  105. package/docs/research/ledger/confer/2026-09-13-round-2/cass.md +72 -0
  106. package/docs/research/ledger/confer/2026-09-13-round-3/README.md +70 -0
  107. package/docs/research/ledger/confer/2026-09-13-round-5/README.md +61 -0
  108. package/docs/research/ledger/confer/2026-09-13-round-6/README.md +68 -0
  109. package/docs/research/ledger/confer/2026-09-13-round-7/README.md +64 -0
  110. package/docs/research/ledger/confer/2026-09-13-round-9/README.md +59 -0
  111. package/docs/research/ledger/confer/2026-09-14-wake/wake.md +146 -0
  112. package/docs/research/ledger/docs/inspirations.md +320 -0
  113. package/docs/research/ledger/docs/pr2-pr6-integration.md +53 -0
  114. package/docs/research/ledger/docs/research/2026-09-07-confer-inspirations.md +163 -0
  115. package/docs/research/ledger/docs/research/2026-09-07-letta-continuous-service.md +104 -0
  116. package/docs/research/ledger/docs/research/2026-09-08-claude-history-retrieval.md +117 -0
  117. package/docs/research/ledger/docs/research/2026-09-09-agentsview-native-discovery.md +87 -0
  118. package/docs/research/ledger/docs/research/2026-09-09-daemon-observation.md +231 -0
  119. package/docs/research/ledger/docs/research/2026-09-09-discovery-pagination.md +114 -0
  120. package/docs/research/ledger/docs/research/2026-09-09-harness-transcript-contract.md +145 -0
  121. package/docs/research/ledger/docs/research/2026-09-09-native-history-discovery.md +180 -0
  122. package/docs/research/ledger/docs/research/2026-09-09-native-history-implementation.md +137 -0
  123. package/docs/research/ledger/docs/research/2026-09-09-other-inspirations.md +279 -0
  124. package/docs/research/ledger/docs/research/2026-09-09-trajectory-and-letta-code.md +128 -0
  125. package/docs/research/ledger/docs/research/2026-09-13-diagnostics-coverage.md +116 -0
  126. package/docs/research/ledger/docs/research/2026-09-13-fts-rebuild.md +83 -0
  127. package/docs/research/ledger/docs/research/2026-09-13-read-path-split.md +74 -0
  128. package/docs/research/ledger/docs/research/2026-09-13-runtime-rollout.md +102 -0
  129. package/docs/research/ledger/docs/research/2026-09-13-scan-outcomes.md +80 -0
  130. package/docs/research/ledger/docs/research/2026-09-13-search-quality.md +105 -0
  131. package/docs/research/ledger/docs/research/2026-09-13-source-coverage.md +64 -0
  132. package/docs/research/ledger/docs/research/2026-09-13-sync-wall-budget.md +82 -0
  133. package/docs/research/ledger/docs/research/2026-09-13-typed-read-gate.md +81 -0
  134. package/docs/research/ledger/docs/research/2026-09-13-writer-lease.md +84 -0
  135. package/docs/research/ledger/docs/research/2026-09-16-c1-copy-fallback.md +227 -0
  136. package/docs/research/ledger/docs/research/2026-09-16-c10-kimi.md +414 -0
  137. package/docs/research/ledger/docs/research/2026-09-16-c2-derive-counter.md +216 -0
  138. package/docs/research/ledger/docs/research/2026-09-16-c3-echo-filter.md +305 -0
  139. package/docs/research/ledger/docs/research/2026-09-16-c4-title-index.md +349 -0
  140. package/docs/research/ledger/docs/research/2026-09-16-c5-trigram.md +268 -0
  141. package/docs/research/ledger/docs/research/2026-09-16-c6-recency-prior.md +438 -0
  142. package/docs/research/ledger/docs/research/2026-09-16-c7-tombstones.md +467 -0
  143. package/docs/research/ledger/docs/research/2026-09-16-c8-remote-truth.md +390 -0
  144. package/docs/research/ledger/docs/research/2026-09-16-c9-grok.md +380 -0
  145. package/docs/research/ledger/docs/research/2026-09-16-wake-port-program.md +38 -0
  146. package/docs/research/ledger/docs/research/2026-09-17-cursor-blobstore.md +157 -0
  147. package/docs/research/ledger/manifest.json +540 -0
  148. package/legacy/NOTICE.md +50 -0
  149. package/legacy/bin/ledger-core.ts +7 -0
  150. package/legacy/bin/ledger.ts +7 -0
  151. package/legacy/bin/traj-bridge.ts +7 -0
  152. package/legacy/scripts/import-claude-history.ts +130 -0
  153. package/legacy/scripts/native-history-smoke.ts +52 -0
  154. package/legacy/scripts/observe-daemon.ts +570 -0
  155. package/legacy/scripts/retitle-sessions.md +19 -0
  156. package/legacy/scripts/verify-runtime-rollout.ts +151 -0
  157. package/legacy/src/canonical.ts +108 -0
  158. package/legacy/src/cli.ts +1293 -0
  159. package/legacy/src/db.ts +2254 -0
  160. package/legacy/src/diagnostics.ts +87 -0
  161. package/legacy/src/discovery.ts +56 -0
  162. package/legacy/src/embeddings.ts +382 -0
  163. package/legacy/src/filter.ts +602 -0
  164. package/legacy/src/gemini_embeddings.ts +103 -0
  165. package/legacy/src/identity.ts +9 -0
  166. package/legacy/src/index.ts +10 -0
  167. package/legacy/src/ingest.ts +791 -0
  168. package/legacy/src/managed.ts +178 -0
  169. package/legacy/src/native/common.ts +68 -0
  170. package/legacy/src/native/cursor.ts +647 -0
  171. package/legacy/src/native/grok.ts +540 -0
  172. package/legacy/src/native/kimi.ts +706 -0
  173. package/legacy/src/native/opencode.ts +470 -0
  174. package/legacy/src/native/sqlite-ro.ts +281 -0
  175. package/legacy/src/native.ts +97 -0
  176. package/legacy/src/normalizer.ts +457 -0
  177. package/legacy/src/parentage.ts +562 -0
  178. package/legacy/src/pressure.ts +162 -0
  179. package/legacy/src/private-storage.ts +74 -0
  180. package/legacy/src/reader.ts +1255 -0
  181. package/legacy/src/scanner.ts +591 -0
  182. package/legacy/src/schema-gate.ts +263 -0
  183. package/legacy/src/schema.ts +829 -0
  184. package/legacy/src/semantic-top-k.ts +71 -0
  185. package/legacy/src/session-hash.ts +49 -0
  186. package/legacy/src/store-status.ts +218 -0
  187. package/legacy/src/sync-preparation.ts +45 -0
  188. package/legacy/src/sync-truth.ts +843 -0
  189. package/legacy/src/sync.ts +1233 -0
  190. package/legacy/src/types.ts +436 -0
  191. package/legacy/src/vocab.txt +30522 -0
  192. package/legacy/src/watch.ts +673 -0
  193. package/legacy/src/writer-lease.ts +310 -0
  194. package/ops/README.md +150 -0
  195. package/ops/install-cli.sh +63 -0
  196. package/ops/install-native.sh +35 -0
  197. package/ops/install-release.sh +49 -0
  198. package/ops/linux/install-systemd-user.sh +103 -0
  199. package/ops/macos/install-launchd.sh +72 -0
  200. package/ops/sync-settings.sh +37 -0
  201. package/package.json +21 -5
  202. package/skills/trajectories/SKILL.md +138 -0
  203. package/skills/trajectories/scripts/trajectories_recent.sh +26 -0
  204. package/skills/trajectories/scripts/trajectories_search.sh +26 -0
  205. package/index.js +0 -1
@@ -0,0 +1,128 @@
1
+ # Trajectory and Letta Code: integration evidence
2
+
3
+ Source refresh: 2026-09-09. Retain published `@letta-ai/trajectory` for canonical
4
+ normalization; adapt selected Letta Code lifecycle contracts independently. Letta
5
+ Code is not an adopted dependency or a replacement for Ledger's durable store.
6
+ This addendum supplements the [prior comparison](2026-09-07-confer-inspirations.md)
7
+ and [service review](2026-09-07-letta-continuous-service.md), without repeating them.
8
+
9
+ ## Pins and scope
10
+
11
+ | Inspected source | Exact commit | Version / boundary |
12
+ | --- | --- | --- |
13
+ | letta-ai/trajectory | `21ae92d10579499b183d93929c85da0b91233167` | GitHub HEAD and npm latest were still `0.3.0`, unchanged from the prior research; installed package agreed. `NORMALIZER_VERSION=0.3.0`, `CANONICAL_SCHEMA_VERSION=3`. [Constants](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/src/version.ts#L1-L16) |
14
+ | letta-ai/letta-code | `170a6d190eb70b65ebf0d4e1683f971e18633997` | Package `0.31.14`; pins Trajectory **`0.2.0`**, not `0.3.0`. [Package](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/package.json#L1-L3), [dependency](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/package.json#L123-L135) |
15
+ | Ledger research baseline | `571c14498acad05c89d2fefc14b8ee3ae775fd11` | Original `main` inspected during the source refresh. |
16
+ | Ledger PR2 research head | `94f70c5fa46fcc8f5ccbdf477d67c0cd2c4a32cc` | Historical comparison point, not the final merged PR2 head. |
17
+ | Ledger PR6 research head | `1efa46d9ac7164f2c32b2a47957b6ea732322f8d` | Historical comparison point, before current integration repairs. |
18
+
19
+ At preservation time, this worktree starts at PR2's merge commit
20
+ `7fe199ce9d62e4a9e966aff18b7c33eda917ac40`. The coordinator reports PR6 integration
21
+ underway with Ledger DB schema 6, atomic cursor commits, and bounded chunks. Those
22
+ changes were not evaluated by this source pass: the old PR findings below must
23
+ not be presented as current-main failures or as verified repairs.
24
+
25
+ Evidence came from fresh primary GitHub source/API reads, with both upstream HEADs
26
+ rechecked during the pass. Confer's direct shell was unavailable; registrar and
27
+ doctor checks found a usable queue, but job
28
+ `499e3ea4-cc67-4619-b200-c895c4231a14` failed because Letta Code was absent from its
29
+ catalog. That job supplies no findings. Upstream test source was inspected, not
30
+ run. No daemon/runtime verification is claimed here; main owns that observation.
31
+ No upstream clones, native transcript inspection, or secret values are included.
32
+
33
+ ## Canonical contract already available in 0.3.0
34
+
35
+ - **Identity and versions are separate.** `record_id` hashes native group,
36
+ source-record identity, and semantic component key, without source type.
37
+ Native/location identities support conflict detection; content fallback only
38
+ supports exact dedup. `content_hash` covers normalized semantic content;
39
+ `record_hash` covers the full normalized record, including timestamps.
40
+ Ledger supplies source scope, content versions, and durable ingestion order.
41
+ [Implementation](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/src/canonical.ts#L43-L153)
42
+ - **Partial is not arbitrary streaming.** Explicit `partial:true` permits an
43
+ initial single-role fragment; a positive `baseByteOffset` implies partial mode.
44
+ Canonical meta appears only at offset zero, and cross-chunk tool results retain
45
+ their call IDs. Byte offsets affect byte anchors, not ordinals: id-less Letta
46
+ Code rows are ordinal-anchored. Preserve native group context and test each
47
+ adapter's chunk equivalence rather than generalizing from JSONL syntax.
48
+ [API](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/src/index.ts#L94-L172),
49
+ [tests](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/test/canonical.test.ts#L468-L584),
50
+ [Letta ordinal fallback](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/src/adapters/letta-code/index.ts#L60-L69)
51
+ - **Normalization is neither raw retention nor an ingestion engine.** The API
52
+ accepts a complete string; JSONL parsing builds arrays and skips malformed rows
53
+ with diagnostics. Tool argument/result bounds cap fields, not peak memory.
54
+ Canonical JSON preserves emitted normalized records, not original source bytes.
55
+ Persist diagnostics and the returned normalizer/schema/effective configuration.
56
+ [Parser](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/src/adapters/shared.ts#L10-L45),
57
+ [bounds](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/src/bounds.ts#L17-L24),
58
+ [result envelope](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/src/canonical.ts#L338-L349)
59
+
60
+ ## Letta Code's actual use, not inferred infrastructure
61
+
62
+ - **Historical export:** discovery feeds whole-input `normalizeTranscript` calls,
63
+ JSON files, and a manifest, defaulting to `/tmp/letta-trajectories`. Re-export
64
+ removes previous export contents. Search scans user/assistant prose for a
65
+ case-insensitive substring. This path is a replaceable export, not canonical
66
+ persistence, incremental sync, or a continuously maintained search index.
67
+ [CLI](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cli/subcommands/trajectories.ts#L23-L62),
68
+ [export implementation](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cli/subcommands/trajectories/export.ts#L150-L334),
69
+ [query implementation](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cli/subcommands/trajectories/review.ts#L167-L200)
70
+ - **Own-turn capture and correction to the prior review:** native rows append to
71
+ `$LETTA_TRANSCRIPT_ROOT` or `~/.letta/transcripts/<agent>/<conversation>/transcript.jsonl`,
72
+ with a separate `state.json`. Reflection later calls `normalizeTranscript` with
73
+ `partial:true`, not `normalizeToCanonical`. The listener attempts capture before
74
+ reflection, but **catches append failure and still evaluates reflection**.
75
+ Therefore the prior capture-before-trigger observation is ordering, not a
76
+ capture-success gate. Ledger must define its own committed-evidence prerequisite.
77
+ [Root](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/utils/transcript-paths.ts#L4-L21),
78
+ [capture](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cli/helpers/reflection-transcript.ts#L914-L952),
79
+ [normalization](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cli/helpers/reflection-transcript.ts#L630-L641),
80
+ [decisive caller](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/websocket/listener/turn-completion.ts#L67-L105)
81
+ - **Sync, watch, and query boundaries:** completion sync sends Cloud a
82
+ `reflected_through_message_id`; the inspected filesystem watcher watches new
83
+ worktrees, not harness history. Separate local-backend search treats vector and
84
+ hybrid requests as FTS-lite without a vector index. None proves fleet transcript
85
+ synchronization or continuous cross-harness indexing.
86
+ [Completion sync](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cli/helpers/reflection-completion.ts#L40-L130),
87
+ [watcher](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/websocket/listener/worktree-watcher.ts#L120-L158),
88
+ [local query](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/backend/local/transcript-search.ts#L409-L460)
89
+ - **Useful later Dream contracts:** reflection completion is gated on memory
90
+ integration, not merely subagent success. Cron has persisted PID/token ownership
91
+ and run outcomes, but per-minute dedup remains in memory. Adapt explicit
92
+ ownership and completion semantics; do not inherit an exactly-once claim.
93
+ [Integration gate](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cli/helpers/reflection-launcher.ts#L628-L634),
94
+ [completion caller](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cli/helpers/reflection-launcher.ts#L868-L906),
95
+ [lease](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cron/cron-file.ts#L646-L682),
96
+ [dispatch](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/src/cron/scheduler.ts#L498-L594)
97
+
98
+ ## Historical PR findings versus remaining architecture
99
+
100
+ | Pinned observation before integration | Disposition / minimal Ledger-owned contract |
101
+ | --- | --- |
102
+ | PR2 scopes Ledger IDs; PR6 passes stored session IDs as native `groupId`. The branches also assigned incompatible meanings to DB migration v4. [PR2 identity](https://github.com/archeism/ledger/blob/94f70c5fa46fcc8f5ccbdf477d67c0cd2c4a32cc/packages/core/src/normalizer.ts#L102-L106), [PR6 handoff](https://github.com/archeism/ledger/blob/1efa46d9ac7164f2c32b2a47957b6ea732322f8d/packages/core/src/ingest.ts#L196-L217), [PR2 migration](https://github.com/archeism/ledger/blob/94f70c5fa46fcc8f5ccbdf477d67c0cd2c4a32cc/packages/core/src/schema.ts#L76-L107), [PR6 migration](https://github.com/archeism/ledger/blob/1efa46d9ac7164f2c32b2a47957b6ea732322f8d/packages/core/src/schema.ts#L117-L145) | Integration concern, not a newly asserted main defect. Schema-6 work is underway. Keep Ledger-scoped keys distinct from native group identity, including append paths and relationships; cover both historical DB shapes. |
103
+ | PR6 commits records, optionally awaits embeddings, then writes its cursor separately. [Sequencing](https://github.com/archeism/ledger/blob/1efa46d9ac7164f2c32b2a47957b6ea732322f8d/packages/core/src/ingest.ts#L132-L144) | Atomic-cursor integration is underway. Commit canonical records and normalization progress together; keep embeddings retryable enrichment outside that boundary. |
104
+ | PR6 assumes growth means append continuity, initializes progress from full file size, and allocates the entire suffix. A skipped incomplete initial row can be lost if its later suffix contains other valid rows. [Initial cursor/growth](https://github.com/archeism/ledger/blob/1efa46d9ac7164f2c32b2a47957b6ea732322f8d/packages/core/src/ingest.ts#L119-L168), [suffix read](https://github.com/archeism/ledger/blob/1efa46d9ac7164f2c32b2a47957b6ea732322f8d/packages/core/src/ingest.ts#L225-L241) | Bounded-chunk integration is underway. Complete-byte cursors, UTF-8/partial-line handling, and adapter-specific replay equivalence are the contracts to validate, not claims established here. |
105
+ | PR6 skips existing record IDs without comparing semantic hashes; changed full sessions still replace prior records. [Append dedup](https://github.com/archeism/ledger/blob/1efa46d9ac7164f2c32b2a47957b6ea732322f8d/packages/core/src/db.ts#L385-L418), [replacement](https://github.com/archeism/ledger/blob/1efa46d9ac7164f2c32b2a47957b6ea732322f8d/packages/core/src/db.ts#L306-L349) | Separate archival/versioning followup. Atomic cursors and bounded chunks alone do not establish retained source generations, content-conflict handling, or rebuildable evidence. |
106
+
107
+ Remaining architecture: retain raw source generations/range digests before
108
+ advancing capture progress; bind normalization to normalizer/schema/config
109
+ versions and diagnostics; version or quarantine same-identity semantic conflicts.
110
+ Keep source timestamps descriptive, not ingestion cursors. Dream needs durable
111
+ jobs, evidence-bound publication/invalidation, and separate promotion authority;
112
+ fleet/live capture needs explicit identity and privacy contracts. These are
113
+ separately scoped Ledger-owned followups, not supplied upstream features. This
114
+ source note does not certify implementation status or merge readiness.
115
+
116
+ ## Adoption and licensing
117
+
118
+ Adopt the published Trajectory API; independently implement Ledger's storage and
119
+ progress contracts. Learn from Letta Code's explicit ownership and integration
120
+ completion gate, not its replaceable export directory, in-memory cron dedup, or
121
+ best-effort capture ordering. No upstream implementation was copied or vendored.
122
+
123
+ Both inspected upstream repositories declare Apache-2.0; applicable licenses and
124
+ notices still apply. [Trajectory license](https://github.com/letta-ai/trajectory/blob/21ae92d10579499b183d93929c85da0b91233167/LICENSE),
125
+ [Letta Code license](https://github.com/letta-ai/letta-code/blob/170a6d190eb70b65ebf0d4e1683f971e18633997/LICENSE).
126
+ Ledger's [repository guidance](https://github.com/archeism/ledger/blob/43081aef54c23b4bd017b6c0e11fc42a9a1cb381/AGENTS.md#licensing) still records no selected
127
+ project license and prohibits copying/vendoring/deriving Obelisk code without an
128
+ explicit licensing decision. No new dependency or licensing decision is made here.
@@ -0,0 +1,116 @@
1
+ # Durable normalization diagnostics as coverage records, 2026-09-13
2
+
3
+ ## Outcome
4
+
5
+ Ledger now persists the normalization diagnostics of `@letta-ai/trajectory`
6
+ as durable, attributable coverage records (schema v9 `ingest_diagnostics`)
7
+ and surfaces them through `ledger status`. Before this change the diagnostics
8
+ were collected by the normalizer and dropped by `ingest.ts`; the only honest
9
+ signal of lossiness (for example `tool_result_truncated` under the default
10
+ 2,500-code-point tool-result bound) was invisible in the store, the CLI, and
11
+ the robot contract.
12
+
13
+ The increment is stacked on PR16's `codex/ledger-cli-evaluation` head because
14
+ the status surface and `store-status.ts` live there. PR8-owned behavior is
15
+ untouched; the one PR8-file edit (`normalizer.ts`) is an additive export.
16
+
17
+ ## Evidence chain
18
+
19
+ - Round-1 Confer research pinned the upstream contract:
20
+ diagnostic codes are additive and never repurposed, and diagnostic text
21
+ never contains raw transcript content
22
+ (`letta-ai/trajectory@21ae92d10579499b183d93929c85da0b91233167:CANONICAL.md#L204-L209`,
23
+ `src/types.ts#L96-L118`), which makes the messages safe to persist verbatim.
24
+ - The dropped-plumbing defect was verified locally at base `988f52e`:
25
+ `packages/core/src/normalizer.ts#L98` returns
26
+ `NormalizedSessionResult.diagnostics`; `ingest.ts` never read the field.
27
+ - The installed `Diagnostic` shape (`dist/types.d.ts#L67-L73`) is
28
+ `{ code, message, inputLine?, recordIndex?, count? }` — there is no severity
29
+ field anywhere in the package, so the design's severity column was dropped
30
+ rather than stored permanently NULL. `count` is pre-aggregated by upstream
31
+ for `timestamps_interpolated`/`timestamps_synthesized` and summed honestly.
32
+ - Gap alignment: `docs/inspirations.md` names "expose unsupported/failed/
33
+ pending sources" and evidence-bearing completeness reporting as remaining
34
+ work; AgentsView's doctor is the per-root ok/missing/error pattern and Cass
35
+ carries a `_meta.search_completeness` field for the same reason. This is
36
+ Ledger's first durable piece of that surface.
37
+
38
+ ## Design
39
+
40
+ - `ingest_diagnostics` is keyed `(session_id, code)`; `source` is stored for
41
+ filtering. Rows carry `occurrence_count`, a bounded code-point-safe
42
+ `sample` (last message, ≤200 code points), and `first_seen_at` /
43
+ `last_seen_at`. Sessions are globally unique by id, so replacement and
44
+ deletion key on `session_id` alone.
45
+ - Replacement semantics, not accumulation: each successful whole-file
46
+ normalization replaces the session's rows inside the same transaction as
47
+ records and cursor. Identical re-imports are idempotent; counts never
48
+ double; a session that normalizes cleanly loses its old rows.
49
+ - Chunked honesty: a pass publishes live coverage only when it normalized the
50
+ whole file itself (`!append && complete`). Multi-chunk rebuilds merge each
51
+ chunk's aggregate into the stage (`ingest_staged_sessions.diagnostics_json`,
52
+ durable across restarts) and publish the union at promotion. A promotion
53
+ with no aggregate clears rows instead of keeping the predecessor's —
54
+ unknown beats wrong. Live append continuations keep the last whole-file
55
+ coverage and are documented as not re-counting appended content.
56
+ - `ledger build` (the `saveSession` path) publishes the same coverage so a
57
+ build-populated store cannot silently report zero findings.
58
+ - Status surface: robot/JSON gains an additive `diagnostics` object
59
+ (`{ totalSessions, totalOccurrences, byCode[] }`), `null` on stores that
60
+ predate the table (read-only `sqlite_master` probe — `status` still never
61
+ migrates); human output distinguishes `unknown (store predates diagnostics
62
+ schema)`, `none`, and the findings block (top codes by occurrences).
63
+ - Invariant hardening: an `AFTER DELETE ON sessions` trigger removes a
64
+ session's diagnostics rows even when a raw connection has
65
+ `foreign_keys=OFF`; promotion also deletes explicitly.
66
+ - `commitIngest`/`commitStagedIngest` take an options object for the new
67
+ payload (`{ diagnostics? }`) so later extensions (PR8 adds
68
+ `allowPathReplacement` positionally) cannot hit parameter-order traps.
69
+
70
+ ## Verification
71
+
72
+ Independent verifier round (scripts under `/tmp/dx-verify`, base worktree at
73
+ `988f52e`, changed tree uncommitted; every number below is from that round):
74
+
75
+ - Stability: full suite 289 pass / 0 fail / 1846 assertions across 26 files,
76
+ three consecutive runs (25.9s, 25.5s, 25.3s). Base tree: 269 / 0 / 1670
77
+ across 25 files, three runs. Typecheck and build clean.
78
+ - Transient-failure chase: one new e2e test initially re-downloaded a 22 MB
79
+ ONNX model per run under an isolated HOME (35.5 s wall, bun 5 s timeout,
80
+ 5/5 individual timeouts); root-caused and fixed to inherit HOME like the
81
+ sibling subprocess tests (0.49 s with the shared model cache).
82
+ - Capability: 16/16 assertions on a fresh mixed corpus via the canonical CLI
83
+ (`build` + `status --robot`): 3 truncation occurrences attributed to exactly
84
+ the loud session; clean corpus reports `none`; rewriting the source clean
85
+ makes findings disappear (no accumulation). Negative control on the base
86
+ tree scores 2/16 — the base payload has no diagnostics key at all.
87
+ - Atomicity probe: a poisoned aggregate (null code) throws inside
88
+ `commitIngest`; sessions, records, cursor, and diagnostics all roll back
89
+ together (7/7). Staged-union probe: a rebuild consumed across five chunk
90
+ passes published exactly the whole-file ground truth at promotion (5/5).
91
+ - Overhead (N=30 passes, 12-session corpus, embeddings disabled, same script
92
+ bytes on both trees): ingest median 44.1 ms base vs 44.4 ms changed
93
+ (+0.8%, ranges overlap); records/pass and sessions/pass identical
94
+ (236/12). In-process `readStoreStatus` gains ~50 µs; CLI `status --robot`
95
+ wall time is indistinguishable (bun startup dominates).
96
+ - Migration: 19/19 assertions. A v8 store stays v8 under read-only status
97
+ (`diagnostics: null`, human `unknown`), upgrades on the next writer open
98
+ with zero fabricated rows, and a raw `DELETE FROM sessions` under
99
+ `foreign_keys=OFF` still removes the session's diagnostics rows (trigger).
100
+
101
+ ## Boundaries
102
+
103
+ - Occurrence units are per-code heterogeneous (records-affected for
104
+ `timestamps_*`, diagnostic counts elsewhere) — documented on the type, not
105
+ normalized away.
106
+ - Ledger's own `warning()` strings (paths, budgets) remain transient ingest
107
+ results by scope decision; persisting them is follow-up work with a
108
+ privacy decision attached.
109
+ - Brand-new multi-chunk listings publish no coverage until a whole-file
110
+ normalization happens (documented residual; closing it requires staging
111
+ cold partial passes, which the existing ingest-staging contract pins
112
+ against). Zero rows therefore render as `none`, indistinguishable from an
113
+ observed-clean pass for such sessions.
114
+ - No raw source retention: this records the normalizer's observations, not
115
+ source bytes. The archival boundary remains open with its own policy.
116
+ - No upstream code copied; Trajectory remains the only adopted dependency.
@@ -0,0 +1,83 @@
1
+ # FTS rebuild migration (schema v11) and the measured rejection of the prefix index, 2026-09-13
2
+
3
+ ## Outcome
4
+
5
+ Cycle 2's query widening is inert on the production store: 156,801
6
+ records always exceeded `LEDGER_WIDEN_MAX_RECORDS` (10,000), and widened
7
+ queries measured 0.14–1.5 s there. This cycle set out to add an FTS5
8
+ `prefix=` index and **measurement rejected it**: on a byte-consistent
9
+ copy of the live store, prefix options ('2 3', '2 3 4') added
10
+ +106–151 MB (+13–19% store) and ~+35% ingest write cost with **no
11
+ measurable latency benefit** — the residual cost for common short
12
+ prefixes is match-set/bm25 evaluation, not the index seek. The shipped
13
+ increment is what the measurement actually validated: a one-time
14
+ **rebuild of `records_fts`** (schema v11), which made widened queries
15
+ 5–10× faster and exact-term queries 8–80× faster at near-zero size cost,
16
+ plus a measured-basis raise of the widening ceiling to 250,000 records.
17
+ Closes #21.
18
+
19
+ ## Design
20
+
21
+ - FTS5 virtual tables cannot be `ALTER`ed; the migration (inside the
22
+ existing crash-atomic `migrate()` transaction, under the writer lease)
23
+ drops and recreates `records_fts` with the **unchanged** DDL and
24
+ repopulates from `records` via a projection mirroring
25
+ `insertRecordsInternal` value-for-value (single DDL constant shared by
26
+ fresh stores and the rebuild so they cannot drift). Post-copy gates
27
+ inside the transaction: row parity (`records` vs `records_fts` counts)
28
+ and the FTS5 `integrity-check` command — a failure aborts and leaves
29
+ v10 authoritative. `user_version = 11` is the marker. The gates also
30
+ heal drift (lost/orphan FTS rows).
31
+ - Widening ceiling `DEFAULT_WIDEN_MAX_RECORDS` 10,000 → 250,000, on the
32
+ measured basis below; `LEDGER_WIDEN_MAX_RECORDS` semantics unchanged.
33
+
34
+ ## Verification (two independent measurement rounds + adversarial audit)
35
+
36
+ All numbers from byte-consistent copies of the live store
37
+ (156,801 records / 811 MB):
38
+
39
+ - **Rebuild cost**: wall 11.5 s idle / 35.6–38.1 s under host load; WAL
40
+ peak 274 MiB (~2.8% of volume headroom), truncated after commit; net
41
+ store +1.8 MB; parity and integrity-check pass inside the migration.
42
+ Concurrent writers refuse fast via the cycle-3 lease (250 ms → typed
43
+ `WRITER_BUSY`) instead of blocking behind the ~27 s write-lock hold;
44
+ readers unaffected (WAL).
45
+ - **Latency (engine ms, old → rebuilt)**: widened zero-hit probes
46
+ 'records sqlite' 890 → 85/60; 'daemon watchdog' 178 → 19/37;
47
+ 'canonical trajectory' 219 → 106/130 (idle round) and 840 → 474 first /
48
+ 42 → 40 warm, 3456 → 1731 widened (loaded round — magnitudes are
49
+ load-dependent; direction unanimous). Exact-term probes 88 → 5.6,
50
+ 82 → 10.8, 55 → 0.8, 34 → 1.0, 78 → 9.9 ms. Common short prefixes
51
+ ('the*', 'run*') remain ~0.46–0.69 s in every shape — match-set-bound,
52
+ documented as the residual cost class.
53
+ - **Result equality**: 10/10 and 8/8 probe queries (widened and exact)
54
+ byte-identical hits, order, ranks, snippets across the rebuild.
55
+ FTS rowids are remapped; no consumer depends on them (verified).
56
+ - **Prefix option (rejected)**: rebuild-without-prefix vs
57
+ '2 3 4' on identical content — widened queries within noise;
58
+ +151 MB size, 10,772 → 32,129 idx rows; 5,000-record ingest
59
+ 1,919 → 2,595 ms (+35%), WAL 65.5 → 87.9 MB.
60
+ - **Rollback atomicity**: killed mid-migration → `user_version` stays
61
+ 10, index DDL and rows byte-identical, next open migrates cleanly.
62
+ - **Audit fixes before shipping**: both post-copy gates now pinned by
63
+ real-mismatch tests (mutations that neutralize either gate fail the
64
+ suite); the fresh-segments rationale was itself falsified by
65
+ measurement (the rebuilt index has *more* segments on the maintained
66
+ store — the win is empirical, mechanism-neutral); binary-skew and
67
+ marker-only-revert documented; tool-result fallback pinned by column
68
+ value.
69
+ - **Suite**: 522+ pass / 0 fail across 35 files (post-fix count per the
70
+ final round); typecheck/build clean.
71
+
72
+ ## Boundaries
73
+
74
+ - The daemon's first post-merge writer open performs the one-time
75
+ migration on the live store (~30–40 s on this volume, under the
76
+ lease); pre-change binaries refuse a v11 store with the standard
77
+ too-new error — rollback is the `user_version` marker alone (the DDL
78
+ is unchanged).
79
+ - Common-prefix widened queries remain ~0.5 s at this corpus size — a
80
+ ranking/candidate-cap question, not an index question; recorded.
81
+ - Rebuild cadence: the v11 rebuild is one-time; periodic re-defragment
82
+ (Cass-style reconciler) is not included — `automerge=4` plus the
83
+ existing maintenance merge remain the steady-state discipline.
@@ -0,0 +1,74 @@
1
+ # Read-path connection split, 2026-09-13
2
+
3
+ ## Outcome
4
+
5
+ Read verbs (`search`, `recent`, `emit-pi`) opened the write-bearing
6
+ `TrajectoryDb`, whose constructor always writes (WAL pragma,
7
+ `CREATE_TABLES_SQL`, trigger repair; migrations on old schemas) — so a
8
+ search could create or upgrade a store outside the writer lease, and a
9
+ `--semantic` query backfilled embeddings mid-read. This cycle introduces
10
+ `TrajectoryReader`: a strictly read-only connection (`readonly: true` open
11
+ flag — engine-enforced, irreversible; never `query_only`) with typed
12
+ refusals (`STORE_NOT_INITIALIZED`, `SCHEMA_MISMATCH`, `STORE_UNREADABLE`),
13
+ no DDL/migration/repair, and no embedding writes. Semantic/hybrid without
14
+ usable embeddings answers lexically and says so via the cycle-2 envelope
15
+ trio (`search_mode: "lexical"`, `requested_search_mode` as requested,
16
+ `fallback_reason: "embeddings_unavailable"`) — the designed first use of
17
+ that field pair. Closes issue #23's read-side; the lease boundary from
18
+ cycle 3 is now complete.
19
+
20
+ Query internals were extracted and shared between the writer and reader
21
+ handles, so widening, envelope, provenance, and fusion cannot drift; the
22
+ cycle-2 suite passes unchanged against the reader path. The writer handle
23
+ keeps its pre-query backfill (`ensureQueryEmbeddings`) and its documented
24
+ provider-failure asymmetry.
25
+
26
+ ## Evidence chain
27
+
28
+ [Confer round 5](../../confer/2026-09-13-round-5/README.md) pinned the
29
+ read-connection discipline from all six inspirations: Obelisk's
30
+ `readOnly:true` recipe and typed schema refusals (AGPL — patterns only),
31
+ AgentsView's reader-pool/DSN discipline and the stranded-reader-on-swap
32
+ hazard avoided by per-invocation readers, Cass's "a strict read never
33
+ repairs" rule and byte-invariance test (rider — patterns only),
34
+ Trajectory's `openWithWalFallback` writable-retry identified as the
35
+ anti-pattern behind the round-4 stale-`-shm` failure, letta-code's
36
+ manifest refusal with remedy in the message.
37
+
38
+ ## Verification (combined adversarial + independent rounds)
39
+
40
+ - Write-freedom confirmed: db and `-wal` byte-identical after every read
41
+ verb across WAL/non-WAL shapes, refusal paths, and a live writer with an
42
+ open transaction; no sidecar or lock file ever created; `user_version`
43
+ never bumped. (`-shm` is shared wal-index bookkeeping SQLite may refresh
44
+ once on first open of a dirty WAL — documented, excluded from the
45
+ data-hash contract.) Engine-level test proves the handle rejects writes
46
+ (SQLITE_READONLY) — mutation-verified (removing the readonly flag fails
47
+ two tests).
48
+ - Behavioral drift: none — 14 lexical query shapes plus the full envelope
49
+ identical to baseline `a19916b`; semantic/hybrid with embeddings
50
+ byte-identical between handles. Intended changes only: read path never
51
+ backfills; provider failure with vectors present now answers lexically
52
+ (documented) instead of throwing on the writer handle too.
53
+ - Concurrency: reads serve the last committed snapshot during a held
54
+ `BEGIN IMMEDIATE`; 120 concurrent read verbs against a write burst with
55
+ periodic checkpoints all succeeded; the live 820 MB store read correctly
56
+ while a real `ledger sync` held the lease.
57
+ - Suite: 454 pass / 1 fail of 455 across 35 files — the failure is the
58
+ pre-existing native-cursor classification (#18, reproduced identically
59
+ on baseline). Typecheck and build clean. Reader suite: 22 tests / 181
60
+ assertions; cycle-2 and cycle-4 suites pass unchanged.
61
+ - Human-mode note branches on reason (FTS wording pinned; other reasons
62
+ print `answered lexically (<reason>)`); empty stores report plain
63
+ zero-hit results; dimension-mismatched provider vectors fall back rather
64
+ than rank zeros.
65
+
66
+ ## Boundaries
67
+
68
+ - The "initialized store" gate recognizes a `sessions` table (consistent
69
+ with `store-status`); a foreign file with only that table fails per-verb
70
+ with a raw SQLite error — a shared weakness with status, recorded as
71
+ follow-up (AgentsView's required-schema diff is the known shape).
72
+ - `-shm` refresh on first open of a dirty WAL is SQLite's own wal-index
73
+ bookkeeping, not a Ledger write.
74
+ - Writers unchanged: `TrajectoryDb` + lease + backfill-first semantics.
@@ -0,0 +1,102 @@
1
+ # Verified Mac CLI and service rollout
2
+
3
+ The Mac service now uses `main` at
4
+ `51a071ee5af3b722955260edbc669998eb025d6e` and the existing XDG database.
5
+ [PR31](https://github.com/archeism/ledger/pull/31) preserves robot output
6
+ compatibility and fixes Cursor schema classification, closing issue 18.
7
+ Its merge tree exactly matched the tested `3a610b5` tree.
8
+ The service checkout subsequently received documentation-only commit `0680cb5`.
9
+ Upstream PR30 landed during report publication and was preserved in the report's
10
+ merge, but was not deployed; the test and rollout claims here apply to the pinned
11
+ source revision above, not that newer scan-outcomes change.
12
+
13
+ ## Changes and checks
14
+
15
+ - Default robot search remains legacy hits-only JSONL or a JSON array. New agents
16
+ explicitly select `--output-version 2` for metadata and match provenance.
17
+ - Cursor checks required SQLite columns before projection. Invalid schema errors
18
+ no longer depend on runtime-specific error metadata; transient errors retain
19
+ their classification. The original test passed on this Mac, but four
20
+ metadata-stripped regressions failed before the fix and passed afterward.
21
+ - Full core suite: **494 passed, zero failed**, 3,393 assertions, 53.03 seconds.
22
+ Build, package typecheck, helper typecheck, and diff checks passed. The separate
23
+ observer suite passed 12 tests.
24
+ - Independent review found embedded personal fixtures and omitted cursor/staging
25
+ comparison fields in the first helper. Both were corrected before publication;
26
+ the supplemental comparison covered the omitted fields without repeating the
27
+ expensive full archive scan.
28
+
29
+ ## Preservation and retrieval
30
+
31
+ An online SQLite backup was rehearsed separately from the live store. The v6-to-v10
32
+ migration took 23.4 seconds on that copy. Full row digests matched for 1,333,616
33
+ records, 12,880 sessions, 14,874 embeddings, and 12,992 cursors. Old cursor identity
34
+ and prefix hashes and staged-session metadata also matched. Before/after SQLite
35
+ quick checks passed, with no foreign-key violations.
36
+
37
+ Eleven frozen checks passed both before and after migration: original ACTI eval
38
+ and Cursor Git-notes retrieval, the broad evaluation-repository keyword, one
39
+ original session from each of seven populated harnesses, and a negative control.
40
+ All positive target sessions ranked first within source-filtered top-50 results.
41
+ Database, WAL, and writer-lock hashes were unchanged by the query batches.
42
+
43
+ After stopping the old watcher, a fresh quiescent backup held 1,334,038 records
44
+ and 12,884 sessions. The live migration preserved those counts exactly. All 11
45
+ live checks then passed with unchanged database/WAL/lock hashes while the service
46
+ was idle. The live negative was generated privately before querying: an earlier
47
+ visible control literal could itself enter the archive through this agent's
48
+ transcript. Positive cases and limits were unchanged, and both fixtures remain
49
+ available in the private evidence bundle.
50
+
51
+ These checks establish preservation and sampled retrieval, not full historical
52
+ coverage or general ranking quality. Widening retains its 10,000-record ceiling;
53
+ this archive is larger, so it does not automatically receive that fallback.
54
+
55
+ ## Installed operation
56
+
57
+ `~/.local/bin/ledger` now invokes the stable workspace checkout. The launchd job
58
+ `com.archeism.ledger` retains the existing database, all 14 configured sources,
59
+ and discovery limit of 1,000,000 per source. It runs bounded `sync` every 900
60
+ seconds, with one worker, 25 admitted sessions, 64 MiB source budget, 120-second
61
+ pass budget, and 30-second worker deadlines; the old always-on watcher is stopped.
62
+
63
+ Two real passes exited zero and their process trees terminated:
64
+
65
+ | Pass | Duration | Published | Staged Records After | Worker Timeouts |
66
+ | --- | --- | --- | --- | --- |
67
+ | Initial scheduled pass | 115.1 s | No completed sessions | 1,593 | 3 |
68
+ | Explicit resumability check | 111.6 s | 1 session / 31 records | 2,868 | 3 |
69
+
70
+ Final observed totals were 1,334,069 records and 12,885 sessions. Backfill is
71
+ **not complete**: 14,785 queue entries remained, including six timed-out items
72
+ scheduled for retry. Existing failed source artifacts were not silently cleared.
73
+ The service is expected to be idle between passes, with last exit code zero.
74
+
75
+ ## Resource and Evidence Limits
76
+
77
+ The first observer had five database-aggregate timeouts on the large store;
78
+ its incomplete result is retained. A second process-only observation reused
79
+ the repository's PID/start-time tracking, sampled every second without database
80
+ aggregation, and had no collection errors. It attached after startup: its
81
+ 330,727,424-byte sampled peak RSS and 29.67 observed CPU-seconds are lower bounds,
82
+ not whole-pass maxima or a capacity guarantee. No descendants remained at exit.
83
+
84
+ No model was called by the measured operations. Early Bun `resourceUsage()`
85
+ objects serialized as `{}`; they are unavailable measurements, not zeros.
86
+ A replay explicitly materialized their non-enumerable getters and CPU bigint
87
+ counters. Physical process I/O bytes remain unavailable on this Mac. The evidence
88
+ validator reports **valid, incomplete**, with only those two I/O dimensions
89
+ unavailable; no percentile or throughput claim follows from these probes.
90
+
91
+ Private artifacts are under the rollout worktree's
92
+ `.local/runtime-upgrade-20260913/`: frozen fixtures, before/after digests,
93
+ supplemental preservation checks, query attempts, full test log, both observations,
94
+ service summaries, and checksummed `run.json`. They are excluded from Git.
95
+ See [the replay protocol](https://github.com/archeism/ledger/blob/43081aef54c23b4bd017b6c0e11fc42a9a1cb381/lab/runtime-rollout/README.md).
96
+
97
+ Paired rollback files are under
98
+ `~/.local/share/ledger/backups/20260913-runtime-upgrade/`, including
99
+ `quiescent-pre-upgrade.sqlite`, `pre-upgrade.plist`, and `rollout-state.json`.
100
+ Stop the new job first, retain the latest database and sidecars, then restore the
101
+ old backup with code `6a33ca80e921040981114bf3a94e9995566a0f15` and its plist.
102
+ Never run an old writer on the migrated database or discard post-upgrade data.
@@ -0,0 +1,80 @@
1
+ # Per-source scan outcomes, 2026-09-13
2
+
3
+ ## Outcome
4
+
5
+ `scanSessions` collapsed every listing failure into one `read_error`
6
+ diagnostic delivered to an `onDiagnostic` callback that no caller passed —
7
+ sources failed silently and reported 0 sessions; the extended directory
8
+ branch swallowed filesystem errors with no diagnostic at all; and the
9
+ installed Trajectory 0.3.0 cannot fix this from below: a verified probe
10
+ of the package under Bun shows 8 of 10 file listers return silent
11
+ `items=0` for missing, empty, and unreadable roots alike, and the SQLite
12
+ listers' most common real failures escape as raw `SQLiteError` with no
13
+ code. This cycle computes scan outcomes scanner-side and reports one row
14
+ per source.
15
+
16
+ - `scanSessions` returns `{sessions, outcomes}` (clean cutover; every
17
+ caller migrated). Each `ScanOutcome` row carries `source`, `root`,
18
+ a closed status (`listable`, `missing_root`, `root_not_directory`,
19
+ `unreadable_root`, `listing_failed`), `discovered`, and a capped
20
+ content-free `detail` (error class + code only; the only path in a row
21
+ is the root itself). Rows are sorted by source; a zero row is a signal,
22
+ not absence.
23
+ - Ledger probes each resolved root itself (stat: ENOENT vs non-directory
24
+ vs access error) before listing, mirroring exactly what each lister
25
+ reads — verified against the installed adapters for all 10 library
26
+ sources, both native roots, and the extended locations.
27
+ - Native sources funnel their existing diagnostics into the rows:
28
+ a diagnostic alongside discovered sessions keeps `listable` with the
29
+ message in `detail`; `listing_failed` fires only when the scan threw or
30
+ discovered nothing. Extended sources replaced silent skips with rows.
31
+ - `scan --robot` JSONL emits a leading `{"type":"scan_outcomes",...}`
32
+ line (the `search_meta` precedent); `--json` gains `outcomes`; human
33
+ output is byte-identical to baseline when every source is listable and
34
+ otherwise prints one stderr note per anomalous source — `missing_root`
35
+ rows stay silent (absent defaults are normal; robots get every row).
36
+
37
+ ## Evidence chain
38
+
39
+ [Confer round 7](../../confer/2026-09-13-round-7/README.md): the installed-
40
+ package behavior matrix (trajectory), Obelisk's errno split and
41
+ provenance analysis (AGPL — patterns only), AgentsView's typed
42
+ per-source status shape over doctor's three-way text ladder, Cass's
43
+ all-count-keys and sorted/deduped diagnostics discipline with a curated
44
+ typed channel only (rider — patterns only), and letta-code recorded as
45
+ the deliberate counterexample (listing hides unusable sources).
46
+
47
+ ## Verification (combined adversarial + independent rounds)
48
+
49
+ - Root resolution: 14/14 default roots mirror the actual listers
50
+ (compared against installed adapter code); a fake HOME with real-shaped
51
+ stores for all fourteen sources yields 14/14 `listable` with discovered
52
+ counts equal to the library's; the real HOME yields 8 `listable`
53
+ (claude-code 113, codex 833, cursor 640, hermes 124, omp 77, opencode
54
+ 932, pi 873, droid 68) and 6 `missing_root`, each verified genuinely
55
+ absent — no false verdicts.
56
+ - Invariance: human stdout byte-identical to baseline `cb673ea` across
57
+ three HOME shapes (all-listable, partial, real); robot JSONL delta is
58
+ exactly the leading outcomes line; `--json` strictly additive.
59
+ - Mutations: removing the probe or the sort each fails multiple tests;
60
+ the native partial-evidence edge (diagnostic + sessions → `listable`
61
+ with detail) is pinned.
62
+ - Suite: 486 pass / 1 fail of 487 — the pre-existing native-cursor #18.
63
+ Typecheck/build clean. The audit's findings were fixed before shipping:
64
+ native partial-evidence no longer mislabels working Cursor installs
65
+ (640 sessions reported with a diagnostic), lab controller probes
66
+ destructure the new shape (their deeper fixture rejection is
67
+ pre-existing and out of scope), the root/status doc widened, default-
68
+ scan note noise suppressed, sort made code-unit stable.
69
+
70
+ ## Boundaries
71
+
72
+ - Outcomes are recomputed per scan and never persisted; durable per-source
73
+ coverage state (a natural fit for `ingest_queue.last_outcome`) is a
74
+ later cycle.
75
+ - `status` describes the source's scan; `root` names the primary
76
+ location — a multi-location source can be `listable` while `detail`
77
+ records a failure elsewhere (documented).
78
+ - Two historical lab controllers were migrated to the new shape but
79
+ remain non-runnable on their original fixtures for a pre-existing
80
+ OpenCode validator reason (identical before this change; recorded).