@theseus-whale/dsh-continuity 0.0.0-stage → 4.12.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 (258) hide show
  1. package/INSTALL.md +25 -0
  2. package/PANEL.md +92 -0
  3. package/README.md +286 -2
  4. package/RELEASE-NOTES.md +732 -0
  5. package/bin/bc-acceptance-full.mjs +91 -0
  6. package/bin/bc-acceptance-tight.mjs +66 -0
  7. package/bin/bc-acceptance.mjs +22 -0
  8. package/bin/bc-add-keywords.mjs +21 -0
  9. package/bin/bc-demo.mjs +47 -0
  10. package/bin/bc-expand-hint.mjs +179 -0
  11. package/bin/bc-ingest-index.mjs +35 -0
  12. package/bin/bc-ingest.mjs +31 -0
  13. package/bin/bc-label-demo.mjs +18 -0
  14. package/bin/bc-relabel.mjs +150 -0
  15. package/bin/bc-sessionize.mjs +59 -0
  16. package/bin/coref_pipeline.py +47 -0
  17. package/bin/coref_service.py +57 -0
  18. package/bin/debug_ckip.py +16 -0
  19. package/bin/debug_ner_zh.py +18 -0
  20. package/bin/doctor.mjs +275 -0
  21. package/bin/en_ner_error_audit.py +33 -0
  22. package/bin/eval-label-rules.mjs +342 -0
  23. package/bin/export-turns.py +68 -0
  24. package/bin/extract-user-paragraph.mjs +14 -0
  25. package/bin/extraction-composite-smoke.mjs +28 -0
  26. package/bin/extraction-latency.mjs +58 -0
  27. package/bin/extraction-user-smoke.mjs +28 -0
  28. package/bin/extraction_service.py +164 -0
  29. package/bin/facet-active-experiment.mjs +110 -0
  30. package/bin/facet-covid.mjs +8 -0
  31. package/bin/facet-curve.mjs +27 -0
  32. package/bin/facet-embedding-train.mjs +20 -0
  33. package/bin/facet-embedding-validate.mjs +83 -0
  34. package/bin/facet-eval-roleplay.mjs +42 -0
  35. package/bin/facet-eval.mjs +38 -0
  36. package/bin/facet-fold.mjs +31 -0
  37. package/bin/facet-load.mjs +16 -0
  38. package/bin/facet-mlp-scan.mjs +45 -0
  39. package/bin/facet-mvp.mjs +34 -0
  40. package/bin/facet-online-experiments.mjs +78 -0
  41. package/bin/facet-online-race.mjs +99 -0
  42. package/bin/facet-online-validate.mjs +51 -0
  43. package/bin/facet-panel.mjs +22 -0
  44. package/bin/facet-passage.mjs +41 -0
  45. package/bin/facet-random-validate.mjs +48 -0
  46. package/bin/facet-roleplay.mjs +33 -0
  47. package/bin/facet-scan.mjs +56 -0
  48. package/bin/facet-segment.mjs +34 -0
  49. package/bin/facet-train.mjs +19 -0
  50. package/bin/facet-validate.mjs +103 -0
  51. package/bin/facet-zeroshot.mjs +14 -0
  52. package/bin/install-templates.mjs +72 -0
  53. package/bin/memory-bench.mjs +53 -0
  54. package/bin/memory-build-summary.mjs +43 -0
  55. package/bin/memory-build-vector.mjs +31 -0
  56. package/bin/memory-build.mjs +41 -0
  57. package/bin/memory-calibration.mjs +70 -0
  58. package/bin/memory-closed-loop.mjs +119 -0
  59. package/bin/memory-dry-run.mjs +70 -0
  60. package/bin/memory-eval.mjs +104 -0
  61. package/bin/memory-event-alias-test.mjs +89 -0
  62. package/bin/memory-extraction-bench.mjs +58 -0
  63. package/bin/memory-load-gate-replay.mjs +137 -0
  64. package/bin/memory-loop-test.mjs +90 -0
  65. package/bin/memory-pre-turn-harness.mjs +63 -0
  66. package/bin/memory-query.mjs +39 -0
  67. package/bin/memory-replay-hints.mjs +84 -0
  68. package/bin/memory-scale.mjs +58 -0
  69. package/bin/memory-scenario-test.mjs +146 -0
  70. package/bin/memory-user-loop.mjs +95 -0
  71. package/bin/ner_bench_tiny_zh.py +59 -0
  72. package/bin/ner_bench_zh.py +60 -0
  73. package/bin/ner_conll_en.py +139 -0
  74. package/bin/ner_direct_en.py +123 -0
  75. package/bin/ner_direct_zh.py +100 -0
  76. package/bin/ner_pipeline.py +208 -0
  77. package/bin/noise-selfcheck.mjs +50 -0
  78. package/bin/pack-integrity.mjs +47 -0
  79. package/bin/panel-check.mjs +57 -0
  80. package/bin/plugin-integrity.mjs +74 -0
  81. package/bin/preview-live.mjs +13 -0
  82. package/bin/public-install-check.mjs +222 -0
  83. package/bin/relabel-apply.mjs +272 -0
  84. package/bin/relabel-dry-run.mjs +381 -0
  85. package/bin/relik_pipeline.py +39 -0
  86. package/bin/relik_service.py +52 -0
  87. package/bin/srl_pipeline.py +55 -0
  88. package/bin/srl_service.py +68 -0
  89. package/bin/summary-index.mjs +151 -0
  90. package/bin/summary-query.mjs +79 -0
  91. package/bin/vec-check.mjs +27 -0
  92. package/bin/zh_ner_error_audit.py +36 -0
  93. package/bin/zh_ner_slot_eval.py +38 -0
  94. package/client.js +760 -0
  95. package/cordis.patch.yml +378 -0
  96. package/docs/API-NOTES.md +1743 -0
  97. package/docs/ARCHITECTURE.md +355 -0
  98. package/docs/CACHE.md +253 -0
  99. package/docs/CONDUCT.md +30 -0
  100. package/docs/CREATOR-HANDOFF.md +102 -0
  101. package/docs/EXPERIMENT.md +136 -0
  102. package/docs/FACET-MVP-REPORT.md +473 -0
  103. package/docs/GUIDE-0.4.66.md +195 -0
  104. package/docs/GUIDE.md +127 -0
  105. package/docs/MECHANISM.md +243 -0
  106. package/docs/NEW-INSTANCE-HANDOFF.md +219 -0
  107. package/docs/README.md +37 -0
  108. package/docs/SESSION-LAYOUT.md +151 -0
  109. package/docs/history-map.md +249 -0
  110. package/docs/relabel-migration-wiring.md +366 -0
  111. package/guides/00-READ-FIRST.md +206 -0
  112. package/guides/01-INSTALL.md +207 -0
  113. package/guides/02-TABLES.md +225 -0
  114. package/guides/03-AUDIT.md +201 -0
  115. package/guides/04-REBUILD.md +306 -0
  116. package/guides/05-FIRST-RUN.md +191 -0
  117. package/guides/06-EMBEDDING.md +146 -0
  118. package/guides/07-PTC-AND-ASSETS.md +221 -0
  119. package/icon.svg +7 -0
  120. package/locale/en.json +6 -0
  121. package/locale/zh.json +6 -0
  122. package/models/README.md +13 -0
  123. package/models/Xenova/bge-small-zh-v1.5/config.json +31 -0
  124. package/models/Xenova/bge-small-zh-v1.5/onnx/model_quantized.onnx +0 -0
  125. package/models/Xenova/bge-small-zh-v1.5/tokenizer.json +21278 -0
  126. package/models/Xenova/bge-small-zh-v1.5/tokenizer_config.json +15 -0
  127. package/package.json +139 -4
  128. package/src/asset-tool.mjs +237 -0
  129. package/src/assets.mjs +244 -0
  130. package/src/backfill.mjs +74 -0
  131. package/src/backup.mjs +80 -0
  132. package/src/deadend.mjs +95 -0
  133. package/src/deleted-store.mjs +35 -0
  134. package/src/engine.mjs +3831 -0
  135. package/src/facets/classifier.mjs +146 -0
  136. package/src/facets/embedding-service.mjs +53 -0
  137. package/src/facets/embedding-worker.mjs +27 -0
  138. package/src/facets/embedding.mjs +163 -0
  139. package/src/facets/extract.mjs +80 -0
  140. package/src/facets/fold-plan.mjs +84 -0
  141. package/src/facets/hybrid.mjs +29 -0
  142. package/src/facets/index.mjs +113 -0
  143. package/src/facets/linear-probe.mjs +43 -0
  144. package/src/facets/load.mjs +37 -0
  145. package/src/facets/mlp-probe.mjs +54 -0
  146. package/src/facets/mlp-service.mjs +53 -0
  147. package/src/facets/mlp-worker.mjs +26 -0
  148. package/src/facets/online-knn.mjs +58 -0
  149. package/src/facets/online-models.mjs +227 -0
  150. package/src/facets/panel-state.mjs +23 -0
  151. package/src/facets/panel.mjs +73 -0
  152. package/src/facets/random.mjs +26 -0
  153. package/src/facets/scanner.mjs +35 -0
  154. package/src/facets/schema.mjs +75 -0
  155. package/src/facets/seed-examples.mjs +58 -0
  156. package/src/facets/sensitivity.mjs +98 -0
  157. package/src/facets/service.mjs +53 -0
  158. package/src/facets/store.mjs +39 -0
  159. package/src/facets/worker.mjs +23 -0
  160. package/src/folds-store.mjs +109 -0
  161. package/src/groups.mjs +167 -0
  162. package/src/handoff-tool.mjs +51 -0
  163. package/src/handoff.mjs +127 -0
  164. package/src/index.mjs +649 -0
  165. package/src/inject-policy.mjs +17 -0
  166. package/src/learning.mjs +88 -0
  167. package/src/memory/alias-proposal.mjs +40 -0
  168. package/src/memory/bc-audit.mjs +245 -0
  169. package/src/memory/bc-index-updater.mjs +404 -0
  170. package/src/memory/bc-index.mjs +48 -0
  171. package/src/memory/bc-label.mjs +220 -0
  172. package/src/memory/bc-panel-state.mjs +107 -0
  173. package/src/memory/bc-pre-step.mjs +463 -0
  174. package/src/memory/bc-recall.mjs +470 -0
  175. package/src/memory/bc-shift.mjs +123 -0
  176. package/src/memory/bc-store.mjs +41 -0
  177. package/src/memory/bm25.mjs +112 -0
  178. package/src/memory/calibration.mjs +54 -0
  179. package/src/memory/chatter.mjs +29 -0
  180. package/src/memory/cmap-file.mjs +107 -0
  181. package/src/memory/concepts-file.mjs +41 -0
  182. package/src/memory/coref-slots.mjs +40 -0
  183. package/src/memory/event-alias-ledger.mjs +87 -0
  184. package/src/memory/event-log.mjs +95 -0
  185. package/src/memory/event-model.mjs +132 -0
  186. package/src/memory/event-segmenter.mjs +36 -0
  187. package/src/memory/event-summary-tree.mjs +122 -0
  188. package/src/memory/extraction-adapter.mjs +76 -0
  189. package/src/memory/extraction-composite.mjs +75 -0
  190. package/src/memory/extraction-core.mjs +76 -0
  191. package/src/memory/extraction-pre-step.mjs +161 -0
  192. package/src/memory/extraction-provider.mjs +300 -0
  193. package/src/memory/extraction-score.mjs +36 -0
  194. package/src/memory/facet-stabilizer.mjs +59 -0
  195. package/src/memory/history-map.mjs +139 -0
  196. package/src/memory/language-router.mjs +30 -0
  197. package/src/memory/load-gate.mjs +161 -0
  198. package/src/memory/mechanical-note.mjs +104 -0
  199. package/src/memory/onboarding.mjs +163 -0
  200. package/src/memory/persona.mjs +78 -0
  201. package/src/memory/planner.mjs +249 -0
  202. package/src/memory/pre-turn.mjs +80 -0
  203. package/src/memory/query-aliases.mjs +39 -0
  204. package/src/memory/recall-cue.mjs +43 -0
  205. package/src/memory/recall.mjs +65 -0
  206. package/src/memory/referent-candidates.mjs +55 -0
  207. package/src/memory/referent-ledger.mjs +86 -0
  208. package/src/memory/relabel-migrate.mjs +376 -0
  209. package/src/memory/relik-adapter.mjs +25 -0
  210. package/src/memory/special-keywords.mjs +60 -0
  211. package/src/memory/structured-adapters.mjs +75 -0
  212. package/src/memory/summary-index.mjs +335 -0
  213. package/src/memory/summary-tree.mjs +110 -0
  214. package/src/memory/term-extractor.mjs +44 -0
  215. package/src/memory/tokenize.mjs +9 -0
  216. package/src/memory/vector-index.mjs +54 -0
  217. package/src/memory/window-summary.mjs +133 -0
  218. package/src/mood.mjs +133 -0
  219. package/src/peer-tool.mjs +63 -0
  220. package/src/peer.mjs +144 -0
  221. package/src/policy.mjs +170 -0
  222. package/src/preflight.mjs +113 -0
  223. package/src/provenance.mjs +94 -0
  224. package/src/range.mjs +75 -0
  225. package/src/recall-exact-tool.mjs +267 -0
  226. package/src/recall-tool.mjs +521 -0
  227. package/src/recheck.mjs +99 -0
  228. package/src/save-start.mjs +29 -0
  229. package/src/session-guard.mjs +140 -0
  230. package/src/session-log-tool.mjs +322 -0
  231. package/src/session-log.mjs +606 -0
  232. package/src/skills.mjs +111 -0
  233. package/src/split-range.mjs +115 -0
  234. package/src/state.mjs +198 -0
  235. package/src/t0.mjs +149 -0
  236. package/src/tag-confirm.mjs +78 -0
  237. package/src/tag-detect.mjs +42 -0
  238. package/src/tag-maintenance.mjs +285 -0
  239. package/src/tag-reject.mjs +73 -0
  240. package/src/tags-store.mjs +94 -0
  241. package/src/tags.mjs +692 -0
  242. package/src/threads-backend.mjs +26 -0
  243. package/src/threads-core.mjs +1887 -0
  244. package/src/threads-store.mjs +207 -0
  245. package/src/threads-tool.mjs +522 -0
  246. package/src/threads.mjs +929 -0
  247. package/src/tool-preview.mjs +427 -0
  248. package/src/topic.mjs +63 -0
  249. package/src/training.mjs +75 -0
  250. package/src/turn-tag.mjs +62 -0
  251. package/src/user-turn.mjs +39 -0
  252. package/templates/cmap.md +11 -0
  253. package/templates/concepts.md +12 -0
  254. package/templates/habits.md +40 -0
  255. package/templates/keywords.md +6 -0
  256. package/templates/rebuild.md +134 -0
  257. package/templates/rules-safe.md +184 -0
  258. package/templates/rules.md +177 -0
