dsh-engram 0.5.1 → 0.7.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.
package/README.md CHANGED
@@ -264,8 +264,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
264
264
  <!-- dsh-market compatibility block — keep labels bilingual and in sync with
265
265
  docs/RELEASE-NOTES.TEMPLATE.md (market README convention) -->
266
266
 
267
- - **DSH 版本 / DSH versions**: `>=0.1.2-alpha.2 <0.3.0-0` (本版 `0.5.1`; 已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` — 见下方矩阵)
268
- - **最后验证日期 / Last verified**: 2026-10-19 — 会话扫描修复(`session.v<N>.jsonl.zstd`,issue #8)+ 数据导出/导入与替换/冲突可视化(issue #3),npm test 334/334 通过
267
+ - **DSH 版本 / DSH versions**: `>=0.1.2-alpha.2 <0.3.0-0` (本版 `0.7.0`; 已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` — 见下方矩阵)
268
+ - **最后验证日期 / Last verified**: 2026-10-19 — episode / entity pages / anchor revalidation,npm test 381/381 通过
269
269
  - **安装方式已验证 / Verified install**: `dsh plugin --profile web add dsh-engram`
270
270
 
271
271
  > **Short version.** Every **published** release (`0.2.0` … `0.3.6`) supports
@@ -280,7 +280,9 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
280
280
  | `0.2.0` … `0.3.6` (npm, GitHub v0.3.3–v0.3.6) | published | **old DSH only** — `0.1.0-rc.7` / `0.1.0-rc.8` / `0.1.1-rc.1` / `0.1.1-rc.2` | peers `@deepseek-ai/dsh-*@^0.1.0-rc.7` |
281
281
  | `0.3.7` / `0.4.0` (npm) | published | **new DSH, settings `installSection`** — `>=0.1.2-alpha.2 <0.2.0-0` | `engines.dsh` + peers `>=0.1.2-alpha.2 <0.2.0-0` |
282
282
  | `0.5.0` (npm) | published | **DSH `0.1.2-alpha.2` … `<0.3.0-0`** — 设置卡迁移到 entry-id volatile Config(`0.1.7+`/`0.2.x`),`≤0.1.5` 自动回退 `installSection` | `engines.dsh` + peers `>=0.1.2-alpha.2 <0.3.0-0` |
283
- | `0.5.1` (本期 / this release) | published | 同 `0.5.0` — 会话扫描修复(`session.v<N>.jsonl.zstd`,issue #8)、数据导出/导入 GUI、替换/冲突可视化(issue #3) | 同 `0.5.0` |
283
+ | `0.5.1` | published | 同 `0.5.0` — 会话扫描修复(`session.v<N>.jsonl.zstd`,issue #8)、数据导出/导入 GUI、替换/冲突可视化(issue #3) | 同 `0.5.0` |
284
+ | `0.6.0` | published | 同 `0.5.0` — Context Ledger、BoundaryPrune/ResultPack 默认开 + 账本否决、JIT 推送、Context GC 改 opt-in | 同 `0.5.0` |
285
+ | `0.7.0` (本期 / this release) | published | 同 `0.5.0` — session episode、resume brief、entity pages/cards、revalidatable anchors + layered TTL | 同 `0.5.0` |
284
286
 
285
287
  ### Where the API family broke — `0.1.2-alpha.2`
286
288
 
@@ -314,7 +316,7 @@ the loader), and the settings form is keyed by the profile entry id (`engram`),
314
316
  so nothing needs "mounting". `0.5.0` feature-detects the two generations in
315
317
  `installEngramSettings`:
316
318
 
317
- - DSH `≥0.1.7` / `0.2.x` — the 27 GUI knobs are the volatile `Config` fields
319
+ - DSH `≥0.1.7` / `0.2.x` — the 34 GUI knobs are the volatile `Config` fields
318
320
  (`lib/settings.js` `makeEngineConfigSchema`, exported as `Config` from
319
321
  `lib/index.js`); the card reads/writes entry `engram` through the same
320
322
  `/api/dsh-engram/settings` HTTP route, and the `service.settings` seam
@@ -330,14 +332,29 @@ drives mutations).
330
332
  So: keep DSH on `0.1.1-rc.2` or older while running a release ≤ `0.3.6`, and
331
333
  upgrade the plugin to `>=0.3.7` before moving DSH to `0.1.2-alpha.2`.
332
334
 
