omp-fabric 1.3.3 → 1.4.0

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 (73) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/agents/handoff.d.ts.map +1 -1
  3. package/dist/chunks/{chunk-WZAH7BO2.js → chunk-2J2GOB4A.js} +30 -11
  4. package/dist/chunks/chunk-2J2GOB4A.js.map +7 -0
  5. package/dist/chunks/{chunk-2WDZT27Q.js → chunk-3H5LZWAG.js} +253 -4
  6. package/dist/chunks/chunk-3H5LZWAG.js.map +7 -0
  7. package/dist/chunks/{chunk-PYXBHMSL.js → chunk-IMSGR6OW.js} +3 -3
  8. package/dist/chunks/chunk-IY3IQPRQ.js +308 -0
  9. package/dist/chunks/chunk-IY3IQPRQ.js.map +7 -0
  10. package/dist/chunks/{chunk-VSSC4IDU.js → chunk-RTDJFHGH.js} +2 -2
  11. package/dist/chunks/{chunk-45URY66G.js → chunk-S4I7RMR5.js} +3 -3
  12. package/dist/chunks/{chunk-ZP3S74LW.js → chunk-SG4GVSWX.js} +49 -26
  13. package/dist/chunks/chunk-SG4GVSWX.js.map +7 -0
  14. package/dist/chunks/{chunk-JOWMM3EX.js → chunk-WPU4PKXQ.js} +135 -24
  15. package/dist/chunks/chunk-WPU4PKXQ.js.map +7 -0
  16. package/dist/chunks/{chunk-Z5AP4M6K.js → chunk-YOAZ5SO7.js} +12 -2
  17. package/dist/chunks/{chunk-Z5AP4M6K.js.map → chunk-YOAZ5SO7.js.map} +2 -2
  18. package/dist/compaction/branch-summary.d.ts +1 -1
  19. package/dist/compaction/branch-summary.d.ts.map +1 -1
  20. package/dist/compaction/hook.d.ts +21 -1
  21. package/dist/compaction/hook.d.ts.map +1 -1
  22. package/dist/compaction/hook.js +1 -1
  23. package/dist/compaction/lcm-maintenance.d.ts +103 -0
  24. package/dist/compaction/lcm-maintenance.d.ts.map +1 -0
  25. package/dist/compaction/lcm-model.d.ts +41 -0
  26. package/dist/compaction/lcm-model.d.ts.map +1 -0
  27. package/dist/compaction/lcm-runtime.d.ts +106 -0
  28. package/dist/compaction/lcm-runtime.d.ts.map +1 -0
  29. package/dist/config-migrations.d.ts +1 -1
  30. package/dist/config-migrations.d.ts.map +1 -1
  31. package/dist/config.d.ts +7 -1
  32. package/dist/config.d.ts.map +1 -1
  33. package/dist/fabric-runtime-state.d.ts +2 -0
  34. package/dist/fabric-runtime-state.d.ts.map +1 -1
  35. package/dist/fabric-runtime-state.js +12 -7
  36. package/dist/fabric-runtime-state.js.map +2 -2
  37. package/dist/fabric-state.d.ts +2 -1
  38. package/dist/fabric-state.d.ts.map +1 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +1030 -108
  41. package/dist/index.js.map +4 -4
  42. package/dist/memory/lcm-adapter.d.ts +97 -0
  43. package/dist/memory/lcm-adapter.d.ts.map +1 -0
  44. package/dist/providers/memory-provider.d.ts +8 -0
  45. package/dist/providers/memory-provider.d.ts.map +1 -1
  46. package/dist/providers/memory-provider.js +2 -1
  47. package/dist/residency/host.js +6 -5
  48. package/dist/residency/omp-entry.js +6 -5
  49. package/dist/residency/omp-entry.js.map +1 -1
  50. package/dist/runtime/core-override-guest-types.js +1 -1
  51. package/dist/runtime/guest-types.d.ts +1 -1
  52. package/dist/runtime/guest-types.d.ts.map +1 -1
  53. package/dist/runtime/guest-types.js +1 -1
  54. package/dist/storage/lcm-ledger.d.ts +107 -0
  55. package/dist/storage/lcm-ledger.d.ts.map +1 -0
  56. package/dist/storage/lcm-migration.d.ts +67 -0
  57. package/dist/storage/lcm-migration.d.ts.map +1 -0
  58. package/dist/ui/settings.js +5 -5
  59. package/dist/ui/settings.js.map +2 -2
  60. package/docs/adr/0001-lcm-durable-context-ledger.md +6 -0
  61. package/docs/agents/domain.md +25 -0
  62. package/docs/agents/issue-tracker.md +25 -0
  63. package/docs/agents/triage-labels.md +11 -0
  64. package/docs/compaction.md +78 -312
  65. package/docs/configuration.md +3 -3
  66. package/package.json +1 -1
  67. package/dist/chunks/chunk-2WDZT27Q.js.map +0 -7
  68. package/dist/chunks/chunk-JOWMM3EX.js.map +0 -7
  69. package/dist/chunks/chunk-WZAH7BO2.js.map +0 -7
  70. package/dist/chunks/chunk-ZP3S74LW.js.map +0 -7
  71. /package/dist/chunks/{chunk-PYXBHMSL.js.map → chunk-IMSGR6OW.js.map} +0 -0
  72. /package/dist/chunks/{chunk-VSSC4IDU.js.map → chunk-RTDJFHGH.js.map} +0 -0
  73. /package/dist/chunks/{chunk-45URY66G.js.map → chunk-S4I7RMR5.js.map} +0 -0