@@ -0,0 +1,102 @@
1
+ # Handoff to the Creator-mode instance
2
+
3
+ > **Historical.** This was the handoff that started the compaction work. Current operating
4
+ > contract is `docs/NEW-INSTANCE-HANDOFF.md`; current mechanism is `docs/ARCHITECTURE.md`.
5
+
6
+ You are picking this up because the standard-mode session that wrote it could not inspect or
7
+ replace `ctx.compaction`. That session's context ends here; this file is the record. You are not
8
+ obliged to continue it — but if you do, these are the exact gaps.
9
+
10
+ ## What is already decided
11
+
12
+ - Goal: replace the threshold-and-cliff compaction with a **band controller**: keep a verbatim
13
+ recent window, remove a small oldest slice per pass, never fold into the protected tail.
14
+ - The pure policy is implemented and tested in `src/policy.mjs` (9 tests). Do not redesign it
15
+ before running the tests.
16
+ - The adapter must **extend** `BasicCompactionEngine`, not reimplement the transaction.
17
+ - **One engine per context.** The existing `compaction-basic` entry must be replaced, not
18
+ accompanied by a second engine.
19
+ - First experiment should be **config-only** (see `docs/API-NOTES.md` "Config-only quick win"):
20
+ override `thresholdRatio: 0.92`, `retainRatio: 0.5` on the existing entry. If that already
21
+ gives the desired feel, the custom engine may not be worth its cost.
22
+
23
+ ## What you need to inspect (in this order)
24
+
25
+ 1. `cordis_inspect_list` — enumerate providers.
26
+ 2. `cordis_inspect_query` on the `Config` provider — find the loader entry whose name is
27
+ `@deepseek-ai/dsh-compaction-basic`. Record:
28
+ - its loader id and tree id (the id a patch must target),
29
+ - its current `config` (thresholdRatio / retainRatio / headroomTokens),
30
+ - whether any modelPolicies already exist.
31
+ 3. `cordis_inspect_query` on the token-meter provider — record the exact method names/signatures
32
+ for "used tokens" and "window tokens" for a routed request.
33
+ 4. `cordis_inspect_query` on the session provider — record how to enumerate surface nodes
34
+ (`seq`, node kind, role), and how to get the first/last node for a range.
35
+ 5. Check the exports of `@deepseek-ai/dsh-compaction` actually present in the runtime:
36
+ `toolPairingBalancedBefore` / `toolPairingBalancedAfter`.
37
+
38
+ Write the answers into `docs/API-NOTES.md` under a new "Measured at runtime" section. Do not rely
39
+ on the npm types alone; the app may be a newer `0.2.x`.
40
+
41
+ ## Provenance is part of the policy
42
+
43
+ `src/provenance.mjs` is already written and tested. Wire it in **before** removing the checkpoint
44
+ preamble:
45
+
46
+ 1. In `compactIfNeeded`, after selecting `{ start, end, count }`, set
47
+ `this.pendingHeader = gistHeader({ sessionId, startSeq, endSeq, count })`.
48
+ 2. Override `summarize()`: call `super.summarize(...)`, then
49
+ `annotateSummary(base.summary, header)` (confirm the field name).
50
+ 3. Add `SYSTEM_CONVENTION` as **one** system-prompt section. It must not be inside the compacted
51
+ range, or it will be folded away.
52
+ 4. Leave the fixed checkpoint preamble in place for the first version. Removing it means writing
53
+ the replacement transaction yourself — do that only after the gist labels and the standing
54
+ convention are verified.
55
+
56
+ The target model experience is not "a checkpoint happened"; it is:
57
+
58
+ > I have the gist of that stretch. Exact details: `log:…#seq=…`. If the original is gone, say I
59
+ > only remember the gist.
60
+
61
+ ## Then fill `src/engine.mjs`
62
+
63
+ Only two methods are missing:
64
+
65
+ - `measure(agent)` → `{ estTokens, windowTokens }`.
66
+ - `oldestRange(agent, budget)` → `{ start, end }` or `null`.
67
+
68
+ Rules for `oldestRange`:
69
+
70
+ - never start at surface position 0 if it is the system message;
71
+ - inclusive span, both edges balanced (`toolPairingBalancedBefore` / `After`);
72
+ - stop before the protected tail;
73
+ - if no balanced range fits `budget`, return `null` (the caller falls back to the base backend).
74
+
75
+ Keep `compactIfNeeded`'s overflow branch delegating to `super.compactIfNeeded(...)`.
76
+
77
+ ## Acceptance
78
+
79
+ 1. `node test/policy.test.mjs` — 9/9.
80
+ 2. Scratch profile loads the plugin inert (`enabled: false`) and logs once.
81
+ 3. Enable it; run a disposable conversation long enough to cross 65%.
82
+ 4. Observe: passes are small (≤ `maxPerBatch`), recent messages stay verbatim, `/compact` still
83
+ works, overflow still recovers.
84
+ 5. Ask about a detail that exists only in a compacted range. Expected: it cites the `[gist]`
85
+ header / pointer and says it only has the gist (or retrieves), not a confident fabrication.
86
+ 6. Compare against `../sim/results.json`: event count per 100 turns, median drop, p90 drop.
87
+ 7. Keep the previous entry id and config in the handoff so rollback is one line.
88
+
89
+ ## Do not
90
+
91
+ - Do not insert a second `compaction-basic` row.
92
+ - Do not patch the desktop profile first.
93
+ - Do not claim "continuous self"; the seam is policy, not personhood.
94
+ - Do not delete the raw/archived transcript before verifying the summary and the new ranges.
95
+
96
+ ## Files
97
+
98
+ - `src/policy.mjs` — pure controller; do not change without updating tests.
99
+ - `src/engine.mjs` — the two TODOs.
100
+ - `docs/API-NOTES.md` — contract, config-only quick win, constraints.
101
+ - `../sim/` — the simulator and its numbers.
102
+ - `../README.md` — the Coopanion-side patch this mirrors.
@@ -0,0 +1,136 @@
1
+ # Config-only experiment — `thresholdRatio 0.92` / `retainRatio 0.5`
2
+
3
+ > **Historical.** The experiment is preserved for the record. Current band policy and reachable
4
+ > floor are in `docs/ARCHITECTURE.md` and `src/policy.mjs`.
5
+
6
+ This is the first experiment from `CREATOR-HANDOFF.md` (“Config-only quick win”): change the
7
+ shipped compaction backend's policy without changing engine code, and see whether a 50% verbatim
8
+ tail and a 92% cap already feel like the band.
9
+
10
+ ## Where it lives
11
+
12
+ A patch **cannot** target the live engine on this profile. The effective `compaction-basic` is a
13
+ child of the `standard` preset:
14
+
15
+ ```
16
+ include:preset-standard
17
+ └─ group "compaction" isolate: { compaction: true, toolResultPruner: true }
18
+ └─ child "compaction-basic"
19
+ ```
20
+
21
+ `Config.listConfigs` addresses top-level rows only, and the nested id
22
+ `include:preset-standard:compaction:compaction-basic` is not a loader entry. Overriding
23
+ `preset-standard` would change the default backend for every new session, which the handoff
24
+ explicitly says not to do first.
25
+
26
+ So the experiment is shipped as a **copy of the standard preset** whose only difference is the
27
+ compaction child's `config`:
28
+
29
+ | Item | Value |
30
+ |---|---|
31
+ | Loader row id | `include:preset-band` |
32
+ | Declaration `config.id` | `band` |
33
+ | Display name | `Band (config-only)` |
34
+ | Order | 20 |
35
+ | Shipped `preset-standard` | untouched |
36
+ | Rollback | pick another preset, or remove the `dsh-continuity` bundle |
37
+
38
+ The exact override, inside the copied `compaction` group:
39
+
40
+ ```yaml
41
+ - id: compaction-basic
42
+ name: '@deepseek-ai/dsh-compaction-basic'
43
+ config:
44
+ thresholdRatio: 0.92
45
+ retainRatio: 0.5
46
+ # headroomTokens omitted: the shipped default 65536 applies and the
47
+ # resolved threshold is min(W × 0.92, W − O − 65536).
48
+ ```
49
+
50
+ Nothing else in the 22-plugin preset list changes. `command-compact` and `tool-result-pruner` stay.
51
+
52
+ ## Resolved numbers (live model route)
53
+
54
+ `cordis_inspect_query` / `ctx.llm.resolveModelInfo('deepseek-official', 'deepseek-flash')`:
55
+
56
+ | Input | Value |
57
+ |---|---|
58
+ | `contextWindow` | 1,048,576 |
59
+ | reserved completion tokens (header `maxTokens`) | 256,000 |
60
+ | `messageBudget = W − O` | 792,576 |
61
+ | `headroomTokens` | 65,536 |
62
+
63
+ Reported by the panel's projection and computed with the base backend's own formulas:
64
+
65
+ | Config | `thresholdTokens` | `retainTokens` | one pass at the threshold |
66
+ |---|---|---|---|
67
+ | shipped `0.8 / 0.16` | 727,040 | 126,812 | 600,228 |
68
+ | **experiment `0.92 / 0.5`** | **727,040** | **396,288** | **330,752** |
69
+ | band engine (reference) | triggers at 515,174 | protects 221,921 | small slices, ≤ 8,000 |
70
+
71
+ The 92% ratio is not the binding cap: `0.92 × 1,048,576 = 964,690`, but
72
+ `1,048,576 − 256,000 − 65,536 = 727,040`. The experiment halves the retained tail (126,812 →
73
+ 396,288) but keeps the same trigger point, so each cut is still one large cliff (~331k tokens).
74
+
75
+ ## Why that still matters
76
+
77
+ Seven real summary compactions found in the local session logs (read-only scan; see
78
+ `docs/API-NOTES.md` §6) shadowed:
79
+
80
+ | session | shadowed tokens | shadowed surface nodes | summary maxTokens |
81
+ |---|---:|---:|---:|
82
+ | `session-2f831fa2…` | 363,912 | 1,259 | 65,536 |
83
+ | `session-2f831fa2…` | 354,500 | 1,166 | 65,536 |
84
+ | `session-2f831fa2…` | 342,756 | 1,000 | 65,536 |
85
+ | `session-4185b80f…` | 425,772 | 804 | 8,192 |
86
+ | `session-f1ac062b…` | 442,443 | 587 | 65,536 |
87
+
88
+ Full record for the first one:
89
+
90
+ ```
91
+ compactionId b57ba840-1892-4175-b652-06c7e30b8609
92
+ start seq 8255
93
+ summary seq 8257 shadowedRange 4424–7043 363,912 tokens
94
+ replace seq 8258 surfaceOp replace 4424–7043
95
+ end seq 8259
96
+ ```
97
+
98
+ The experiment changes *how much recent history survives* the cliff; it does not remove the cliff.
99
+ If the 50% tail already feels right, the custom engine is not worth its cost. If the single 331k
100
+ drop is still too disruptive, the `continuity` preset is the next step.
101
+
102
+ ## How to run it
103
+
104
+ 1. Start a **new** session (existing sessions keep the preset revision they started with).
105
+ 2. Pick the preset **`Band (config-only)`**. It appears beside `standard` in the preset control.
106
+ 3. Work normally until the session crosses the threshold. Automatic compaction happens at a step
107
+ boundary; the conversation shows the usual compaction row.
108
+ 4. To see the numbers rather than feel them, open the **Continuity** sidebar panel: the
109
+ “Config-only projection” card recomputes the table above from the live route and model.
110
+ 5. Compare a `Band` session's compaction row against a `standard` session's row (template below).
111
+
112
+ The panel's “Recent passes” list only observes the **continuity engine**, not the shipped backend;
113
+ a Band pass is visible in the session's compaction row and its log (`compaction/start`,
114
+ `compaction/summary`, replacement `user/message`, `compaction/end`).
115
+
116
+ ## Decision gate
117
+
118
+ - **Feels acceptable** → keep using `band`; the custom engine is optional. Rollback to `standard`
119
+ is one preset selection.
120
+ - **Still a cliff** → use `continuity`: same preset list, but `dsh-continuity/engine` replaces
121
+ `compaction-basic`, labels every pass with a gist pointer, and (since the cache-first update)
122
+ does one ~190k drain per high crossing instead of many small passes.
123
+ - **Something breaks** → remove the bundle (`plugin_manager` `remove_bundle`, target
124
+ `dsh-continuity`) and select `standard`. `preset-standard` and its compaction backend were never
125
+ modified, so no session needs repair.
126
+
127
+ ## Status
128
+
129
+ - 2026-10-26: `include:preset-band` registered and active on the desktop profile; the resolved
130
+ arithmetic is valid (`396,288 < 727,040`).
131
+ - No session has crossed the band threshold yet. The `compactionId` of the first Band pass will be
132
+ recorded here (or in `docs/API-NOTES.md`) once it happens.
133
+ - 2026-10-26 (later): the `continuity` engine's old policy produced 53 passes in
134
+ `session-0b094f6e…` (698,108 tokens total, 34 one-node passes) and repeatedly wiped the suffix
135
+ cache. `continuity` now uses `CACHE_FIRST_POLICY` (86/62, 190k per pass, 30% protected); see
136
+ `docs/CACHE.md`. The config-only `band` preset in this document is unchanged.
@@ -0,0 +1,473 @@
1
+ # Facet MVP 报告
2
+
3
+ ## 已完成
4
+
5
+ ```text
6
+ src/facets/schema.mjs 固定 6 槽 facet 词表 + alias 表
7
+ src/facets/extract.mjs 规则/词典回退提取器
8
+ src/facets/index.mjs 每 turn facet 索引、idf、alias 查询、seq 排序
9
+ src/facets/scanner.mjs 增量 seq 扫描器 + residual 队列
10
+ bin/facet-mvp.mjs CLI
11
+ test/facets.test.mjs 4 个测试
12
+ ```
13
+
14
+ ## 模块
15
+
16
+ ```text
17
+ buildFacetIndex(rows) rows -> entries + idf
18
+ queryFacets(index, alias) alias -> facet 集合 -> 排序 -> ranges
19
+ indexStats(index) 分布/unknown 统计
20
+ scanRows(rows, cursor) 从 cursor.lastSeq 往后扫,unknown 进 residual,不阻塞
21
+ ```
22
+
23
+ ## 第 100 轮真实快照测试
24
+
25
+ 数据:Continuity 1381–1480 的 100 个 turn;facet 由模型只读正文产生(不是规则提取器)。
26
+
27
+ ```text
28
+ 查询 跑团 → 54 matches
29
+ 查询 调试 → 19 matches
30
+ 查询 测试 → 20 matches
31
+ unknown → 0
32
+ ```
33
+
34
+ 跑团命中的 seq 段示例:
35
+
36
+ ```text
37
+ 56006–56051 (turn 1381–1386)
38
+ 56069–56141 (1389–1396)
39
+ 56159–56186 (1399–1401)
40
+ 56224–56305 (1408–1413)
41
+ ```
42
+
43
+ ## 测试
44
+
45
+ ```text
46
+ node test/facets.test.mjs 4 pass
47
+ npm test 全部通过
48
+ npm run check 通过
49
+ ```
50
+
51
+ ## 规则提取器 vs 模型 facet(同一批 100 turn)
52
+
53
+ 规则/词典提取器(`extract.mjs`):
54
+
55
+ ```text
56
+ unknown 41 / 100
57
+ activity 跑团 4 / 54
58
+ 查询“跑团” matches 0
59
+ ```
60
+
61
+ 模型 facet(只读正文,作为索引输入):
62
+
63
+ ```text
64
+ unknown 0 / 100
65
+ activity 跑团 54 / 54
66
+ 查询“跑团” matches 54
67
+ ```
68
+
69
+ 结论:**索引/查询层已经可用;提取层是瓶颈。**
70
+ 规则词典只能做 v0 fallback,真正可用必须接小模型/embedding 分类器。
71
+
72
+ ## ONNX/embedding 小模型
73
+
74
+ `src/facets/embedding.mjs`:
75
+
76
+ ```text
77
+ @huggingface/transformers
78
+ Xenova/bge-small-zh-v1.5
79
+ ONNX/WASM,本地缓存
80
+ hf-mirror 只用于首次下载
81
+ ```
82
+
83
+ 分层 holdout,train 52 / test 48:
84
+
85
+ ### embedding only
86
+
87
+ ```text
88
+ activity 91.4% coverage 72.9%
89
+ interaction 93.9% coverage 68.8%
90
+ participants 70.2% coverage 97.9%
91
+ medium 87.0% coverage 95.8%
92
+ topic 94.3% coverage 72.9%
93
+ ```
94
+
95
+ ### embedding + NB fallback
96
+
97
+ ```text
98
+ activity 83.3% coverage 100%
99
+ interaction 83.3% coverage 100%
100
+ participants 68.8% coverage 100%
101
+ medium 87.5% coverage 100%
102
+ topic 85.4% coverage 100%
103
+ ```
104
+
105
+ ### slot-aware fusion(embedding 只赢 4 个槽,participants 留给 NB)
106
+
107
+ ```text
108
+ activity 83.3% coverage 100%
109
+ interaction 83.3% coverage 100%
110
+ participants 83.3% coverage 100%
111
+ medium 87.5% coverage 100%
112
+ topic 85.4% coverage 100%
113
+ ```
114
+
115
+ 结论:embedding 在“敢答”时更准,但 coverage 低;按槽融合后 coverage 100%,participants 回到 83.3%。
116
+ 0.9.2 使用 slot-aware fusion。
117
+
118
+ ### embedding worker
119
+
120
+ ```text
121
+ src/facets/embedding-worker.mjs
122
+ src/facets/embedding-service.mjs
123
+ ```
124
+
125
+ worker 同时加载:
126
+
127
+ ```text
128
+ prototypes JSON
129
+ 可选 NB model JSON
130
+ ```
131
+
132
+ 返回 fused facets;模型推理不在主线程。
133
+
134
+ 验证文件:
135
+
136
+ ```text
137
+ last100/FACET-EMBEDDING-VALIDATION.json
138
+ ```
139
+
140
+ ## 敏感度曲线与折叠优先级
141
+
142
+ `src/facets/sensitivity.mjs`:
143
+
144
+ ```text
145
+ IDF 加权 cosine
146
+ coverage² 惩罚
147
+ 减去全语料 baseline
148
+ 3 窗 EMA(0.5/0.3/0.2)
149
+ ```
150
+
151
+ last100 查询“跑团”:
152
+
153
+ ```text
154
+ 跑团段平均 smoothed:0.275
155
+ 技术段平均 smoothed:0.0048
156
+ ≈ 57 倍分离
157
+ 最高:0.316(1381)
158
+ 最低:0(技术段)
159
+ ```
160
+
161
+ CLI:
162
+
163
+ ```powershell
164
+ node bin/facet-curve.mjs --input rows.jsonl --query 跑团 --out series.json
165
+ ```
166
+
167
+ 同一模块的 `foldPriority()` 用 `(1-score)×age` 排序,先折低相关老段,保护高相关当前话题。
168
+
169
+ 验证文件:
170
+
171
+ ```text
172
+ last100/FACET-CURVE.json
173
+ ```
174
+
175
+ ## 面板快照与 load 提示
176
+
177
+ `src/facets/panel.mjs`:
178
+
179
+ ```text
180
+ buildFacetPanel()
181
+ totalTurns / unknown / facetSum
182
+ 每槽计数
183
+ 当前 alias → facet pairs(含挂载 turn 数)
184
+ sensitivity curve
185
+
186
+ buildLoadHint()
187
+ 只在该话题最近窗口没有出现时返回一行 [回忆?]
188
+ ```
189
+
190
+ last100 面板:
191
+
192
+ ```text
193
+ 总 turn:100
194
+ facet 计数和:600(6 槽 × 100)
195
+ unknown:0
196
+ 当前话题:跑团
197
+ pairs:activity 跑团 54 / interaction 回合制 54 / random 有 0 /
198
+ participants 协作 89 / medium 文字 84 / topic 剧情 47
199
+ ```
200
+
201
+ `random 有 0` 是故意暴露的异常项:alias 声明了“随机”,但 last100 里没有机制词,
202
+ 用户可以据此指出 alias 不合理;面板不替用户掩盖。
203
+
204
+ 输出:
205
+
206
+ ```text
207
+ last100/FACET-PANEL.json
208
+ ```
209
+
210
+ ### 面板接线(0.9.x 预演)
211
+
212
+ ```text
213
+ host: /dsh-continuity/facets.json
214
+ file: ~/.dsh/continuity/facet-panel.json
215
+ client: 有 facet 快照时显示 facet 视图;没有时回退 T 列表
216
+ ```
217
+
218
+ 生成快照(显式 opt-in,不自动写 live):
219
+
220
+ ```powershell
221
+ node bin/facet-panel.mjs --input rows.jsonl --out $HOME\.dsh\continuity\facet-panel.json --alias 跑团
222
+ ```
223
+
224
+ 面板显示:
225
+
226
+ ```text
227
+ 当前话题 + alias-facet pairs
228
+ facet 总计数 / unknown
229
+ 敏感度曲线
230
+ 显示 T 列表(回退)
231
+ ```
232
+
233
+ ### facet load 查询
234
+
235
+ ```powershell
236
+ node bin/facet-load.mjs --index facet-index.json --query 跑团 --top 5
237
+ ```
238
+
239
+ 输出:
240
+
241
+ ```text
242
+ alias → facet 集合
243
+ ranges
244
+ seqs(可直接给 continuity.load 的 seqs)
245
+ ```
246
+
247
+ 这是“引导模型 load”的第一步:模型不再需要知道 T,只需要 query。
248
+
249
+ ### continuity.load({query})
250
+
251
+ `load` 新增可选 `query`:
252
+
253
+ ```text
254
+ continuity.load({ action: "load", query: "跑团" })
255
+ → facet-index.json → seqs → 正常 load
256
+ ```
257
+
258
+ 不要求模型知道 T;返回里带 `facetQuery` 的 ranges/seqs 数。
259
+ 没有 index/没有命中时返回 `facet-no-match`,不会静默切 T。
260
+
261
+ ## high 触发折叠计划
262
+
263
+ `src/facets/fold-plan.mjs`:
264
+
265
+ ```text
266
+ planFacetFold(entries, {query, idf, budgetTokens, recentTurns})
267
+ ```
268
+
269
+ 行为:
270
+
271
+ ```text
272
+ 最近窗口 → protected
273
+ 高 relevance 当前话题 → protected
274
+ 老的低 relevance → 按 (1-score)×age 排序
275
+ 按 token budget 取低相关 seq ranges
276
+ ```
277
+
278
+ 这是 high trigger 的候选计划;引擎已能在 `config.facetFold` 存在时,
279
+ 于 `band-high` / `emergency` 分支优先使用它,并检查:
280
+
281
+ ```text
282
+ active tool pin
283
+ tool pairing before/after
284
+ ```
285
+
286
+ 不满足时回退原来的 oldestRange。引擎默认读取:
287
+
288
+ ```text
289
+ ~/.dsh/continuity/facet-fold.json
290
+ ```
291
+
292
+ 存在时自动用于 `band-high` / `emergency`;不存在时行为不变。生成:
293
+
294
+ ```powershell
295
+ node bin/facet-fold.mjs --input rows.jsonl --out $HOME\.dsh\continuity\facet-fold.json --query 跑团
296
+ ```
297
+
298
+ ## facetNative(T 降为 alias 的过渡开关)
299
+
300
+ 引擎配置:
301
+
302
+ ```text
303
+ facetNative: true
304
+ ```
305
+
306
+ 行为:
307
+
308
+ ```text
309
+ 跳过 turn-stopping 的 TAG 补标催办
310
+ facet/load/query 仍可用
311
+ T 仍作为 save/load 的 alias 存在,但不再强制每轮打标
312
+ ```
313
+
314
+ 默认 `false`;显式开启才改变回合闸。
315
+
316
+ ## random facet 修复
317
+
318
+ `src/facets/random.mjs` 只认显式机制词:
319
+
320
+ ```text
321
+ 掷骰 / 骰子 / 骰 / D20 / 检定 / 抽卡
322
+ ```
323
+
324
+ 全历史 1474 turn 验证(正例标签由同一组机制词生成,因此这是规则校准,不是人工 gold):
325
+
326
+ ```text
327
+ positive:73
328
+ recall:1.00
329
+ falsePositive:0
330
+ precision:1.00
331
+ ```
332
+
333
+ 说明:last100 里这组机制词命中为 0,所以那 100 轮的 `random=无` 现在 **不是退化,而是输入里确实没有机制信号**。
334
+ 全历史里有 73 轮会被标成 `random=有`。
335
+
336
+ ## 本地 worker
337
+
338
+ ```text
339
+ src/facets/worker.mjs 加载 model JSON,消息循环
340
+ src/facets/service.mjs 主线程 client,超时/关闭
341
+ ```
342
+
343
+ 测试:
344
+
345
+ ```text
346
+ facet worker extracts off-thread from a serialized model ✔ 45ms
347
+ ```
348
+
349
+ 宿主主线程不再直接跑分类推理。
350
+
351
+ worker 端到端跑 last100(模型在全部 100 上训练,仅验证链路,不是泛化指标):
352
+
353
+ ```text
354
+ index entries:100
355
+ unknown:0
356
+ 查询“跑团”:52 matches
357
+ 真实跑团:54
358
+ true positive:52
359
+ precision:1.00
360
+ recall:0.963
361
+ ```
362
+
363
+ ## 闭环验证
364
+
365
+ `bin/facet-validate.mjs`:分层 holdout → 训练本地 NB → hybrid extract → 建索引 → alias 查询。
366
+
367
+ 最近 100 turn,train 52 / test 48:
368
+
369
+ ```text
370
+ activity 81.3%
371
+ interaction 81.3%
372
+ participants 83.3%
373
+ medium 85.4%
374
+ topic 83.3%
375
+ ```
376
+
377
+ 查询“跑团”:
378
+
379
+ ```text
380
+ test 中真实跑团 turn:27
381
+ 命中:26
382
+ precision:1.00
383
+ recall:0.963
384
+ ```
385
+
386
+ 唯一漏掉的是 27 个中的 1 个。
387
+ 输出在:
388
+
389
+ ```text
390
+ coopanion-continuity/backups/continuity-tags-20261031/last100/FACET-VALIDATION.json
391
+ ```
392
+
393
+ 结论:**raw text → 本地提取 → 索引 → alias 查询 → seq 范围,这条闭环成立。**
394
+
395
+ ## CLI 增量扫描验证
396
+
397
+ ```text
398
+ node bin/facet-scan.mjs --input rows-a.jsonl --dir facet-state --query 跑团
399
+ node bin/facet-scan.mjs --input rows-b.jsonl --dir facet-state --query 跑团
400
+ ```
401
+
402
+ 结果:
403
+
404
+ ```text
405
+ 第一次 scanned: 50
406
+ 第二次 scanned: 50
407
+ facet-index entries: 100
408
+ facet-cursor.lastSeq: 56460
409
+ residual: 0
410
+ 查询“跑团”: 54 matches(topK 以内)
411
+ ```
412
+
413
+ ## 本地 Naive Bayes 学生模型
414
+
415
+ `src/facets/classifier.mjs`:字符 bigram + 多项式朴素贝叶斯,无外部依赖。
416
+
417
+ ### 按时间切分(前 50 训练 / 后 50 测试)
418
+
419
+ ```text
420
+ activity accuracy 8% coverage 100%
421
+ interaction accuracy 8% coverage 100%
422
+ random accuracy 100% coverage 100%(全预测“无”)
423
+ participants accuracy 78% coverage 100%
424
+ medium accuracy 68% coverage 100%
425
+ topic accuracy 44% coverage 100%
426
+ ```
427
+
428
+ 这是**分布偏移**:前 50 轮几乎全是跑团,后 50 轮几乎全是技术工作。8% 不代表模型本身。
429
+
430
+ ### 分层切分(每个 activity 交替进 train/test)
431
+
432
+ ```text
433
+ train 52 / test 48
434
+ activity 81.3%
435
+ interaction 81.3%
436
+ random 100.0%(仍全是“无”)
437
+ participants 83.3%
438
+ medium 85.4%
439
+ topic 83.3%
440
+ ```
441
+
442
+ 结论:**同样的 Naive Bayes,在代表性训练集上可以到 81%**;
443
+ 真正的问题不是模型类型,而是**类别分布**和 `random` 特征退化。
444
+
445
+ ### 可持久化模型
446
+
447
+ ```text
448
+ node bin/facet-train.mjs --input rows.jsonl --out facet-model.json
449
+ node bin/facet-scan.mjs --input rows.jsonl --model facet-model.json --dir .facet --query 跑团
450
+ ```
451
+
452
+ 模型是普通 JSON;换 ONNX 时只替换 `classifierExtractor`,索引/查询不变。
453
+
454
+ ## 已知限制
455
+
456
+ 1. `extract.mjs` 只是词典回退,不是小模型;对“掷骰”等能命中,对隐含语义不行。
457
+ 2. 模型 facet 输出有质量问题:最近 100 轮 `random` 全是“无”,漏了掷骰。
458
+ 3. 没有接大模型 residual 命名,也没有接 ONNX 小模型。
459
+ 4. 没有写进 Continuity 的 load 工具;目前是独立模块/CLI。
460
+ 5. 查询没有做“所有 facet 必须同时命中”的严格 AND;当前按覆盖度 >= 0.6。
461
+
462
+ ## 下一步
463
+
464
+ ```text
465
+ 1. 用规则提取器跑 last100,比较它与模型 facet 的差异
466
+ 2. 把 facet-index 接入 continuity load 的 query 分支
467
+ 3. residual 聚类 + 大模型命名(离线命令)
468
+ 4. ONNX 小模型 worker
469
+ ```
470
+
471
+ ## 数据安全
472
+
473
+ 没有修改 `~/.dsh/continuity` 的任何文件;测试只读 last100 快照。