333
- ### Current release — `0.5.1`
334
-
335
- Patch release on top of `0.5.0`: session scanning resolves the **versioned** log
336
- name (`session.v3/v4.jsonl.zstd`) instead of the hardcoded
337
- `session.jsonl.zstd` — on current DSH that mismatch made `/stats`, `/toolstats`,
338
- BoundaryPrune's repayment history and the CJK session search all return zero
339
- silently (issue #8). The memory viewer also gains data export/import and
340
- supersede/contradict visualization (issue #3).
335
+ ### Current release — `0.7.0`
336
+
337
+ From event records to **maintainable current truth**: sessions sediment an
338
+ episode at teardown, new sessions get a resume brief, `esr_node` becomes a
339
+ readable page, and file anchors make stale truth detectable.
340
+
341
+ - **Session episode** — zero-LLM digest at `session/disposed` (files / commands /
342
+ failures→fixed / decisions / open loops), never indexed, newest 20 per
343
+ workspace kept.
344
+ - **Resume brief** — the newest episode from the last 7 days is injected as a
345
+ `[RESUME]` line (≤240 chars + drill pointer) at session start.
346
+ - **Entity pages + cards** — `truth / timeline / open loops / conflicts /
347
+ relations`; up to 2 one-line cards in the index, full page via
348
+ `engram_detail(entity=…)`.
349
+ - **Revalidatable anchors** — file-backed memories record `mtime/size/sha256`;
350
+ a bounded revalidation at session start tags changed/missing sources `stale`
351
+ (dropped from index/truth, still re-fetchable).
352
+ - **Layered TTL** — preference/procedure permanent, episode 14d, error 60d,
353
+ others 180d.
354
+ - **Migration** — only new writes are anchored (no historical backfill);
355
+ restart `dsh web` after upgrading; an episode appears after one session ends,
356
+ the resume brief on the next new session. The `0.6.0` ledger / defaults / JIT
357
+ behaviour is unchanged.
341
358
 
342
359
  The published `0.4.0` declared `>=0.1.2-alpha.2 <0.2.0-0` — which the semver
343
360
  gate **rejects on every DSH `0.2.0-0` prerelease** (`<0.2.0-0` excludes
@@ -358,7 +375,7 @@ feature-detected legacy fallback).
358
375
  `0.1.2-alpha.2` is the minimum version for this API family: host settings are
359
376
  **feature-detected** — on DSH `≤0.1.5` they register the `dsh-engram`
360
377
  namespace via `settings.installSection`; on `≥0.1.7` / `0.2.x` the form is the
361
- plugin's `Config` with the 27 GUI knobs marked `.volatile()` (entry id
378
+ plugin's `Config` with the 34 GUI knobs marked `.volatile()` (entry id
362
379
  `engram`). The browser settings card reads and writes through the plugin's own
363
380
  HTTP route (`/api/dsh-engram/settings`, see Route B above) on both. The full
364
381
  regression suite (npm test 329/329, incl. the new settings-v2 coverage for the
@@ -623,10 +640,12 @@ Triggers follow DSH's own compaction timing (step pressure / context-overflow /
623
640
  `/compact`); the lock, replay validation, tool-call/result pairing and token
624
641
  pricing are all reused from the basic engine. Any error falls back to the
625
642
  default compressor — compaction is never broken; with `gcReplacesCompaction:
626
- false` (or a host without `dsh-compaction-basic`) a bare `BasicCompactionEngine`
627
- is mounted instead, so the `compaction` service never disappears while
628
- dsh-engram is installed. Mounting registers the `compaction` service on the
629
- plugin's fiber, so unloading/reloading engram restores the default engine.
643
+ false` (the default since v0.6, or a host without `dsh-compaction-basic`) a bare
644
+ `BasicCompactionEngine` is mounted instead, so the `compaction` service never
645
+ disappears while dsh-engram is installed. Mounting registers the `compaction`
646
+ service on the plugin's fiber, so unloading/reloading engram restores the
647
+ default engine. **Taking over compaction is opt-in**: turn on
648
+ `gcReplacesCompaction` (and `autoWebCompaction` for web presets).
630
649
 
631
650
  > **Shrink gate**: the harness refuses any checkpoint that is not strictly
632
651
  > smaller than the evicted span (`summary is not smaller than the shadowed
@@ -641,19 +660,19 @@ plugin's fiber, so unloading/reloading engram restores the default engine.
641
660
 
642
661
  #### Where it is enabled (the entry point)
643
662
 
644
- Assembly happens on **two planes** — and web is now fully automatic, zero config:
663
+ Assembly happens on **two planes**, but both switches are opt-in (no takeover by
664
+ default):
645
665
 
646
- - **Host plane (headless / TUI / base profiles) — on by default, zero config**:
666
+ - **Host plane (headless / TUI / base profiles)**:
647
667
  the main plugin (`lib/index.js`) mounts the engine inside `ctx.effect` via
648
668
  `mountCompactionEngine(ctx, resolved, { readWorkspace }) → new Engine()`,
649
669
  registering the `compaction` service on its own fiber; the plugin patch
650
670
  disables the base `compaction-basic` row, making engram the sole host-plane
651
- provider. `gcReplacesCompaction: true` (default) → `ContextGcEngine`;
652
- `false` → a bare `BasicCompactionEngine`. Tune via profile patch
653
- (`config: { gcReplacesCompaction: false }`) or the settings card's
654
- `gcNarrative` knob (narrative off = fully mechanical).
655
- - **Preset plane (web profile) — fully automatic, zero config, covers every
656
- preset**: web keeps compaction inside each agent preset's isolated realm
671
+ provider. `gcReplacesCompaction: false` (default) → a bare
672
+ `BasicCompactionEngine` (DSH's own summarizer); `true` → `ContextGcEngine`
673
+ (pointer summaries). Enable via profile patch
674
+ (`config: { gcReplacesCompaction: true }`) or the settings card.
675
+ - **Preset plane (web profile) — covers every stock preset once enabled**: web keeps compaction inside each agent preset's isolated realm
657
676
  (the shipped presets mount their own `compaction-basic`), unreachable from a
658
677
  host-plane row — and unreachable from a profile patch too (`mountPreset`
659
678
  builds its `Include.Config` with no patches; verified against the harness
@@ -663,8 +682,9 @@ Assembly happens on **two planes** — and web is now fully automatic, zero conf
663
682
  root: `standard`, `code`, `cordis`, and your own presets): it swaps the
664
683
  `compaction-basic` row inside the `compaction` group for
665
684
  `dsh-engram/compaction`. That auto-wiring is:
666
- - **on by default** (`autoWebCompaction: true`, toggle in the settings card's
667
- memory-GC section), idempotent — an already-wired preset is left alone;
685
+ - **off by default (opt-in)** (`autoWebCompaction: false`, toggle in the
686
+ settings card's memory-GC section); once enabled it is idempotent — an
687
+ already-wired preset is left alone;
668
688
  **what "off" means**: the plugin stops auto-wiring on later boots (the
669
689
  headless/TUI/base host plane is unaffected) — it does NOT un-wire presets
670
690
  that were already wired; use `npm run web-compaction:revert` for that;
@@ -719,9 +739,10 @@ Assembly happens on **two planes** — and web is now fully automatic, zero conf
719
739
 
720
740
  #### First impressions after an npm install (perceive / guide / configure)
721
741
 
722
- - **Automatic**: install into a profile and boot once — the host plane is taken
723
- over by `mountCompactionEngine`, and the web plane by `autoWebCompaction`
724
- (default on) rewriting every stock preset at boot. **Zero manual setup.**
742
+ - **Semi-automatic (opt-in)**: DSH's own summarizer stays the default. Turn on
743
+ `gcReplacesCompaction` (host plane) and `autoWebCompaction` (web presets) in
744
+ the settings card, then boot once — `mountCompactionEngine` takes over and
745
+ the stock presets are rewritten. **No file editing after that.**
725
746
  - **Perceivable**: at boot the plugin writes an authoritative snapshot to
726
747
  `$DSH_HOME/engram/context-gc.status.json` (`host` plane mode + the per-preset
727
748
  `web` results + effective config). At any time run `npx dsh-engram status` or
@@ -730,8 +751,9 @@ Assembly happens on **two planes** — and web is now fully automatic, zero conf
730
751
  log lines confirm it too: `engram context-gc: compaction = Context GC …` and
731
752
  `engram web-provision: wired Context GC into preset …`.
732
753
  - **Configurable**: one settings card (memory-GC section) governs everything:
733
- `autoWebCompaction` (web auto-wiring on/off), `gcReplacesCompaction`
734
- (Context GC vs default summarizer), `gcNarrative` (narrative safety net).
754
+ `autoWebCompaction` (web auto-wiring, default off), `gcReplacesCompaction`
755
+ (Context GC vs host summarizer, default off), `gcNarrative` (narrative
756
+ safety net).
735
757
  Changes take effect after restarting `dsh web`, and the web rows are
736
758
  refreshed to match automatically.
737
759
 
@@ -748,7 +770,7 @@ means that preset was customized (or has no compaction group) and was left untou
748
770
  `dsh-compaction-basic unavailable` means the backend is missing and everything
749
771
  falls back to the default compressor.
750
772
 
751
- ### BoundaryPrune (subtask-boundary pruning, default OFF)
773
+ ### BoundaryPrune (subtask-boundary pruning, default ON + ledger veto)
752
774
 
753
775
  Context GC owns *what a compaction summary says*; BoundaryPrune owns *when a
754
776
  deterministic prune fires*: at todo-completion progress and goal terminal
@@ -783,10 +805,13 @@ later request. The two switches are independent.
783
805
  T2048+small-edges lands 2.4× the first-prune savings of the host default on
784
806
  the real corpus (10.14M vs 4.23M chars). Lowering the threshold is safe with
785
807
  `resultPack` on, which archives the removed middles.
786
- - Default **off**: `boundaryPrune: false`. When on, the log shows
808
+ - Default **on**: `boundaryPrune: true` (`false` is the opt-out). Adaptive gate
809
+ `boundaryPruneAdaptive: true` lets the Context Ledger stop further fires once
810
+ this workspace's own accounting is net negative (≥3 fires) — evidence can only
811
+ turn pruning off. The log shows
787
812
  `engram boundary-prune (todo @N reqs): pruned …`.
788
813
 
789
- ### ResultPack L2 (archive + `result_recall`, default OFF)
814
+ ### ResultPack L2 (archive + `result_recall`, default ON)
790
815
 
791
816
  BoundaryPrune makes pruning lossless: the removed middle of every pruned
792
817
  tool result is redacted (same rules as the memory write path) and archived to
@@ -824,6 +849,112 @@ Mechanisms must be provably activating, and dormant ones are off by default.
824
849
  the loop already measured from session logs (engram_recall queries → hits →
825
850
  engram_detail follows) so you can see injection→query→detail activation.
826
851
 
852
+ ### Context Ledger (net-savings accounting)
853
+
854
+ Turns "saves tokens" into a checkable number. Every model request is one ledger
855
+ tick: injected `[ENGRAM]`/`[RECALL]` and `[ESR]` blocks are charged per request
856
+ they survive; results removed by BoundaryPrune are credited per later request
857
+ they no longer replay; every prune pays one prefix-rewrite penalty
858
+ `(1 − ledgerCacheDiscount)` (the KV-cache break). `GET /api/dsh-engram/stats`
859
+ and `/overview` return `ledger`:
860
+
861
+ - `totals` — `requests / injectedChars / avoidedChars / rewriteCount /
862
+ rewriteChars / netChars / netTokens` with
863
+ `net = avoided − injected − rewriteChars × (1 − discount)`;
864
+ - `byWorkspace` / `byDay` — the same arithmetic per workspace and calendar day
865
+ (`byDay` newest first);
866
+ - `openSessions` — sessions still accumulating in memory (a restart loses at
867
+ most `flushEvery` requests).
868
+
869
+ The Telemetry tab renders it directly (net-token headline, saved / injected /
870
+ rewrite-penalty cards, a 14-day red/green net chart), and the memory overview
871
+ adds a "net context tokens" stat card. Durable rollup at
872
+ `~/.dsh/engram/ledger.json` (atomic write, daily buckets, delta flush); the hot
873
+ path is an integer add, zero I/O and zero model calls.
874
+ Defaults: `ledgerEnabled: true`, `ledgerCacheDiscount: 0.1`; off = no listeners,
875
+ no writes. **Honest scope**: tokens are `chars / 4` estimates, not provider
876
+ billing, and no quality delta is claimed; Context GC compaction savings are not
877
+ wired yet (the host does not expose before/after sizes), so the ledger only
878
+ counts what it can prove.
879
+
880
+ ### JIT push (v0.6-C)
881
+
882
+ Pull-only recall measured dormant (24 `engram_recall` / 8 `engram_detail` across
883
+ 112 real sessions), so v0.6 pushes on three deterministic events instead. One
884
+ line per event, at most 3 lines per session (`jitMaxLines`, `jitMaxLineChars`=220),
885
+ and silence when there is nothing relevant to point at:
886
+
887
+ | Event | Trigger | What is pushed |
888
+ |---|---|---|
889
+ | Error recurrence | the same `cmd:` signature fails a second time and a prior error/procedure memory exists | that memory's id + a one-line excerpt + `engram_detail` |
890
+ | File focus | the same file is edited twice in a row and a filePath/dir-anchored memory exists | preference first, then fact/decision |
891
+ | Goal completion | goal complete/block while active ESR tasks remain | the first two open tasks + `esr_status` |
892
+
893
+ - **Append-only**: a pushed line is never edited or withdrawn, so the prefix
894
+ changes once per push. Each push charges a rewrite
895
+ (`estimatePrefixChars + line length`) in the Context Ledger
896
+ (`rewriteCount` / `rewriteChars`), visible on the telemetry page.
897
+ - **Silent without a hit** — no memory/task to point at, no line.
898
+ - **Zero LLM, pure rules**; `jitEnabled:false` disables it, and the empty
899
+ `[JIT]` section costs nothing.
900
+ - **Not yet**: the resume brief (next-day continuation) and an explicit
901
+ remaining-requests ROI gate — today the 3-line budget plus the ledger are the
902
+ guardrails.
903
+
904
+ ### Session episode + resume brief (v0.7-A/D)
905
+
906
+ - **episode** — at `session/disposed`, a zero-LLM digest of the event log: files
907
+ touched, commands run, failures that later recovered (`cmd×N→fixed`), written
908
+ commit subjects, and still-open todos. Written only when there is substance (a
909
+ bare `ls` session produces none); **never indexed**; the newest 20 per
910
+ workspace are kept and older ones archived.
911
+ - **resume brief** — at the first assembly of a new session, the newest episode
912
+ from the last 7 days is injected as a `[RESUME]` line (≤240 chars) plus an
913
+ `engram_detail <id>` pointer, frozen with `[ENGRAM]`/`[RECALL]`. No recent
914
+ episode → no line; returning to a project does not need a re-briefing.
915
+ - Settings: `episodeEnabled`, `resumeBriefEnabled` (both default on), plus
916
+ `episodeMaxPerWorkspace` / `resumeBriefMaxAgeDays` / `resumeBriefMaxChars`.
917
+
918
+ ### Entity pages + entity cards (v0.7-B)
919
+
920
+ `esr_node` grows from a dot on the graph into a readable **page**: current
921
+ truth, timeline, open loops, conflicts and relations for one thing
922
+ (package / repo / service / bug…).
923
+
924
+ - **Entity card (in the index, default on)** — `[ENGRAM]` renders ONE line for
925
+ each active entity (anchored memories or open tasks), at most 2:
926
+ `[ENT] dsh-engram · package · 3 mem · 1 open · truth: … #id · page: engram_detail(entity="dsh-engram")`
927
+ Those entities' flat memory lines are not repeated; other entities stay in a
928
+ single `nodes:` line.
929
+ - **Full page (on drill)** — `engram_detail(entity="<name|id>")` returns
930
+ `truth / timeline / open loops / conflicts / relations`, with memory ids and
931
+ evidence gaps. A name with anchored memories but no registered node still
932
+ gets a virtual page.
933
+ - Pure, deterministic: preference leads `truth`, superseded rows never enter
934
+ it, conflicts are de-duplicated by unordered pair (`#a vs #b`).
935
+ - Settings `entityCardsEnabled` (default on); `entityCardsMax` /
936
+ `entityCardChars` tunable.
937
+
938
+ ### Revalidatable anchors + layered TTL (v0.7-C)
939
+
940
+ "Treating the past as truth" is the strongest credibility critique against
941
+ memory plugins. v0.7 gives file-backed memories an **anchor**:
942
+
943
+ - on write, record `{path, mtimeMs, size, hash?}` (sha256 for files ≤256KB,
944
+ stat only for larger ones) in the memory row; relative paths resolve against
945
+ the workspace;
946
+ - at session start a bounded revalidation (≤40 rows) tags changed/missing
947
+ sources `stale`; the `[ENGRAM]` index and entity `truth` stop showing them,
948
+ but nothing is deleted — `engram_detail` still returns them and the entity
949
+ timeline marks `· stale`;
950
+ - **layered TTL**: `preference` / `procedure` permanent; `episode` 14 days;
951
+ `error` 60 days; everything else `expireDays` (180). Hard deletes still do not
952
+ exist — GC only archives.
953
+ - Settings: `anchorRevalidate` (default on), `episodeTtlDays`, `errorTtlDays`.
954
+ - **Not done**: the offline consolidation job (episode abstraction/merge) —
955
+ deterministic rules can only roll up, not abstract semantically; deferred
956
+ until v0.8 alongside playbooks, rather than shipping a lossy pseudo-merge.
957
+
827
958
  ## Auto-capture policy
828
959
 
829
960
  Capture is deterministic and offline — it only sees tool *results*, never the
@@ -908,12 +1039,13 @@ Defaults are token-conscious; override any key via the profile patch
908
1039
  autoCapture: true # zero-LLM tool-result capture
909
1040
  autoCapturePreferences: true # zero-LLM user-correction/preference capture (prefer/avoid/switch-to cues)
910
1041
  preferenceCapturePerSession: 8 # per-session preference memory cap
911
- boundaryPrune: false # ResultPack L1: prune stale over-threshold tool results at todo/goal boundaries (default OFF)
1042
+ boundaryPrune: true # ResultPack L1: prune stale over-threshold tool results at todo/goal boundaries (default ON)
1043
+ boundaryPruneAdaptive: true # ledger veto: stop pruning this workspace once its net is negative (>=3 fires)
912
1044
  boundaryPruneThresholdChars: 0 # threshold override (0 = host 8192; e.g. 2048 prunes earlier)
913
1045
  boundaryPruneHeadChars: 0 # retained head under an override (0 = host 4096)
914
1046
  boundaryPruneTailChars: 0 # retained tail under an override (0 = host 1024)
915
1047
  boundaryPruneIdleCadence: 0 # request-count boundary for todo/goal-less sessions (0 = event-only)
916
- resultPack: false # ResultPack L2: archive pruned middles + result_recall paged recall (default OFF; needs L1 on)
1048
+ resultPack: true # ResultPack L2: archive pruned middles + result_recall paged recall (default ON; needs L1 on)
917
1049
  resultPackRetentionDays: 7 # archive retention days (mtime sweep on the GC cadence)
918
1050
  sessionSearch: true # engram_recall may also FTS past sessions
919
1051
  recallScope: workspace # recall scope: "workspace" (strict isolation, default) | "global" (opt-in cross-workspace recall with [W:<ws>] origin markers)
@@ -932,8 +1064,17 @@ Defaults are token-conscious; override any key via the profile patch
932
1064
  gcEnabled: true # scheduled memory GC
933
1065
  gcIntervalHours: 24 # sweep cadence
934
1066
  gcStableRetentionDays: 120 # stable tasks leave [ESR] after this
935
- gcReplacesCompaction: true # Context GC: take over DSH auto-compact (false = keep the default LLM summarizer)
1067
+ gcReplacesCompaction: false # Context GC: take over DSH auto-compact (default off = host summarizer; true = opt-in pointers)
936
1068
  gcNarrative: true # scoped LLM narrative for un-provenanced turns; false = fully mechanical (zero LLM)
1069
+ autoWebCompaction: false # rewrite stock web presets (default off; explicit opt-in, revert with the CLI)
1070
+ jitEnabled: true # JIT push: error recurrence / file focus / goal completion → one memory line
1071
+ episodeEnabled: true # session episode: zero-LLM digest at teardown (never indexed)
1072
+ resumeBriefEnabled: true # resume brief: newest episode from the last 7 days at session start
1073
+ entityCardsEnabled: true # entity card: one truth/tasks/drill line per active entity in the index
1074
+ anchorRevalidate: true # re-stat filePath anchors at session start (changed/missing → stale)
1075
+ episodeTtlDays: 14 # episode TTL (preference/procedure permanent; error 60d; others expireDays)
1076
+ ledgerEnabled: true # Context Ledger: injected cost / prune savings / rewrite penalty → net tokens
1077
+ ledgerCacheDiscount: 0.1 # cached-prefix price share; rewrites pay (1−discount)
937
1078
  engramIndexOrder: 40 # systemPrompt section order (before tools band)
938
1079
  esrOrder: 41
939
1080
  ```
@@ -941,7 +1082,7 @@ Defaults are token-conscious; override any key via the profile patch
941
1082
  ## Development
942
1083
 
943
1084
  ```sh
944
- npm test # 291 tests: core + web API + GC + usage-observability + Context GC + ESR triggers + BoundaryPrune + preference learning (node:test)
1085
+ npm test # 381 tests: core + web API + GC + usage-observability + Context GC + ESR triggers + BoundaryPrune + preference learning + Context Ledger + JIT push (node:test)
945
1086
  npm run eval # offline recall + structure benchmark (deterministic)
946
1087
  npm run build:client
947
1088
  ```