@@ -0,0 +1,6 @@
1
+ ---
2
+ status: accepted
3
+ ---
4
+ # LCM owns the durable context ledger
5
+
6
+ OMP Fabric's LCM engine owns a project-scoped SQLite context ledger containing every raw conversation entry indefinitely, plus immutable leaf and condensed summary nodes. The OMP session JSONL remains an integration source for on-demand selected-session reconciliation, while the LCM compaction hook reads ready frontier state and returns the standard OMP result without blocking on maintenance. This replaces the old Fabric projection directly because the required durability, hierarchy, and recovery semantics cannot be provided by the derived memory cache or by a compaction hook alone. The deterministic emergency reducer is retained inside LCM for provider outages, and the existing OMP-native engine remains an explicit delegation path.
@@ -0,0 +1,25 @@
1
+ # Domain Docs
2
+
3
+ How the engineering skills should consume this repo's domain documentation when exploring the codebase.
4
+
5
+ ## Before exploring, read these
6
+
7
+ - `CONTEXT.md` at the repo root, if it exists.
8
+ - `docs/adr/` for decisions that touch the area being changed, if it exists.
9
+
10
+ If these files do not exist, proceed silently. Create them lazily when domain terms or durable decisions are resolved.
11
+
12
+ ## File structure
13
+
14
+ This is a single-context repository:
15
+
16
+ ```
17
+ /
18
+ ├── CONTEXT.md
19
+ └── docs/
20
+ └── adr/
21
+ ```
22
+
23
+ ## Use the glossary vocabulary
24
+
25
+ Use terms from `CONTEXT.md` when naming domain concepts. Flag conflicts instead of silently introducing synonyms.
@@ -0,0 +1,25 @@
1
+ # Issue tracker: GitHub
2
+
3
+ Issues and specs for this repo live as GitHub issues. Use the GitHub CLI for all operations.
4
+
5
+ ## Repository
6
+
7
+ - **Repository**: tickernelz/omp-fabric
8
+ - **Create an issue**: `gh issue create --title "..." --body "..."`
9
+ - **Read an issue**: `gh issue view <number> --comments`
10
+ - **List issues**: `gh issue list --state open`
11
+ - **Comment on an issue**: `gh issue comment <number> --body "..."`
12
+ - **Apply or remove labels**: `gh issue edit <number> --add-label "..."` / `--remove-label "..."`
13
+ - **Close**: `gh issue close <number> --comment "..."`
14
+
15
+ ## Pull requests as a triage surface
16
+
17
+ **PRs as a request surface: no.**
18
+
19
+ ## When a skill says "publish to the issue tracker"
20
+
21
+ Create a GitHub issue and apply the appropriate triage label.
22
+
23
+ ## Blocking
24
+
25
+ Use GitHub native issue dependencies when available. Otherwise record each dependency in a `Blocked by` line in the issue body.
@@ -0,0 +1,11 @@
1
+ # Triage Labels
2
+
3
+ The skills speak in terms of five canonical triage roles. This file maps those roles to the labels used in this repository's GitHub tracker.
4
+
5
+ | Label in Matt Pocock skills | Label in GitHub | Meaning |
6
+ | --- | --- | --- |
7
+ | `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue |
8
+ | `needs-info` | `needs-info` | Waiting on reporter for more information |
9
+ | `ready-for-agent` | `ready-for-agent` | Fully specified and ready for an agent |
10
+ | `ready-for-human` | `ready-for-human` | Requires human implementation |
11
+ | `wontfix` | `wontfix` | Will not be actioned |
@@ -1,332 +1,98 @@
1
- # Deterministic compaction
1
+ # LCM compaction
2
2
 
3
- OMP Fabric provides an LLM-free compactor through `session_before_compact`. This compactor is the default engine. Set `compaction.engine` to `"omp"` to defer to OMP's native compactor.
3
+ OMP Fabric uses LCM as its default compaction engine. Set `compaction.engine` to `"omp"` only when OMP's native compaction should own the session.
4
4
 
5
- Fabric keeps a bounded recent raw continuity tail after compaction. The tail uses OMP's active `keepRecentTokens` setting, which defaults to 20,000 tokens. Fabric rebuilds the older state into its deterministic summary. OMP's native cut and Codex-style checkpoint compaction use the same fresh-window principle. The summary carries durable state, and a small raw suffix keeps the recent conversation coherent for the model.
5
+ ## Model-visible context
6
6
 
7
- `compaction.targetContextRatio` sets a hard occupancy ceiling that applies after compaction. Fabric never treats the ceiling as space to fill. The value defaults to 75%, and you can change it from `/fabric-settings` (shown as **Max occupancy**) or in JSON. Allowed values are bounded to `0.25`–`0.85`. The ceiling is one of four constraints and the smallest wins; in practice continuity binds first on a large-context model, so measured post-compaction occupancy usually lands far below this value and changing it alone has no effect:
7
+ LCM assembles one bounded OMP compaction result from:
8
8
 
9
- ```json
10
- {
11
- "compaction": {
12
- "engine": "fabric",
13
- "targetContextRatio": 0.75
14
- }
15
- }
16
- ```
9
+ - ready summary-frontier nodes;
10
+ - a protected fresh tail selected by OMP's `firstKeptEntryId` preparation;
11
+ - bounded source and lineage metadata.
17
12
 
18
- Configure OMP's continuity tail in OMP's `settings.json`:
13
+ The hook uses the standard `session_before_compact` contract. It reads committed nodes and produces a valid `CompactionResult`; it does not call or await a summarization model. When semantic maintenance has not produced a ready node, the hook emits a bounded deterministic emergency excerpt with explicit source references.
19
14
 
20
- ```json
21
- {
22
- "compaction": {
23
- "keepRecentTokens": 20000
24
- }
25
- }
26
- ```
15
+ ## Durable storage
16
+
17
+ LCM stores the complete authoritative OMP `SessionEntry` as canonical UTF-8 JSON in a project-scoped SQLite ledger outside the working tree. Object keys are recursively sorted before hashing. The ledger retains raw entries indefinitely by default and never deletes them during compaction.
18
+
19
+ Each summary node is immutable after publication of its source identity. Leaf nodes cover bounded raw-entry ranges. Condensed nodes cover completed child nodes. Every source reference carries the session, entry ID, revision, and payload hash. Node, edge, frontier, and maintenance-job publication is transactional.
20
+
21
+ SQLite uses WAL, `synchronous=FULL`, a serialized writer, a 5-second busy timeout, and startup integrity verification. Project storage uses canonical recorded cwd/realpath identity with device/inode preference when available. Symlink aliases and renames converge; distinct worktrees remain distinct projects.
22
+
23
+ ## Lifecycle
24
+
25
+ `message_end` is only a dirty-session hint because OMP emits a detached message before native persistence. LCM assigns authoritative identity from post-persistence session readback:
26
+
27
+ 1. `session_start` reconciles only the selected `getSessionFile()`; unrelated sessions are not scanned.
28
+ 2. `agent_end` and `session_compact` read the stable active branch and append complete entries idempotently.
29
+ 3. Background maintenance claims leaf and condensation jobs with durable leases and bounded retries.
30
+ 4. A later compaction hook reads ready nodes without waiting for maintenance.
31
+ 5. `session_shutdown` aborts model work, drains writes, and closes the ledger.
27
32
 
28
- Use `{ "compaction": { "engine": "omp" } }` to defer to OMP's native compaction engine.
33
+ The selected-session reconciler stores a source generation/checkpoint and resumes after interruption. It does not perform a global three-day migration. The old bulk migration command is not part of normal operation.
29
34
 
30
- `/fabric settings` also exposes a **Threshold** for the active model. It
31
- supports two modes: a window-occupancy percent or an exact token count
32
- ("Custom tokens…"). Fabric stores thresholds by canonical `provider/model`
33
- key, so switching models selects that model's own value. `OMP default` clears
34
- both maps and leaves OMP's built-in threshold unchanged.
35
+ ## Summary maintenance
36
+
37
+ The dedicated model is selected from `compaction.summaryModel` through OMP's public model registry and session-aware resolver. The active session model is the fallback when the dedicated route is unavailable. Leaf and condensed prompts XML-fence transcript evidence and treat it as untrusted data.
38
+
39
+ Maintenance defaults are bounded to 32 model calls, 2,000,000 input tokens, and 128,000 output tokens per project per UTC day, with a nested 16-call session limit. One project model job runs at a time. Jobs use 30-second leases renewed every 10 seconds, 60-second call limits, exponential retry backoff capped at 15 minutes, and three attempts. A failed call does not publish a ready node or increment usage counters.
40
+
41
+ The emergency reducer is deterministic, explicitly nonsemantic, source-addressed, and bounded to 4,096 bytes by UTF-8 size. Provider failure keeps raw entries and pending maintenance recoverable.
42
+
43
+ ## Retrieval
44
+
45
+ Use the existing namespaced memory actions:
46
+
47
+ - `memory.recall` returns bounded raw and summary hits. The default LCM scope is the current session when one is bound; explicit session scope remains available. Active-branch results require source references on the live branch. Incomplete or stale coverage is reported and never treated as an authoritative no-match.
48
+ - `memory.expand` follows a stable raw or summary reference. Raw expansion returns the exact structured `SessionEntry` payload, including tool arguments, tool results, custom details, and media fields. Summary expansion returns the summary text and its structured source references.
49
+ - `memory.sessions` remains the session inventory action.
50
+
51
+ Summary text is a navigation aid. Exact action or factual claims should be checked against expanded raw source entries.
52
+
53
+ ## Tree and handoff behavior
54
+
55
+ LCM uses the standard `session_before_tree` hook when the user requests a branch summary. The result contains bounded typed branch facts and the abandoned `oldLeafId`; sibling branch prose is not used as source truth.
56
+
57
+ Trajectory handoff compaction has no live `ExtensionContext`, so it uses the LCM deterministic emergency reducer over the discarded prefix, keeps the latest user boundary when one exists, and records source range metadata. It does not invoke the old Fabric compiler or a hidden model call.
58
+
59
+ ## Operational controls
60
+
61
+ Raw retention is indefinite but bounded operationally:
62
+
63
+ - 8 GiB per project: warning in status and UI when available;
64
+ - 10 GiB per project: stop new model-maintenance claims while preserving raw appends;
65
+ - ENOSPC: durable degraded state; no successful skip is reported;
66
+ - backup/export: mode-0600 `VACUUM INTO` copy with SHA-256, row counts, and integrity manifest;
67
+ - deletion: explicit typed project confirmation, verified backup, transactional scoped delete, post-delete integrity check, and audit manifest.
68
+
69
+ Automatic raw deletion is disabled.
70
+
71
+ ## Configuration
35
72
 
36
73
  ```json
37
74
  {
38
75
  "compaction": {
39
- "thresholds": {
40
- "anthropic/claude-sonnet-4-5": 0.8,
41
- "openai/gpt-5.4": 0.9
42
- },
43
- "tokenThresholds": {
44
- "google/gemini-3-pro": 400000
45
- }
76
+ "engine": "lcm",
77
+ "summaryModel": "provider/model",
78
+ "targetContextRatio": 0.75,
79
+ "lcmMaxInputChars": 48000,
80
+ "lcmMaxOutputTokens": 4096,
81
+ "lcmMaxOutputChars": 16384,
82
+ "lcmMaxLeafEntries": 8,
83
+ "lcmMaxCondenseChildren": 4
46
84
  }
47
85
  }
48
86
  ```
49
87
 
50
- Fabric bounds percent thresholds to `0.25`–`0.95` and rounds token thresholds
51
- to integers bounded to `1,000`–`100,000,000`. When a hand-written config sets
52
- both for one model, the token threshold wins. A configured threshold makes
53
- Fabric trigger compaction at a safe settled boundary once the active model
54
- reaches it. OMP's own automatic compaction keeps its built-in trigger: the
55
- host's `session_before_compact` event carries no trigger reason, so Fabric
56
- cannot tell an automatic threshold compaction apart from an overflow or manual
57
- one and never defers the host's automatic pass.
58
-
59
- ## Invariants
60
-
61
- 1. **The session log is ground truth.** The summary is a bounded continuation view with stable entry-id and file addresses.
62
- 2. **Live cut and cumulative truth are separate.** The cut comes from the window made live by the last compaction. Fabric rebuilds the summary from every raw, typed, content-bearing entry on the supplied active branch prefix before the new kept boundary.
63
- 3. **Rendered summaries are never semantic input.** `compaction` entries, branch-summary prose, custom summary prose, and unknown roles produce no normalized events. A valid Fabric branch-summary details envelope may contribute its typed facts. Its `summary` string never contributes. Top-level OMP `custom_message` entries work differently: OMP puts them in model context, so Fabric preserves their typed `customType`, text content, visibility, and bounded JSON details. `custom` state entries that bear no context remain excluded.
64
- 4. **Structure drives projection.** The core uses entry/message types, roles, content-part types, custom-message fields, tool names, typed `fabric_exec` display fields, JSON arguments, call ids, `isError`, aggregate trace outcomes, exit codes, entry ids, ordering, valid Fabric execution traces, and valid Fabric branch-summary facts. It applies no semantic regex over prose, code, shell commands, or tool output. Whitespace normalization, bounded truncation, exact identity comparisons, and path segmentation stay mechanical.
65
- 5. **Serialization is deterministic and bounded.** Identical branch entries and instructions produce byte-identical output. The rendered result is at most 32 KiB in UTF-8.
66
- 6. **The nominal model window is the safety boundary.** Fabric never treats it as a target to fill. Fabric calibrates OMP's structural token estimate against `preparation.tokensBefore`, retains the largest closure-safe suffix within OMP's bounded `keepRecentTokens` continuity budget, and treats the configured occupancy ratio, OMP response reserve, estimator-error margin, and pre-compaction size as hard ceilings. Undocumented provider headroom never enters the budget.
67
-
68
- These invariants prevent summary-chain drift and deterministic
69
- forgetting. OMP replaces the previous rendered summary on each compaction.
70
- Fabric still re-derives the original goal, cumulative successful file
71
- addresses, error state, and user scope changes from raw branch history every
72
- time.
73
-
74
- ## Loss model and memory
75
-
76
- Fabric compaction is **source-lossless and addressably lossless**. The model's bounded continuation view does not stay byte-for-byte lossless:
77
-
78
- - Compaction appends a marker. It never deletes or rewrites raw session JSONL. The active parent-linked session branch remains ground truth.
79
- - The model receives a bounded deterministic projection plus the recent raw continuity tail. Fabric preserves typed goals, declared Fabric run intent paired with aggregate outcomes, file operations, failures, status, and stable addresses through mechanical rules. Arbitrary old prose, tool-output bodies, and thinking may fall out of the inline view.
80
- - Every sampled omission records a count and source entry-id range. `memory.expand` can re-read exact untruncated source by stable entry ID or operation address with source-hash and lineage checks.
81
- - The memory index remains derived and disposable. Compaction works without successful indexing, and it never treats an incomplete index as ground truth. Exact expansion reads session JSONL.
82
-
83
- Near-lossless continuation comes from three layers: dense typed projection for
84
- normal work, a bounded raw tail for immediate local coherence, and
85
- integrity-bound source recall for exact old detail. Deleting the source
86
- session removes the final exact-recall layer.
87
-
88
- ## OMP pipeline
89
-
90
- ```text
91
- active branch entries ─┬─► live window ─► calibrated token budget ─► closure-safe cut ─► firstKeptEntryId
92
- └─► raw cumulative prefix ─► normalize ─► project ─► bound/render
93
- ```
88
+ Legacy persisted `compaction.engine: "fabric"` is migrated to `"lcm"` by the config migration. Unknown engine values normalize to the LCM default. OMP native delegation remains the explicit `"omp"` value.
94
89
 
95
- - `normalize.ts` converts raw message and top-level `custom_message` entries to typed events. It selects custom content only from typed string or text parts, keeps JSON details depth/node/collection/string/byte bounded, and omits malformed details while otherwise valid content stays. Assistant thinking parts count as deliberation, so normalization never turns them into events. Summaries carry side effects and state, and truncated scratchpad text that could read as fact stays out. The compactor records how many thinking blocks it erased, so the omission stays auditable. Only `toolCallId` pairs each tool call with its result. A completed `fabric_exec` with a non-empty typed `display.name` contributes a bounded declared-intent event that carries its optional `display.description`, aggregate outcome, and call address. A `fabric_exec` result contributes nested events only through a valid `details.trace` V1 guard, or through the separate strict legacy `details.audits` adapter when no `trace` field exists.
96
- - `projections.ts` computes goal, file, operation-state, turn, status, and transcript views.
97
- - `enrichers.ts` permits deterministic optional annotations. Fabric ships no built-in enrichers.
98
- - `render.ts` independently bounds every rendered block and enforces the global UTF-8 limit.
99
- - `hook.ts` computes the live cut, selects cumulative source, and emits v2 details for the configured OMP or Fabric engine.
100
-
101
- ## Live cut and closure
102
-
103
- The last compaction marker identifies the live window:
104
-
105
- - a valid `firstKeptEntryId` starts the window at that entry.
106
- - a compact-all marker or missing/orphan kept id starts it after the marker.
107
- - without a marker, the whole supplied active path is live.
108
-
109
- When OMP supplies the active model metadata, Fabric chooses the live cut from a calibrated bounded continuity budget:
110
-
111
- 1. Sum OMP's public structural message estimates for the current context.
112
- 2. Calibrate that estimate with `preparation.tokensBefore`, which compensates for provider tokenization, system prompts, tool schemas, and other fixed context that a character heuristic cannot observe directly.
113
- 3. Set the continuity target to calibrated fixed overhead plus OMP's `keepRecentTokens` and the maximum 32 KiB summary reservation. The absolute recent-tail budget does not grow with a 200K, 1M, or proxy-inflated advertised window.
114
- 4. Clamp that target to all independent safety ceilings: `contextWindow × targetContextRatio`, 90% of `contextWindow - reserveTokens`, and 95% of `tokensBefore`. The last ceiling prevents a low-usage manual compaction from expanding context. The advertised window is authoritative for threshold and manual compaction. Overflow recovery treats the failed request as stronger evidence: an API rejection proves the effective window is below `tokensBefore`, so Fabric first clamps the working window to 90% of the observed failed size.
115
- 5. Select the earliest eligible boundary whose retained suffix fits the resulting raw-tail budget. Suffix size decreases monotonically, so this boundary gives the largest legal raw suffix. User/custom boundaries and assistant boundaries are both eligible, which lets Fabric split a single enormous autonomous turn during compaction. On repeated compaction, the kept boundary must follow the previous compaction marker in raw log order. OMP replays entries contiguously from `firstKeptEntryId`, so a boundary before that marker would replay the old rendered summary beside the new one.
116
-
117
- Fabric computes structural spans for every call id across the supplied branch
118
- and rejects every candidate cut that separates an actual call/result pair.
119
- This enforces both directions:
120
-
121
- - a summarized tool call never has a kept result.
122
- - a kept tool call never has a summarized result.
123
-
124
- This pairing check handles parallel calls, delayed results, reverse or
125
- malformed ordering, and malformed prior boundaries. When no non-crossing
126
- boundary fits, Fabric uses compact-all (`firstKeptEntryId: ""`), and no kept
127
- side remains to orphan either half. If the rendered deterministic summary
128
- itself would push the calibrated projection over the target, Fabric cancels
129
- the compaction to avoid persisting an expanding or over-budget result. If
130
- model metadata is unavailable, the legacy latest-turn closure-safe cut remains
131
- as a compatibility fallback.
132
-
133
- The live cut determines only what OMP keeps. The summary source is the raw
134
- active-branch prefix before that new boundary. Normalization skips earlier
135
- compaction and branch-summary prose within that prefix.
136
-
137
- ## Bounded sections
138
-
139
- Fabric emits the original first user goal first. Later user scope changes and
140
- the potentially large file, operation-state, and earlier-turn collections use
141
- deterministic earliest-plus-latest sampling. Every omission records a count
142
- and a source entry-id range. File lines also carry the source call entry id.
143
-
144
- Rendered block limits include their headers:
145
-
146
- | Block | UTF-8 limit |
147
- | --- | ---: |
148
- | `[Session Goal]` | 4096 bytes |
149
- | `[Compaction Request]` | 3072 bytes |
150
- | `[Files And Changes]` | 4608 bytes |
151
- | `[Fabric Activity]` | 2048 bytes |
152
- | `[Outstanding Context]` | 4608 bytes |
153
- | `[Earlier Turns]` | 3072 bytes |
154
- | `[Current Status]` | 2048 bytes |
155
- | collapsed transcript | 5120 bytes |
156
- | footer | 1536 bytes |
157
-
158
- The limits sum below 32 KiB, leaving room for separators. A final UTF-8 guard
159
- enforces the global limit. Projection limits stay finite: 24 later goals, 24
160
- file addresses per operation kind, 32 operation-state records, 48 Fabric
161
- activity records, 32 earlier turns, and 40 transcript events. Omitted source
162
- remains executable-addressable through entry-id ranges and the footer recall
163
- pointer.
164
-
165
- ## Sections
166
-
167
- - **Session Goal**: up to three bounded lines from the original first user message, followed by sampled later user scope changes.
168
- - **Compaction Request**: canonicalized, bounded custom instructions. See below.
169
- - **Files And Changes**: successful typed file-tool addresses grouped as Created, Written, Modified, or Read. `edit` counts as Modified. `write` counts as Written unless a typed result explicitly proves creation.
170
- - **Fabric Activity**: completed named `fabric_exec` runs as bounded `name → outcome` records that place an em dash between the name and the optional description, followed in source order by phases and significant non-file nested operations, including bash, agents, workflow, mesh, state, MCP, and extension refs. Named runs expose the exact assistant call entry ID while sourced raw, and their typed fact address after branch rehydration. Nested phases and operations expose stable `entryId/subordinal` addresses. The name and outcome are mandatory for a rendered run. The optional description decays first under tighter views.
171
- - **Outstanding Context**: typed tool/bash failures and later exact structural resolutions. File failures require the same action and path, bash failures the same command, and generic failures the same ref and arguments. Fabric quotes explicit error text with bounds and never parses or classifies it. Trace failures use only `operation.outcome` and `operation.error`.
172
- - **Earlier Turns**: sampled user/custom context one-liners, tool-name counts, and the latest named Fabric run plus outcome for each summarized turn.
173
- - **Current Status**: the latest summarized user/custom context, modification address, named Fabric run plus outcome, and assistant line.
174
- - **Transcript**: the latest 40 typed events, including quoted and bounded custom-message content and bounded structural details, plus an omission range when applicable. A completed named `fabric_exec` replaces its generic outer call/result pair with `name → outcome`. The description stays in the richer Activity tier.
175
- - **Footer**: deterministic source timestamp, cumulative source range, and session-log recall guidance.
176
-
177
- Fabric omits commit projections. The core ignores `git commit`
178
- command prefixes, and it never pulls hashes or summaries from shell stdout. A
179
- caller that needs a commit ID across compaction must provide it explicitly
180
- through a valid typed `preserve` item or another typed state transition.
181
-
182
- ## Remaining structural text operations
183
-
184
- The clean core retains only these mechanical text operations:
185
-
186
- - select text from typed user, assistant, top-level custom-message, tool-result, Fabric display-name/description, command-argument, error, phase, ref, and path fields.
187
- - split user text on literal newlines for bounded goal lines, or select the first line for one-line views.
188
- - trim/collapse whitespace and truncate by fixed character or UTF-8 byte limits.
189
- - quote bounded user/custom/assistant/tool/error text without interpreting its content.
190
- - compare typed action/path, action/command, or ref/JSON-arguments identities exactly for resolution.
191
- - segment typed paths on `/` or `\\` to compute display roots.
192
- - split a typed Fabric ref once on `.` to expose provider/action identity.
193
- - inspect the explicit typed `created: true` result field for write classification.
194
- - decode the exact typed Fabric request prefix with a bounded structural JSON parser.
195
-
196
- The core never recovers command prefixes, stdout/stderr line formats, error
197
- wording, path-looking prose, commit-looking prose, source code, or tool-result
198
- renderings into semantic facts.
199
-
200
- ## Custom instructions
201
-
202
- Plain custom instructions are always explicit user data; Fabric never treats a reserved text sentinel as routing control.
203
-
204
- Fabric treats every other plain instruction as explicit user data. It
205
- canonicalizes whitespace, bounds the input, and includes the text in
206
- `[Compaction Request]` without semantically parsing it.
207
-
208
- `compact.request` may add typed `preserve: string[]` values. When present, the
209
- controller forwards an exact versioned prefix followed by JSON. The hook
210
- accepts only the exact prefix and a strict v1 object. Once that reserved
211
- prefix is present, malformed JSON or scalars, duplicate protocol keys
212
- (including escaped-key aliases), unknown fields or versions, invalid types,
213
- unpaired UTF-16 surrogates, excessive structure, or exceeded bounds produce a
214
- structured decode error and cancel the operation. Fabric never reinterprets or
215
- renders the encoded payload as plain instructions. A UI/RPC context receives a
216
- bounded error notification when available.
217
-
218
- Fabric enforces the typed v1 limits before value mapping or canonicalization.
219
- Instructions cap at 8192 characters and 8192 UTF-8 bytes. The `preserve` list
220
- holds at most 16 items, and each item caps at 2048 characters and 2048 UTF-8
221
- bytes. The complete prefix-plus-JSON source must fit within 16 KiB. The
222
- decoder checks the aggregate source limit before invoking its bounded
223
- recursive-descent parser. While parsing, it rejects duplicate decoded keys and
224
- validates scalar grammar and surrogate pairing. It checks the preserve count
225
- before it iterates or canonicalizes values. Plain OMP and manual instructions
226
- stay explicit bounded text and never run through the typed protocol parser.
227
-
228
- ## Compaction details v2
229
-
230
- New summaries emit `details.compactor: "fabric"` and `details.version: 2` with:
231
-
232
- - cumulative source and live-cut ranges.
233
- - branch, source-entry, event, and live-cut counts.
234
- - prior recognized Fabric v1/v2 marker counts.
235
- - per-projection omission counts, the typed preserve count (valid v1 requests cannot exceed the preserve limit), and the structural count of erased assistant thinking blocks.
236
- - instruction mode, canonicalization, source size, truncation, and preserve counts.
237
- - stable kept/source entry-id addresses and the source timestamp.
238
- - when continuity budgeting is active: effective window, occupancy ceiling ratio/tokens, continuity target, reserve and reduction ceilings, the binding constraint, OMP reserve/recent settings, raw estimate, calibration scale, fixed overhead, raw-tail budget, retained raw tokens, and Fabric's `projectedTokensAfter`. OMP core independently recomputes its own `estimatedTokensAfter` after persisting the compaction. Legacy v2 records with `strategy: "adaptive"` remain recognized.
239
-
240
- Fabric recognizes exact versions 1 and 2 only. v1 details and rendered prose
241
- never serve as truth. An old session migrates to v2 on the next compaction,
242
- because Fabric rebuilds the new result from raw active-branch entries. V2
243
- validation accepts the legacy commit-omission counter for old records. New
244
- summaries drop the commit projection and its counter.
245
-
246
- ## Nested Fabric execution traces
247
-
248
- For an outer `fabric_exec` tool result, normalization pairs the result with
249
- its assistant call by exact `toolCallId`. When that call has a non-empty typed
250
- `display.name`, Fabric emits a declared-intent record with an internal
251
- `call-entry-id/call:toolCallId` fact address. Fabric also exposes the
252
- assistant call entry ID for exact raw-source expansion, or that fact address
253
- after branch rehydration. Fabric bounds the name to 256 UTF-8 bytes and the
254
- optional description to 1024 bytes, and the outcome comes from a valid
255
- aggregate trace outcome or the outer typed `isError` flag when no aggregate
256
- exists. Fabric
257
- never treats this metadata as proof of work. The paired outcome and nested
258
- operations remain the authoritative evidence. Normalization reads nested
259
- execution only from `message.details.trace` through
260
- `readFabricExecutionTraceV1`. Emitted operations follow `operation.sequence`
261
- order with addresses such as `entry-id/0`, and phases use `entry-id/phase:0`.
262
- Known `omp.read`, `omp.grep`, `omp.find`, `omp.ls`, `omp.edit`, `omp.write`, and
263
- `omp.bash` and `` calls retain exact typed arguments and outcomes. Other refs remain
264
- typed Fabric activity.
265
-
266
- Fabric ignores a present trace version when it is malformed or unknown. It
267
- never reinterprets such a trace as legacy data. When `trace` is absent, the
268
- legacy adapter accepts only an audit array whose records have typed `ref`, JSON
269
- `args`, boolean `success`, and optional string `error`. The adapter never
270
- reads audit rendering or `result` prose. An unnamed outer tool conversation
271
- remains generic in the transcript. A completed named run replaces that generic
272
- call/result pair with its bounded name and outcome. `fabric_exec` source code
273
- and outer result prose still cannot create file, failure, or activity facts.
274
-
275
- ## Deterministic branch summaries
276
-
277
- When the Fabric engine is active, the same registration also handles
278
- `session_before_tree`. The handler returns nothing when `userWantsSummary` is
279
- false, and it compiles only `preparation.entriesToSummarize` when true. Tree
280
- custom instructions use the same plain/typed decoder and fail-closed limits as
281
- compaction. Plain instructions remain ordinary explicit request text on the tree path.
282
-
283
- `replaceInstructions: true` follows OMP replacement-prompt semantics. A
284
- deterministic projection cannot execute an arbitrary replacement summarizer
285
- prompt, so Fabric returns `undefined` and defers to OMP or another handler.
286
- Fabric produces no summary and no typed Fabric branch details in that explicit
287
- mode.
288
-
289
- Branch details use `kind: "omp-fabric.branch-summary"`, current `version: 2`,
290
- stable source addresses, and at most 256 bounded typed facts in a 128 KiB
291
- envelope. Facts cover source users, top-level custom messages, named Fabric
292
- runs, phases, and operations. V2 adds bounded `fabricRun` facts that carry the
293
- declared name and description with the paired outcome. Strict v1 envelopes
294
- remain readable, and Fabric never reinterprets them as v2. Newly generated
295
- details record `source.oldLeafId` from `preparation.oldLeafId`, which is the
296
- canonical abandoned/from-leaf provenance. Older v1 envelopes without that
297
- field remain readable. The OMP host writes the generic `BranchSummaryEntry.fromId`
298
- from the navigation target position, and that position differs from the
299
- abandoned leaf. A hook cannot correct that core-generated field, so consumers
300
- must use Fabric's typed `source.oldLeafId` when present.
301
-
302
- Nested branch summaries re-emit only valid typed facts, and normalization
303
- never reads branch summary prose. Later compaction can then resolve
304
- abandoned-branch failures against later exact successes, and custom context, files, and
305
- activity survive navigation or forks without any prose parsing. OMP supplies
306
- only the active path or the abandoned `entriesToSummarize` path to each
307
- compiler, so sibling branches cannot contaminate one another.
308
-
309
- ## OMP compaction precedence
310
-
311
- Precedence remains:
312
-
313
- 1. the configured compaction engine;
314
- 2. OMP's native compaction behavior when the engine is `"omp"`;
315
- 3. Fabric's deterministic summary when the engine is `"fabric"`.
316
-
317
- Fabric marks claimed events with `_fabricCompaction`. OMP's public extension contract runs `session_before_*` handlers in extension load order and keeps the latest non-cancelling result. An unrelated handler loaded after Fabric can replace Fabric's compaction or tree result. A later cancellation terminates dispatch. Fabric never monkeypatches OMP's private runner.
318
-
319
- ## Reconstruction QA
320
-
321
- `src/compaction/qa.ts` derives probes from normalized source events, never
322
- from rendered sections. QA probes follow the same bounded sampling policy as
323
- projections. The report checks directly rendered samples for content, and it
324
- validates omitted collections for count and range addressability. Mutation tests
325
- remove file, error, turn, latest Fabric run intent/outcome/address, and footer
326
- information to verify that the report detects loss.
327
-
328
- Run:
90
+ ## Verification
91
+
92
+ Focused LCM tests cover ledger durability, canonical payload identity, branch isolation, model budgets, emergency bounds, on-demand session reconciliation, memory provider routing, tree summaries, and handoff continuity. Run:
329
93
 
330
94
  ```sh
331
- bun vitest run tests/compaction-qa.test.ts
95
+ bun run check
332
96
  ```
97
+
98
+ This command includes typecheck, a fresh `dist/` build, the lazy-graph assertion, the full test suite, and dead-code lint.
@@ -158,7 +158,7 @@ where absent values do not participate. Orchestration programs (`agents.run` / `
158
158
  "updateDebounceMs": 100
159
159
  },
160
160
  "compaction": {
161
- "engine": "fabric"
161
+ "engine": "lcm"
162
162
  },
163
163
  "retention": {
164
164
  "orphanedTempRunMs": 21600000,
@@ -238,7 +238,7 @@ Each in-place handoff captures Main's active model at the boundary and restores
238
238
 
239
239
  `executor.resultFormat` sets the default for `fabric_exec` return values. Find it under `/fabric settings` → **Executor**. `"auto"` keeps strings as text and renders structured values as syntax-highlighted YAML. `"yaml"`, `"json"`, and `"text"` each force their named behavior. A call-level `resultFormat` parameter overrides the configured default.
240
240
 
241
- Configure the compaction engine under `/fabric settings` → **Compaction**. Select `"fabric"` for deterministic compaction or `"omp"` to hand compaction to OMP core.
241
+ Configure compaction under `/fabric settings` → **Compaction**. Select `"lcm"` for durable hierarchical context or `"omp"` to hand compaction to OMP core.
242
242
 
243
243
  ## Code modes
244
244
 
@@ -483,7 +483,7 @@ Mesh topics, shared state, and the participant directory remain project-scoped.
483
483
 
484
484
  ## Compaction
485
485
 
486
- The deterministic, LLM-free compaction engine is on by default. It keeps OMP's bounded `keepRecentTokens` continuity tail. `compaction.targetContextRatio` sets a hard occupancy ceiling. Set `compaction.engine` to `"omp"` to use OMP's native compaction or `"fabric"` to use Fabric's deterministic summary. See [compaction](compaction.md) for invariants, loss guarantees, sections, and limits.
486
+ The LCM compaction engine is on by default. It keeps OMP's bounded `keepRecentTokens` continuity tail and assembles durable summary nodes. `compaction.targetContextRatio` sets a hard occupancy ceiling. Set `compaction.engine` to `"omp"` to use OMP's native compaction. See [compaction](compaction.md) for invariants, loss guarantees, sections, and limits.
487
487
 
488
488
  ## Catalog repairs
489
489
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omp-fabric",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "A programmable tool and agent runtime for Oh My Pi (OMP)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",