dsh-prime-memory 0.22.1 → 0.24.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/CHANGELOG.en.md +401 -0
- package/CHANGELOG.ja.md +401 -0
- package/CHANGELOG.ko.md +401 -0
- package/CHANGELOG.md +100 -0
- package/dist/client.js +1951 -1188
- package/dist/config.d.ts +176 -1240
- package/dist/config.js +113 -2
- package/dist/conflict-service.d.ts +12 -0
- package/dist/conflict-service.js +24 -0
- package/dist/contract.d.ts +327 -0
- package/dist/domain-gate.d.ts +19 -0
- package/dist/domain-gate.js +45 -0
- package/dist/graph/constraints.d.ts +4 -2
- package/dist/graph/constraints.js +4 -2
- package/dist/hooks/obsolete-notice.d.ts +26 -0
- package/dist/hooks/obsolete-notice.js +64 -0
- package/dist/hooks/recall.d.ts +41 -0
- package/dist/hooks/recall.js +127 -28
- package/dist/hooks/skill-recall.d.ts +25 -0
- package/dist/hooks/skill-recall.js +72 -0
- package/dist/index.d.ts +1 -1029
- package/dist/index.js +55 -2
- package/dist/memory-types.d.ts +69 -0
- package/dist/memory-types.js +165 -0
- package/dist/memport/format.d.ts +75 -0
- package/dist/memport/format.js +345 -0
- package/dist/memport/prefilter.d.ts +62 -0
- package/dist/memport/prefilter.js +132 -0
- package/dist/memport/scan.d.ts +13 -0
- package/dist/memport/scan.js +100 -0
- package/dist/metadata-validators.d.ts +22 -0
- package/dist/metadata-validators.js +45 -0
- package/dist/pipeline/l1.d.ts +44 -2
- package/dist/pipeline/l1.js +177 -9
- package/dist/pipeline/md-sync.d.ts +65 -0
- package/dist/pipeline/md-sync.js +456 -0
- package/dist/pipeline/ruminate.d.ts +46 -1
- package/dist/pipeline/ruminate.js +150 -1
- package/dist/pipeline/runner.d.ts +10 -0
- package/dist/pipeline/runner.js +7 -1
- package/dist/pipeline/slot-migrate.d.ts +45 -0
- package/dist/pipeline/slot-migrate.js +45 -0
- package/dist/pipeline/workspace-relink.d.ts +60 -0
- package/dist/pipeline/workspace-relink.js +73 -0
- package/dist/projection/recall.d.ts +112 -0
- package/dist/projection/recall.js +183 -0
- package/dist/projection/slots.d.ts +5 -0
- package/dist/prompts/examples.d.ts +73 -0
- package/dist/prompts/examples.js +178 -0
- package/dist/prompts/graph-projection.js +3 -0
- package/dist/prompts/l1-dedup.d.ts +9 -3
- package/dist/prompts/l1-dedup.js +34 -13
- package/dist/prompts/l1-extraction.d.ts +9 -4
- package/dist/prompts/l1-extraction.js +76 -8
- package/dist/settings.d.ts +8 -0
- package/dist/settings.js +15 -1
- package/dist/skills/crystallize.d.ts +41 -0
- package/dist/skills/crystallize.js +75 -0
- package/dist/stats.d.ts +30 -1
- package/dist/stats.js +504 -13
- package/dist/store/embedding-source.d.ts +8 -0
- package/dist/store/embedding-source.js +39 -2
- package/dist/store/file-versions.d.ts +4 -0
- package/dist/store/file-versions.js +4 -0
- package/dist/store/graph-store.d.ts +14 -0
- package/dist/store/graph-store.js +35 -0
- package/dist/store/l1-snapshot.d.ts +26 -1
- package/dist/store/l1-snapshot.js +53 -8
- package/dist/store/l1.d.ts +77 -3
- package/dist/store/l1.js +128 -3
- package/dist/store/memory-md-archive.d.ts +84 -0
- package/dist/store/memory-md-archive.js +155 -0
- package/dist/store/memory-md-disable.d.ts +23 -0
- package/dist/store/memory-md-disable.js +106 -0
- package/dist/store/memory-md-export.d.ts +50 -0
- package/dist/store/memory-md-export.js +200 -0
- package/dist/store/memory-md-ledger.d.ts +94 -0
- package/dist/store/memory-md-ledger.js +243 -0
- package/dist/store/memory-md-orphan.d.ts +27 -0
- package/dist/store/memory-md-orphan.js +153 -0
- package/dist/store/memory-md-parse.d.ts +35 -0
- package/dist/store/memory-md-parse.js +85 -0
- package/dist/store/memory-md-skeleton.d.ts +18 -0
- package/dist/store/memory-md-skeleton.js +61 -0
- package/dist/store/memory-md-types.d.ts +174 -0
- package/dist/store/memory-md-types.js +10 -0
- package/dist/store/memory-md.d.ts +108 -0
- package/dist/store/memory-md.js +219 -0
- package/dist/store/memory-sources.d.ts +59 -0
- package/dist/store/memory-sources.js +214 -0
- package/dist/store/obsolete-notices.d.ts +39 -0
- package/dist/store/obsolete-notices.js +153 -0
- package/dist/store/recall-feedback.d.ts +75 -0
- package/dist/store/recall-feedback.js +213 -0
- package/dist/store/recall-usage.d.ts +11 -0
- package/dist/store/recall-usage.js +29 -0
- package/dist/store/session-recalled.d.ts +60 -0
- package/dist/store/session-recalled.js +310 -0
- package/dist/store/skill-store.d.ts +99 -0
- package/dist/store/skill-store.js +330 -0
- package/dist/store/sqlite.d.ts +71 -0
- package/dist/store/sqlite.js +259 -15
- package/dist/store/supersede.d.ts +1 -1
- package/dist/store/supersede.js +1 -1
- package/dist/tools/index.d.ts +4 -13
- package/dist/tools/index.js +80 -12
- package/dist/tools/skills.d.ts +13 -0
- package/dist/tools/skills.js +130 -0
- package/dist/types.d.ts +30 -7
- package/dist/types.js +10 -2
- package/dist/util/maturity.d.ts +44 -0
- package/dist/util/maturity.js +43 -0
- package/dist/util/md-name.d.ts +129 -0
- package/dist/util/md-name.js +366 -0
- package/dist/util/md-normalize.d.ts +23 -0
- package/dist/util/md-normalize.js +131 -0
- package/dist/wing-backfill.js +7 -4
- package/dist/workspace-route.d.ts +22 -0
- package/dist/workspace-route.js +66 -0
- package/dsh.plugin.json +1 -1
- package/package.json +6 -5
package/CHANGELOG.en.md
CHANGED
|
@@ -7,6 +7,407 @@
|
|
|
7
7
|
|
|
8
8
|
This file covers the **0.12.0** release notes and the current **unreleased** changes in English. For the full history, see [CHANGELOG.md](./CHANGELOG.md) (Chinese).
|
|
9
9
|
|
|
10
|
+
## [0.24.0] — Unreleased (local line `0.24.0-local.0…3`, 2026-10-13)
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Single source of truth for the type vocabulary (`src/memory-types.ts`)**: the 29 original names of the host memory taxonomy + the plugin's legacy 7 types + the `unclassified` fallback, 37 types in total. The projection-directory whitelist, the `memory_add` write whitelist, the panel labels, the enum strings in the extraction and dedup prompts, and the type codes in memport's TS/Python dual implementations are **all derived from it**. Previously the "full set of types" was hand-copied in four places that each evolved on its own: `memory_add` **silently rewrote** external classifications into `episodic`, while the memport copy promised "passed through as-is" — two contradictory accounts of the same thing.
|
|
15
|
+
- **Name distillation (`cfg.naming`)**: extraction produces a `title` on the spot, **defined separately from** `content` (the title is the noun phrase answering "what is this entry about", the content is the full narrative body); the dedup merge also produces a `merged_title`. On write, `title` is only a **name candidate** and must pass the `validateTitle` shape gate — if it fails, the naming engine still handles it; the source of truth for name uniqueness does not split into two sets of criteria just because one more source appears.
|
|
16
|
+
- **few-shot standard-format example set (`src/prompts/examples.ts`)**: per-type positive and negative examples, with a cap on the total length budget (examples are a fixed cost paid on every distillation round); the positive examples themselves must pass the gate and carry a complete skeleton, and the test cases consume `auditFewShot()` directly instead of hand-copying the criteria.
|
|
17
|
+
- **Executable skeleton criteria (`SKELETON_ELEMENTS` + `scoreSkeleton`)**: turning "no cause-and-effect chain, an incomplete write does not count as usable" from a wish inside the prompt into a criterion that can be measured and used to set defaults. Declared limitation: a keyword heuristic, usable only for relative comparison between two arms on the same input — not an absolute quality score.
|
|
18
|
+
- **Directory skeleton + a per-type `_index.md` (`memory-md-skeleton.ts`)**: each type directory holds one index file (type name + entry count in the library). Empty directories get dropped by git and by archives, while "there is no such directory" and "this type has 0 entries" look identical to a human. Idempotent: unchanged content means zero writes and no mtime bump; zero action while the projection surface is off.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Three defaults flipped per A/B measurement** (`narrativeTemplates.enabled` / `naming.enabled` / `naming.fewShot`). The basis is two measurements in **opposite directions**: on the real-session distillation path, skeleton completeness is **0.000** (0/23) without examples and **0.703** (26/37) with them; while for the naming task of renaming existing entries, adding examples actually **−0.113** (18/160 missed answers). Conclusion: **examples must not cross tasks** — they only enter the extraction prompt, never the naming script.
|
|
23
|
+
- **md projection on by default** (`memExport.enabled`): the whole plan rests on "files are the authority on content + the database is the index"; defaulting it off means defaulting it unused. `mdSync.enabled` **still defaults off** — it writes to the database, and the risk is asymmetric.
|
|
24
|
+
- **The workspace-attribution config key renamed `workspaceHints` → `workspaceSource`**: a hard rename with no compatibility alias (the key has never shipped externally with any release; adding an alias means nurturing a second source of truth). On by default; the routing `path` now stores the **workspace root** (old values were written as `E:\test\rewrite-agently\.agents`, and `targetFor` appends `.agents/memory` again → producing a `.agents\.agents\memory\` orphan tree; the guardrail "fall back to a single root only when the root does not exist" cannot catch this shape). Backfill on a real machine gave **724/1166** existing records their attribution, with `hashRecords` byte-for-byte unchanged.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **The ledger loader overwrote absolute keys into `relPath`**: since N10 the ledger keys are absolute paths, and the "on mismatch, rewrite from the key" line fired on every single load, measurably contaminating **1167/1241** entries; downstream symptoms were orphan archiving assembling an illegal directory containing a colon, and 75 moves all failing with ENOENT. Now derived from `root` + key (new `deriveRelPath`); the archiving side no longer trusts the stored `relPath`.
|
|
29
|
+
- **`--revert` did not fall back to hooks**: `findArchivedOld` touched `deps.hooks.exists` directly, while `runCli` does not pass hooks when calling revert (the apply side has `deps.hooks ?? defaultHooks`, the revert side omitted it). The first rollback run in the sandbox errored out on all 74 entries. The point is the asymmetric harm: an apply failure is escaped via `--revert`, so **a broken rollback means the backup is the only way out**.
|
|
30
|
+
- **Cross-root duplicate files bypassed "if both sides changed, touch neither"**: `roots = the record's landing root ∪ the roots the ledger has recorded`, so one record can have one file under each of two roots; the decision used the old root's copy while the write went to the new root's copy computed by `targetFor` — a human edit in the old root overwrote the authoritative copy, and the report looked entirely compliant. Now only the current landing root is acknowledged; the rest are counted in the new field `staleRootFiles` and displayed on the panel.
|
|
31
|
+
- **A name collision pushed the whole memory out of the retrieval library**: the `{ ...old record, id: new id }` idiom wrote to the database carrying "a name already belonging to another row" → hit the partial unique index → the batch write fell back to per-row and still failed → that entry's merged product **silently vanished** (the old record had already retired, so this supersede left nothing behind). The naming criterion changed from "name is empty" to "**this name does not belong to it**".
|
|
32
|
+
- **The vector "N pending" counter never reached zero while "rebuild index" said there was nothing to do**: the display-side `missing = total − embedded` denominator included retired rows, while retired rows legitimately have no vectors by design; the two SQL statements driving the backfill both exclude retired rows, so "pending 114" and "nothing to do" appeared on the same screen. The denominator is now unified on active rows.
|
|
33
|
+
- **The projection guardrail was counting "traversal" instead of "action"**: `maxRecords` also charged entries judged "unchanged" against the quota, so the second click scanned the same first N — the panel's "click again to continue" was a lie (real-machine symptom: `已写 9 · 未变 291 · 剩余 866` stayed constant). Now only entries that touched disk are counted; total scan volume is bounded by `timeBudgetMs`.
|
|
34
|
+
- **O(n²) ledger flush**: `set()` serialized the whole ledger to JSON and atomically rewrote it once per entry. On 1200 entries on the same disk, measured **9442ms → 1954ms** (dirty flag + batch window + forced `flush()`).
|
|
35
|
+
- **`NAME_MAX`(40) and `NAME_CLIP_MAX`(28) split into two numbers**: the character counter priced ASCII and Han characters the same, so `dsh-agent-teams` / `Python-3.13` ate 15 units in a single word, and legitimate names of just one or two words were judged `too-long`; while setting both to 40 lets `deriveName` copy a narrative sentence into a sentence tail (observed in practice). Also removed the hard-coded 28 inside `validateTitle` (one threshold, two sources of truth).
|
|
36
|
+
- **Three false kills by the name gate**: the preamble-strip table and the name-reject table were **separated** (the bare subjects 「用户/团队」 no longer mistakenly kill noun phrases like 「用户npm账号用户名」, 10 real-machine entries); `has-id-fragment` narrowed to "4+ digits following a non-ASCII character" (`ADR-0006`, `Han-1413141` now pass, 4 real-machine entries).
|
|
37
|
+
|
|
38
|
+
### Known boundaries
|
|
39
|
+
|
|
40
|
+
- Incremental projection at the end of rumination relies on an `id→updatedAt` baseline diff, while relabel / retirement go through `patchMetadata` and do not touch `updated_time` ⇒ **a metadata-only rewrite is not re-projected in that round**.
|
|
41
|
+
- P2 reverse sync still owes two items: the startup automatic hook (changed to endpoint + button only) and the batch of `pending` entries not yet on the `conflicts` adjudication surface.
|
|
42
|
+
- **The 8-language translations have not been kept up since 0.20.0** (this pass only backfilled the entries from 0.22.0 onward; the 0.20/0.21 gap remains, noted separately).
|
|
43
|
+
|
|
44
|
+
## [0.23.0] — Unreleased (local line `0.23.0-local.1…8`, 2026-10-12…13)
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- **md authoritative projection surface (P0/P1/U/N10/N11)**: the `l1_records.name` column (file identity key + partial unique index); `renderRecord` + the dual-fingerprint ledger (`dbDigest`/`fileDigest`) + the `mem-export` / `mem-reconcile` endpoints; the panel's "external archive" section; the projection root switched to **workspace-first** (`<ws>/.agents/memory/<类型>/<名>.memory.md`); staleness judgment now also couples with `.memory.md.disable`.
|
|
49
|
+
- **P2 reverse sync (file → index)**: a **three-way quadrant** computed from the ledger's dual digest — only the file changed → backfill into the database and rewrite with the canonical render (breaking the write-back loop); only the database changed → reuse `exportRecords` to rewrite the file; **both changed → neither side is touched**, only `pending` is raised; `.disable` goes through retirement without deleting the file; unrecognized new files are only counted, never imported (import must pass through the write kernel). Endpoint `dsh-memory/mem-sync`.
|
|
50
|
+
- **P3 archive + physical delete**: the `exportThenPurge` gate moved from a whole-database hash to a **batch-level projection** (with concurrent distillation, as soon as any record unrelated to the batch is changed, the old implementation made cleanup never able to delete anything); after deletion a human-readable `retired.md` is written + the batch's projected files (including `.disable`) moved into a snapshot directory; `cleanup-retired` dry run returns a **preview of the to-delete list**; the graph projection index table gained `forgetRecords` (previously the whole repo only ever added and never removed — records restored from a snapshot were treated as "already projected" because the projection row was still there, so **they were never re-projected**, and the retrieval graph silently lacked one entry without raising an error).
|
|
51
|
+
- **P4.1 default class `unclassified` + P4.2 body layout standardization** (`normalizeContentMd`). Idempotence is a hard requirement: without it the ledger's `fileDigest` changes every round, and the write-back loop is introduced by the renderer itself. Layout only, no semantics (no bulletizing prose, no inserting an H1, no stuffing metadata into the body).
|
|
52
|
+
- **Orphan projection file archive `dsh-memory/mem-orphans`**: only moves files "the ledger records us as having written, and that no record currently claims this path for"; unrecognized files absent from the ledger are **left alone** (they may be input a human placed in the projection directory waiting to be synced back). Never deleted, only moved, preserving the relative shape and the original text.
|
|
53
|
+
|
|
54
|
+
### Behavior fixes (recall display surface)
|
|
55
|
+
|
|
56
|
+
- Recall entries no longer vanish instantly: the view carries `body` / `retired`, the removal of `session_recalled` rows stopped, and the pill shows a "judged stale" strikethrough annotation.
|
|
57
|
+
- Startup cleans up existing retirement residue (725 rows still dirty in `l1_fts` on this machine); the retirement invariant gained two bypass write paths (fixing "after marking invalid, it revives on the retrieval surface").
|
|
58
|
+
- Recall scoring end to end: `-1..5` (0..5 relevance; `-1` declares stale and retires), scores feed the maturity metric (`-1/1/2` pull down and sink, `4/5` push up and float).
|
|
59
|
+
- Workspace content routing landed for the first time (dsh ecosystem → `rewrite-agently`, non-dsh → `agent-no-dsh`; **only writes `workspace_id`, does not touch `scope`, does not touch `updated_time`**, and syncs the attribution columns carried by the `l1_fts` rows).
|
|
60
|
+
|
|
61
|
+
### Discipline
|
|
62
|
+
|
|
63
|
+
- Two giant memport functions split over two rounds (Extract Function, behavior preserved, CLI gold standard byte-for-byte regression).
|
|
64
|
+
- The endpoint-contract **five-places-changed-together** discipline stayed in force (`MEMORY_ENDPOINTS ≡ switch ≡ contract dual map ≡ contract-keys count ≡ config`), count chain 55→56→57→58→59.
|
|
65
|
+
|
|
66
|
+
## [0.22.2] — 2026-10-12
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- Skin tri-state (auto/light/dark) + token override block; the panel's 11 Tabs tightened onto a single row.
|
|
71
|
+
- `ext_key` idempotence for `memory_import` (`l1_records.ext_key` + partial unique index + `deduped` receipt).
|
|
72
|
+
- **Memport Connect**: `.mem` parsing / pre-filtering / scanning + source registry + Connect Tab (cross-implementation sha256 gold-standard alignment).
|
|
73
|
+
- **Skill crystallization**: skill-store (JSON sidecar) + candidate detection + skill recall injection + the board switch `skillsEnabled`.
|
|
74
|
+
- G4 graph causal edges (导致 / 因为 / 修复了 / 取代, without bumping `projectorVersion`).
|
|
75
|
+
- G3 maturity derived at read time (record-card badge + contradiction-adjudication view annotation, not part of automatic adjudication).
|
|
76
|
+
- G1 `usageScenario` gating end to end (extraction → landing in `metadata.dsh_usage_scenario` → recall fine ranking; off stays byte-for-byte unchanged).
|
|
77
|
+
- G2 per-type narrative templates (gated prompt variant; off is a prefix of on).
|
|
78
|
+
- wing / cognition hall two axes do not cross (orthogonal accessors + disjoint value-domain regression lock).
|
|
79
|
+
- **G-live live recall set of this session**: persistent sidecar + the `session-recalled` read-only endpoint + the pill read-only list.
|
|
80
|
+
- `memoryRecall` session-aware projection (the data source of the brief sidebar's "recalled this session" section, `init(header).id`).
|
|
81
|
+
- `cfg.slots.migrateLegacy` (off by default): softly retires rule slots that are "pinned as resident while their content is already carried by live L1".
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
|
|
85
|
+
- Rumination re-feed resetting or inflating the pending count (ruminate now passes empty messages, same semantics as `enqueueSessionSlices`).
|
|
86
|
+
- The rumination finalize and `doLightRefresh`'s L3 forced real run + count zeroing + `state.save()` flush (fixing "pending L2/L3 not cleared after rumination, bouncing back on restart").
|
|
87
|
+
|
|
88
|
+
### Discipline
|
|
89
|
+
|
|
90
|
+
- All new capabilities off by default; in the off state the artifacts and injections are byte-for-byte unchanged; the cross-plugin display contract (the `memorySlots` projection) stays wired.
|
|
91
|
+
|
|
92
|
+
## [0.22.1] — 2026-10-09
|
|
93
|
+
|
|
94
|
+
### Fixed
|
|
95
|
+
|
|
96
|
+
- **Popover underlay made opaque**: the memory popover in the input bar (`.dsh-mem-popover`) and the dropdown / filter panels (`.dsh-mem-pop`) previously followed the host's `--dsw-specific-menu`, which the host resolves to a translucent glass value ⇒ the panel let the background show through. Now an alias layer is stacked on an **opaque `bg-primary` underlay** (the underlay technique), so the panel is solid regardless of the host's alpha.
|
|
97
|
+
|
|
98
|
+
## [0.22.0] — 2026-10-09
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
|
|
102
|
+
- **Declaration surface adapted to 15rc**: 9 dsh peers covering all published host rcs (`0.1.0-rc.2..0.2.0-rc.2`, evidenced entry by entry via `npm view` and consistent across the line sets), all optional; `engines >= 0.1.0-rc.2` as a coarse fence (the precise gate is peers), `package.json` and `dsh.plugin.json` in sync.
|
|
103
|
+
- **Dual-manifest version restored**: `dsh.plugin.json` had drifted at `0.20.0-beta.6-dsh0.2.0.1`, this batch aligned it byte-for-byte with `package.json` (the V1 gate).
|
|
104
|
+
- **`dsh.client.inject` shrunk to `ui-primitives` only**: `dsh-client-connection` only exists as a package from 0.1.2 on, and declaring it would hang the entire client entry on 0.1.0/0.1.1 (`rpc.ts` has long lazily `ctx.get`s that connection).
|
|
105
|
+
|
|
106
|
+
### Discipline
|
|
107
|
+
|
|
108
|
+
- All build-type repos inject `prepack: npm run build` — `npm pack` only triggers prepack, not `prepublishOnly`; this is one of the three defense layers against the stale-build miscarriage.
|
|
109
|
+
|
|
110
|
+
## [0.21.0] — 2026-10-04
|
|
111
|
+
|
|
112
|
+
### Added
|
|
113
|
+
|
|
114
|
+
- **Tool-group sealing (memory panel → Memory → Tool Sealing)**: 5 toggles (room management / graph / ruminate / conflict / mutate write-delete, covering 13 tools). Off = that group's tools **are not registered**, vanishing straight from the model's tool list (not a rejection at execution time). A flip takes effect instantly via a volatile hot update, no restart needed. The core reads (memory_search / memory_read_scene / memory_receipts / conversation_search) and the three slot tools are not under control. Background: most grouped tools (e.g. Room governance, rumination) are used extremely rarely day to day, so keeping them resident in the tool list only wastes attention and lures the model into mis-invoking them.
|
|
115
|
+
- **Existence check on mem_ references in memory_slot_write**: L1 record_ids of the `mem_*` shape in refs are run through a `getByIds` existence check before writing; a hallucinated or misspelled id is rejected outright with a prompt to go through memory_search — guaranteeing that "memories activated by search" entering a slot reference are necessarily real records (the brief side's name-summary resolution therefore has reliable input). File-path / URL refs are not checked.
|
|
116
|
+
|
|
117
|
+
## [0.20.4] — 2026-10-04 (local build, unreleased)
|
|
118
|
+
|
|
119
|
+
### Fixed
|
|
120
|
+
|
|
121
|
+
- **Full fault tolerance for projection refViews resolution**: the call to L1 `getByIds` inside `resolveRefViews` is wrapped in try/catch — the registry's drive has no exception protection, so any throw at the resolution layer (sqlite busy / backend degradation / abnormal record state) would take down the whole session-event driver and even the host process. On failure it degrades to that frame carrying no refViews (the front end falls back to the raw refs).
|
|
122
|
+
|
|
123
|
+
## [0.20.3] — 2026-10-03
|
|
124
|
+
|
|
125
|
+
### Fixed
|
|
126
|
+
|
|
127
|
+
- **The `memory_search` render text now carries the id**: v0.20.2 added record_id to the output JSON and the schema, but the model sees the render product, not the raw JSON — the rendered line had no id, which for the model is as good as no return (found on real-machine retest). Each result now ends in `— id: mem_xxx`, directly writable into slot refs.
|
|
128
|
+
|
|
129
|
+
## [0.20.2] — 2026-10-03
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
|
|
133
|
+
- **Projection `memorySlots` dirtiness loosened to any event**: previously dirtiness was judged by store rev only on `tool/result` (settled, non-error) — after a write it relied on "another tool result happening to come in" to refresh, and cross-session viewing had to wait for the viewing session's own tool calls; the real machine exposed the sidebar sitting on an empty frame long after a write. Changed to an O(1) rev comparison on any committed event — when rev changes, rebuild and push; the isError guard is removed (rev only increments after a real change; the event is just a trigger, not the data source).
|
|
134
|
+
- **Resident injection moved to a `<system-reminder>` tag frame** (aligning with the dsh-agent-instructions AGENTS.md injection house style): the user-role carrier is unchanged, but it now presents as a tag box + authority declaration (no reply needed / do not echo / does not override system prompts or the user's direct instructions) — fixing weak models that echoed slot content verbatim as if it were the user's own speech and disrupted normal replies; closing tags inside the slot body are escaped (`</system-reminder>`) to prevent slot content from forging the frame boundary.
|
|
135
|
+
|
|
136
|
+
### Added
|
|
137
|
+
|
|
138
|
+
- **`memory_search` results expose `id` (L1 record_id)**: breaking the deadlock of "retrieval can't get an id → can't write slot refs / feed memory_receipts"; the schema description notes the two destinations of id.
|
|
139
|
+
- **wire view exposes `refs` + `refViews`**: `mem_*` references are resolved at projection-frame build time via L1 `getByIds` into `[type] 名称简述` (first line of content, truncated at 80 chars), rendered directly by brief-sidebar (≥0.5.0-beta.2); path / URL references stay literal; missing or retired records produce no entry. Resolution happens at frame-build time — the reference set is frozen when the slot is written, so later edits to the L1 record do not flow back into old frames. The self-implemented schema only validates extra fields "if present", so old checkpoint rows pass wholesale (stateVersion untouched).
|
|
140
|
+
|
|
141
|
+
## [0.20.1] — 2026-10-03 (promoted to stable; the beta channel's full capability set since beta.1 finalized)
|
|
142
|
+
|
|
143
|
+
The complete Hall·Room classification-management chain (two-level registry / merge / rename / retire / update / adoption / retirement-with-records / retiring an unregistered entry adds a registry record), independent Hall and Room management pages (search filter, default-collapsed, pointer drag-and-drop classification, retirement filter), aging-weight display + recall usage stats (only entering topN counts as used). The last beta before promotion was 0.20.0-beta.26, identical in content to 0.20.1; the `dsh-0.2.0-beta` channel continues to receive subsequent betas.
|
|
144
|
+
|
|
145
|
+
## [0.20.0-beta.26] — 2026-10-03
|
|
146
|
+
|
|
147
|
+
### Added (usability after Hall/Room growth)
|
|
148
|
+
|
|
149
|
+
- **Hall/Room name search filter**: a new search box on the Hall page (slug, display name, alias, case-insensitive) — a hit on the hall itself shows all its child rooms, otherwise only the matching child rooms are kept, and a group with no match at all is hidden; while searching, matching groups auto-expand (the collapsed state no longer hides results); the self-grown unregistered area is filtered the same way. The Room page has the same search box, composing with the retirement-filter chips.
|
|
150
|
+
- **Hall grouping collapse, default all collapsed**: the hall header only shows "total N entries · M rooms"; tap the header or the ▸/▾ button to expand/collapse child rooms; "expand all / collapse all" batch buttons; the expanded state is remembered in localStorage (`dsh.memory.halls.open`). The click-to-classify priority (tap the hall header to finish classifying) is unchanged.
|
|
151
|
+
|
|
152
|
+
## [0.20.0-beta.25] — 2026-10-02
|
|
153
|
+
|
|
154
|
+
> Fix for self-grown rooms becoming state-invisible after retirement + the Hall child-room display rule (user ruling).
|
|
155
|
+
|
|
156
|
+
### Fixed / Changed
|
|
157
|
+
|
|
158
|
+
- **Self-grown unregistered rooms become "retired / restore" on retirement**: previously retirement only soft-deleted records, the vocabulary had no entry to change, and the button was always "adopt / retire". Now retire withRecords, for an unregistered slug, **auto-adds a grown registration entry and sets it retired** — the panel row instantly switches to the "retired" state, and "restore" (active:true) brings it back into the vocabulary. Persisted, survives restart.
|
|
159
|
+
- **Hall page child rooms show only active**: retired rooms no longer appear under the hall grouping (see them on the Room page, which includes a "retired" filter); the group aggregate count accordingly includes only active subtypes.
|
|
160
|
+
|
|
161
|
+
## [0.20.0-beta.24] — 2026-10-02
|
|
162
|
+
|
|
163
|
+
### Fixed
|
|
164
|
+
|
|
165
|
+
- **Hall page expand/retire aligned with the Room page**: expanding a room row on the Hall page also pulls only active records (`retired:false`); after a retirement confirmation, if that room is expanded, the expanded area auto-refreshes. (beta.23 only patched the Room page, the Hall page missed the sync — the other spot behind the user-observed "retire but I see no effect".)
|
|
166
|
+
|
|
167
|
+
## [0.20.0-beta.23] — 2026-10-02
|
|
168
|
+
|
|
169
|
+
> **Room page retirement filter completed** (beta.22's filter chips never landed due to a patch script failing mid-way, only the badge made it into the package — this pass writes each item to disk via Edit and verifies all green).
|
|
170
|
+
|
|
171
|
+
### Fixed / Added
|
|
172
|
+
|
|
173
|
+
- **Retirement-filter chips** (Room page, above the registration form): all / active (vocabulary not retired) / retired.
|
|
174
|
+
- **Instant retirement effect**: expanding an entry pulls only **active** records (`retired:false`) — after retirement the expanded area shows "no memory entries"; if the room is expanded after a retirement confirmation it **auto-refreshes**; [retired] badge + grey-out fallback (already in beta.22).
|
|
175
|
+
|
|
176
|
+
## [0.20.0-beta.22] — 2026-10-02
|
|
177
|
+
|
|
178
|
+
> Retirement-effect visibility + Room page retirement filter (real-machine feedback: after a retirement confirmation the UI showed no change and there was no way to filter).
|
|
179
|
+
|
|
180
|
+
### Fixed / Added
|
|
181
|
+
|
|
182
|
+
- **Instant retirement effect**: expanding a Room-page entry pulls only **active** records (`retired:false`) — after retirement the expanded area shows "this Room has no memory entries"; if that room is expanded after a retirement confirmation its entries **auto-refresh**; mixed-listing fallback: retired entries show a [retired] badge and are greyed out.
|
|
183
|
+
- **Retirement filter**: the Room page gains "all / active / retired" chips (a vocabulary retirement-state filter).
|
|
184
|
+
|
|
185
|
+
## [0.20.0-beta.21] — 2026-10-02
|
|
186
|
+
|
|
187
|
+
> **Retire with records**: retiring a room can optionally **retire all its active memories along with it** (previously there was only the verb table, and self-grown rooms especially had no way to be handled).
|
|
188
|
+
|
|
189
|
+
### Added
|
|
190
|
+
|
|
191
|
+
- **`retire withRecords`** (the Room/Hall page "retire" button, red): vocabulary retirement + batch soft-delete of all **active** records under that room (each batch ≤200, the same primitive as records-delete; reason=manual) — records can be restored one by one in the memory page's "retired" section. A self-grown unregistered row also gets a "retire" (records only, no vocabulary entry to touch). The response carries a `retiredRecords` count.
|
|
192
|
+
- The "export orphans" button is relocated back to the **memory query panel** (inline in the orphan-filter row).
|
|
193
|
+
|
|
194
|
+
### Fixed
|
|
195
|
+
|
|
196
|
+
- recall-usage test isolation (a persisted-roundtrip case racing under parallelism); the literal `\n` display fix in the RoomTab retirement confirm dialog.
|
|
197
|
+
|
|
198
|
+
## [0.20.0-beta.20] — 2026-10-02
|
|
199
|
+
|
|
200
|
+
> **Room on its own tab** (separated from Hall): a room's existence, name, and entries each have their own management surface; the memory page no longer piles up Room tags.
|
|
201
|
+
|
|
202
|
+
### Added
|
|
203
|
+
|
|
204
|
+
- **The "Room" tab** (after Hall): a flat list of all rooms (registered entries ∪ self-grown unregistered) — **existence** (register a two-level slug / adopt grown / retire·restore), **name** (edit the display name + classification note; renaming can use a two-level slug, records follow), **entries** (▸ expand to browse that room's memory entries, default collapsed, first pull of 10); the orphan export / high-privilege toggles ride along.
|
|
205
|
+
- **Re-editable after registration**: a new `room-admin update` (rewrite label/description, fields not provided are left untouched) + store `RoomRegistryStore.update` + tool `memory_room_admin action=update` + a panel "edit" entry — previously, after registration the label/description could only fill in blanks, not be rewritten.
|
|
206
|
+
- **Room-row content expansion** (same as Hall-page room rows): default collapsed, ▸ expand to view entries.
|
|
207
|
+
- **Memory-page Room block separated**: removed the slug chips / paging / expand block (duplicating the Hall/Room pages), keeping only the "no binding · N" orphan filter and the guidance text — room tag browsing/management belongs to the Hall/Room pages.
|
|
208
|
+
|
|
209
|
+
### Changed
|
|
210
|
+
|
|
211
|
+
- The merge/classify/rename forms and preview sticky-follow scroll (with many halls you no longer swipe up and down hunting for the confirm dialog).
|
|
212
|
+
- Pointer-based custom drag-and-drop (the same pointer scheme as ego-browser, a fallback for webviews where HTML5 DnD does not fire).
|
|
213
|
+
|
|
214
|
+
## [0.20.0-beta.19] — 2026-10-02
|
|
215
|
+
|
|
216
|
+
> Classification interaction redone (real-machine feedback: HTML5 drag-and-drop does not fire in some webviews; after tapping a hall the preview was buried inside the source row and looked like "no response").
|
|
217
|
+
|
|
218
|
+
### Changed
|
|
219
|
+
|
|
220
|
+
- **Pointer-based custom drag-and-drop** (the same pure-pointer scheme as ego-browser): hold a room / self-grown slug → a floating ghost chip follows the finger → hover a hall header for a dashed highlight → release to classify. Not dependent on HTML5 DnD, works in any webview. Click-to-classify ("classify" / "assign" → selection state → tap the hall header) is kept.
|
|
221
|
+
- **Global action bar**: the merge/classify/rename forms and the dryRun preview are **permanently at the page head** (the red confirm dialog does not scroll with the row and is no longer buried inside the source room row) — after tapping a hall you always see it.
|
|
222
|
+
- **Room-row layout**: buttons pinned to one row no longer wrap (Export is no longer stranded on its own line); name/alias wrap naturally in the left info area (aliases can break mid-word).
|
|
223
|
+
|
|
224
|
+
## [0.20.0-beta.18] — 2026-10-02
|
|
225
|
+
|
|
226
|
+
### Maintenance
|
|
227
|
+
|
|
228
|
+
- lint cleanup: the two dead imports left in stats.ts / rooms-registry.ts by beta.17's isTag→isRoomSlug replacement (missed by the release gate — after the pipe `$?` took the tail's exit code, the D2 pitfall recurring). No functional change.
|
|
229
|
+
|
|
230
|
+
## [0.20.0-beta.17] — 2026-10-02
|
|
231
|
+
|
|
232
|
+
> **Fix for hall/room relations lost after restart**: the loader of `rooms-registry.json` was still filtering slugs with `isTag` — on restart-from-disk all `major/minor` two-level entries were treated as illegal and **silently dropped** (single-segment halls passed, so they survived). This is the third spot of the isTag/isRoomSlug mixup; the same batch cleared the identical landmine in `normTags`.
|
|
233
|
+
|
|
234
|
+
### Fixed
|
|
235
|
+
|
|
236
|
+
- **Loader dropping two-level entries** (`store/rooms-registry.ts` init): the filter changed to `isRoomSlug`. **Your on-disk rooms-registry.json data was intact** (the two-level entries were always in the file, only dropped at startup) — after upgrading and reloading the relations recover automatically, no repair action needed.
|
|
237
|
+
- **normTags washing out slash tags** (`metadata-validators.ts`): the gate "every tags write-back point must pass through here" used isTag, so a `hall/minor` tag written back by classification would be silently stripped the next time distillation or relabeling touched it. Now two-level room slugs pass (three-level still rejected); the `isRoomSlug` source of truth was moved into this file (to avoid a dependency cycle), and the rooms-registry re-export stays compatible.
|
|
238
|
+
- **list-records two-level tag filter wrongly rejected** (same shape as stats.ts tagSel): changed to `isRoomSlug` — tapping a two-level room's record filter on the Hall page used to 400.
|
|
239
|
+
- Red-test-first ×3 (two-level persistence roundtrip / normTags passing / integration two-level tag filter), verified red then fixed back to green.
|
|
240
|
+
|
|
241
|
+
## [0.20.0-beta.16] — 2026-10-02
|
|
242
|
+
|
|
243
|
+
> **Self-grown unregistered slugs classified straight into a hall**: each chip in the bottom "self-grown unregistered" area can now be dragged onto a hall header — adoption + becoming its subtype in one step.
|
|
244
|
+
|
|
245
|
+
### Added
|
|
246
|
+
|
|
247
|
+
- **grown chip drag / click classify**: drag an unregistered slug (e.g. `git-commits`) onto a hall header (or tap the "assign" button on the chip to enter selection state, then tap the target hall) → dryRun preview → confirm to run for real. Semantics = **adopt in place (from, source=grown) → rename to `hall/子类`**: record tags follow, the old name goes into the target's aliases, the entry is active and does not wear ⭐ (adoption identity). Falling back to a two-level slug under its own hall (e.g. `dsh-plugin/xxx`) = adopt in place.
|
|
248
|
+
- The composition order is pinned in an integration test (markMered early-exits on an unregistered from — you must adopt from first, then rename); execMerge auto-adopts an unregistered from.
|
|
249
|
+
|
|
250
|
+
## [0.20.0-beta.15] — 2026-10-02
|
|
251
|
+
|
|
252
|
+
> Two back-to-back fixes from real classification feedback: ① a renamed entry wrongly carrying "retired" (it would fall out of the annotation vocabulary); ② HTML5 drag-and-drop not working in some webviews → a **click-to-classify** main path added.
|
|
253
|
+
|
|
254
|
+
### Fixed
|
|
255
|
+
|
|
256
|
+
- **Entry wrongly marked retired after classify (rename)**: renameRoom reuses the merge orchestration, and `markMerged`'s "turn the old entry retired" came along — the newly-classified room displayed "retired" and **fell out of the annotator vocabulary** (the listActive filter). Now rename's tail restores the prior state (an active entry stays active after rename); a real merge (union semantics) is unaffected. Red-test-first (unit + HTTP-surface integration).
|
|
257
|
+
|
|
258
|
+
### Changed
|
|
259
|
+
|
|
260
|
+
- **Click-to-classify as the main path**: tap the room row's "classify" → enter selection state (the button becomes "pick hall…", all hall headers dashed-highlight) → tap the target hall header → dryRun preview → confirm to run. Drag-and-drop is kept (still usable in supporting environments) but no longer depended on.
|
|
261
|
+
|
|
262
|
+
## [0.20.0-beta.14] — 2026-10-02
|
|
263
|
+
|
|
264
|
+
> Memory cards gain **aging weight** and **recall usage** display, and start accumulating data for "aging-weight effect statistics". Definitions (user ruling): **only entering topN (being injected into context) counts as used**; a participation attempt that did not enter = attempt only.
|
|
265
|
+
|
|
266
|
+
### Added
|
|
267
|
+
|
|
268
|
+
- **Card fields**: an "aging N%" chip (the read-path decay coefficient `max(0.5, 0.5^(Δ天/半衰期))`, same formula and same source as the recall ranking; ≤60% turns red = aging) + a "used/attempts" counter (the title carries last-used / last-attempt times). The toolbar gains a summary "recall usage used/attempted(rate%)".
|
|
269
|
+
- **Stats surface**: `RecallUsageStore` (a recall-usage.json sidecar, the same discipline family as rooms-registry — a corrupt file falls back to read-only degrade, never blocking the recall read path); each recall round records at the three terminal states (inject / all-suppressed / budget-zeroed) (candidates attempts++, injected used++, timestamp takes the latest); in-memory immediate + a debounced 5s atomic flush, 50k entries evicted by most-recent-attempt; un-assembled = a zero-cost bypass.
|
|
270
|
+
- Contract: UiRecord gains `agingWeight`/`usage`, ListRecordsResponse gains `usageSummary` (optional fields, zero breakage for old clients); the contract key count is unchanged.
|
|
271
|
+
|
|
272
|
+
### Effect-statistics definitions (for later analysis)
|
|
273
|
+
- usageSummary: tracked (memories with usage stats) / attempted (Σ attempts) / used (Σ used) / rate (usage %)
|
|
274
|
+
- Fine-grained analysis (usage distribution by type/age band, half-life tuning basis) accumulates data from this version; the analysis view is to be discussed separately.
|
|
275
|
+
|
|
276
|
+
## [0.20.0-beta.13] — 2026-10-02
|
|
277
|
+
|
|
278
|
+
> Classification logic completed: putting a room under an existing hall (previously you could only add a new hall, or merge into another room and erase its identity). The panel supports **drag-and-drop classification** — drag a room and drop it on a hall header.
|
|
279
|
+
|
|
280
|
+
### Added
|
|
281
|
+
|
|
282
|
+
- **Hall-page drag-to-classify**: a room row is draggable (grab cursor when hiPriv is on), hall headers are drop targets (dashed highlight); release = a pre-filled rename (major/minor) straight to a dryRun preview, confirm to run — records follow, the old name goes to aliases, the grouped view hangs it under that hall. Touchscreens / environments without drag use the room-row "classify" button or the hall quick-select chips in the rename form as fallback.
|
|
283
|
+
- Backend fix: `renameSlug` target validation `isTag` → `isRoomSlug` — previously two-level targets (major/minor) were wrongly rejected, so "classify under a hall" was actually broken (and the rename orchestration would rewrite records first, then throw when renaming the registry, leaving a half-done state). Per the C3 removal/change discipline: red-test-first (unit + HTTP-surface integration, one each), verified red then fixed to green.
|
|
284
|
+
|
|
285
|
+
### Fixed
|
|
286
|
+
|
|
287
|
+
- Same as above: the `renameSlug` two-level target validation (a gap introduced in beta.5).
|
|
288
|
+
|
|
289
|
+
## [0.20.0-beta.12] — 2026-10-02
|
|
290
|
+
|
|
291
|
+
> lint cleanup + the removal discipline written down (C3 added to ENGINEERING-NOTES). **No functional change**.
|
|
292
|
+
|
|
293
|
+
### Maintenance
|
|
294
|
+
|
|
295
|
+
- **eslint cleanup (13 error → 0)**: longtask removal residue (stats.ts dead imports ×2, RecordsTab dead state) + older batches' debt (recluster.ts dead interface and let, rooms-registry.ts / ruminate.ts / room-review.ts / two test files' dead imports and let). The remaining 4 warnings are pre-existing baseline (the any in primitives/tools).
|
|
296
|
+
- **C3 "removal is also TDD" added to ENGINEERING-NOTES**: removal first changes tests to express the new expectation (red) → then removes the implementation (green); lint is a must-run gate for deletion-type changes (an unused import = an auto-detector for "not fully removed").
|
|
297
|
+
|
|
298
|
+
## [0.20.0-beta.11] — 2026-10-02
|
|
299
|
+
|
|
300
|
+
> Hall·Room **integration tests** landed (`tests/hall-room.integration.test.ts`: HTTP-surface full chain × real-storage user journey, 9 cases); the first integration run caught and fixed a unit-test blind spot.
|
|
301
|
+
|
|
302
|
+
### Fixed
|
|
303
|
+
|
|
304
|
+
- **rooms-get merged view hardcoding source `pre-registered`** (introduced in beta.4): when registry entries were merged into the count list the source was written fixed, so an adopted (source=grown) entry always wore the ⭐ pre-registered badge in the panel count chips — identity distortion. Now it uses the entry's real source (⭐ belongs only to pre-registered; adoption shows grown). Cause of the unit-test blind spot: the rooms-registry unit tests only tested the store layer, and no one asserted the source of a grown entry on the endpoint's merged row.
|
|
305
|
+
|
|
306
|
+
### Tests
|
|
307
|
+
|
|
308
|
+
- `hall-room.integration.test.ts`: empty-table self-grown count → two-level registration / illegal slug rejection → adoption → export three kinds → merge dryRun zero-write → run for real (backup to disk / retirement row rewrite / metadata preservation / scene recompute enqueue source='room-merge') → rename aliases → retire/restore → big-class 200 cap + small-class not counting against quota → corrupt read-only degrade red line (rooms-get not blocking, disk not written back).
|
|
309
|
+
|
|
310
|
+
## [0.20.0-beta.10] — 2026-10-02
|
|
311
|
+
|
|
312
|
+
> **Full removal of longtask (long-task mode)**: this family's home was on the context-compression side ("suggest starting compaction" is its domain), pm carried it by mistake — beta.8 removed the floating ball, this version removes the remaining backend. pm returns to the pure memory domain. Should "immediately distill the tail" and the like be needed later, redesign it from pm's own standpoint and re-charter it.
|
|
313
|
+
|
|
314
|
+
### Removed
|
|
315
|
+
|
|
316
|
+
- **Endpoints `longtask-hint-get` / `longtask-compress-tail`** (contract keys 48 → 46) and the `compressTailTurns` / debounced ruminate loop: context metering (`ContextUsageStore`), todo drift detection (`TodoRefStore`), the suggestion decision — all removed together; `hooks/long-task.ts`, `store/context-usage.ts`, `store/todo-ref.ts` three files deleted (including the todo/write-event declare module augmentation).
|
|
317
|
+
- **The `cfg.longTask.*` config block** (defaults + two Schema sites): longTask keys in old config files are ignored by the schema, no migration needed.
|
|
318
|
+
- **The session-level `longTask` flag and the tail-compression watermark `lastTailCompressedTurn`** (session-modes): leftover keys in old session-modes.json are naturally ignored by the load filter.
|
|
319
|
+
- **`session-mode-set`'s `mode` restored to required** (that optionalization existed only for the longTask either-or); the `longTask` request/response fields deleted.
|
|
320
|
+
- Kept: beta.9's roomRegistry RPC wiring fix (stands on its own); the Hall management page and Room classification management surface unchanged.
|
|
321
|
+
|
|
322
|
+
## [0.20.0-beta.9] — 2026-10-02
|
|
323
|
+
|
|
324
|
+
> Fix for deps being dropped across the whole panel RPC chain: `roomRegistry` and `longTaskDeps` were lost when rpcHandler assembled sources, so panel-side Room-management / long-task endpoints always read "not assembled" (the tool surface passes them directly and was unaffected, hence tools worked since beta.4 while panel registration kept erroring).
|
|
325
|
+
|
|
326
|
+
### Fixed
|
|
327
|
+
|
|
328
|
+
- **`registerMemoryRpc`'s rpcHandler dropped `roomRegistry`/`longTask`** (introduced in beta.4): HTTP dispatch uniformly goes through `buildEndpointDeps`, but sources carried only 7 items — `rooms-get` did not send down the registry, `room-register`/`room-admin` threw "Room registry not assembled (needs a plugin reload to initialize)", `longtask-hint-get`/`longtask-compress-tail` were always disabled. Now they are sent down with sources; a regression test pins the whole HTTP surface (register → rooms-get merge → room-admin, rpc.test.ts).
|
|
329
|
+
|
|
330
|
+
## [0.20.0-beta.8] — 2026-10-02
|
|
331
|
+
|
|
332
|
+
> Remove the floating-ball UI: the floating suggestion panel's home was on the context-compression side ("suggest starting compaction" is its domain), pm carried it by mistake — the FAB shipped since beta.1 is removed in this version.
|
|
333
|
+
|
|
334
|
+
### Removed
|
|
335
|
+
|
|
336
|
+
- **Floating ball + suggestion card (`client/src/longtask-fab.ts`, shipped since beta.1)**: entirely removed, the client reverts to two surfaces — `settings.section` (memory panel) + `conversation.input.left` (tier pill), no more application-wide floating UI. The long-task mode itself (context metering / todo reference / tail turn compression) is unaffected; the `longtask-hint-get` / `longtask-compress-tail` endpoints are kept as the backend surface, and the long-task toggle and manual-compaction entry will land in the memory settings section at finalize time.
|
|
337
|
+
|
|
338
|
+
## [0.20.0-beta.7] — 2026-10-02
|
|
339
|
+
|
|
340
|
+
> Room classification management third voyage (the **management-panel volume**): a dedicated "Hall" tab, hall (big class) + room (small class) managed together — manually viewing/managing Rooms no longer has to borrow the agent tool.
|
|
341
|
+
|
|
342
|
+
### Added
|
|
343
|
+
|
|
344
|
+
- **The "Hall" management tab** (after "Scene"): a hall grouping tree — `major/minor` go under their prefix big-class, a standalone slug forms its own hall (it is both a hall and the only room under it); the hall header row aggregates counts + a one-click "+small class" (pre-filled `hall/`); room rows show ⭐pre-registered / source / state / aliases / counts, retired greyed out. The UI terms Hall/Room are the grouping view, unrelated to Wing (the `metadata.hall` domain) and to cognition hall (ADR-0020 §7 disambiguation).
|
|
345
|
+
- **Full-operation UI entry (high-privilege memoryMutate gate)**: two-level slug registration (a controlled form, placeholder `dsh-plugin` / `dsh-plugin/merge`); self-grown slug **adoption** (`source=grown`); **rename/merge** via the new RPC — dryRun preview (affected count + samples) → "confirm run", the same orchestration as the memory_room_admin tool (auto-backup before execution + scene recompute enqueued on completion); retire/restore one click (restore has no second confirm, retire does confirm); a per-room record-list CSV export; vocabulary / orphan export consolidated onto this page; merge/rename carry an "execute when rumination is idle" hint.
|
|
346
|
+
- **New endpoint `dsh-memory/room-admin`** (merge/rename/retire; memoryMutate gate, endpoint-side throw semantics): contract keys 47 → 48. `rooms-export` gains `kind='records'` (export a record list by Room, `tag` required); `room-register` gains an optional `source` (adoption passes `grown`).
|
|
347
|
+
- The memory Tab Room block slimmed: the management sub-panel removed (orphan export moved to the header row), the hint points to the Hall page.
|
|
348
|
+
|
|
349
|
+
### Fixed
|
|
350
|
+
|
|
351
|
+
- The `rooms-export` records branch kind type narrowing (TS2322) and a garbled historical error string; the CHANGELOG beta.1-beta.5 duplicate header line fix.
|
|
352
|
+
|
|
353
|
+
## [0.20.0-beta.6] — 2026-10-01
|
|
354
|
+
|
|
355
|
+
### Fixed
|
|
356
|
+
|
|
357
|
+
- **Annotator vocabulary wired to the registry (beta.5's missing item completed)**: beta.5's merge/rename/retire landed, but the candidate annotator's (`annotateOrphanCandidates`) vocabulary was still a pure self-grown aggregate — pre-registered Rooms could not enter candidates at all. Now OrphanAnnotateIO carries a registry: the merged vocabulary = registry entries ordered first (count=0, with label/description) + the self-grown directory, capped at 120; both the ruminate and memory_room_admin annotate paths pass the argument. **Pre-registered Rooms now genuinely influence candidate annotation.**
|
|
358
|
+
|
|
359
|
+
## [0.20.0-beta.5] — 2026-10-01
|
|
360
|
+
|
|
361
|
+
> Room classification management second voyage (the **destructive surface**). dryRun defaults to true — merge/rename preview the impact first, run only after confirmation; auto-backup to `rooms-merge-backups/` before execution.
|
|
362
|
+
|
|
363
|
+
### Added
|
|
364
|
+
|
|
365
|
+
- **Room registry two-level system**: slugs support a `major` or `major/minor` two-level shape (e.g. `dsh-plugin`, `dsh-plugin/merge`); **big-class cap 200**, small-class subdivisions do not count against the big-class quota (an overall insurance of 2000). The isTag vocabulary is not loosened (slash is only allowed at the registry layer).
|
|
366
|
+
- **merge/rename/retire (tool `memory_room_admin`, high-privilege)**: merge rewrites the tags of all matching records via a cursor (re-read-merge-write before writing, keys preserved across roomCandidates/roomReview/hall/anchors etc.; includes already-retired rows, consistent with the count definition); rename = 1:1 merge + registry rename (aliases absorb the old name); retire is vocabulary retirement only (existing data untouched). merge/rename running concurrently with rumination overwrite each other — stagger them (both the tool hint and ADR-0020 declare this).
|
|
367
|
+
- **Rewrite-safety trio**: dryRun by default returns only affected + preview with zero writes; auto-backup matching records to `rooms-merge-backups/<ts>-<slug>.json` before running; on completion auto `invalidateRooms` + enqueue scene recompute by affected (family, scene) (`source='room-merge'`).
|
|
368
|
+
- **Panel Room management sub-panel** (appears after high-privilege is enabled): a registration form (slug/name/description, via the new RPC `room-register`), orphan-list export; merge/retirement suggestions go through the agent tool (dryRun preview is more detailed).
|
|
369
|
+
- Endpoint surface 46 → 47 (`room-register`).
|
|
370
|
+
|
|
371
|
+
## [0.20.0-beta.4] — 2026-10-01
|
|
372
|
+
|
|
373
|
+
> Room classification management first voyage (the **zero-drift surface**): an empty registry = behavior byte-identical to beta.3. The merge/rename/retire destructive surface comes with beta.5 (dryRun default true held back one version).
|
|
374
|
+
|
|
375
|
+
### Added
|
|
376
|
+
|
|
377
|
+
- **Room registry (`rooms-registry.json` sidecar)**: pre-register curated Rooms (slug/label/description); corrupt/empty → degrade back to a pure self-grown directory, never blocking the panel or the annotator; cap 200 to prevent spam. The `rooms-get` endpoint layer merges: a registered entry enters the vocabulary even at count=0 and carries `source`/`label`, the response gains a full `registry` field (optionally read by the client).
|
|
378
|
+
- **Export endpoint `dsh-memory/rooms-export`** (kind=rooms|orphans, CSV direct out): rooms = registry ∪ self-grown vocabulary with counts; orphans = the active-record list with no Room binding (including candidate/recheck state columns).
|
|
379
|
+
- **Tool `memory_room_admin`** (action=list|register): list shows the registry + self-grown overview; register pre-registers a Room (high-privilege gate, idempotent completion) — paired with `memory_room_review`'s per-item recheck, the agent gains a full "register → pre-mark → confirm one by one" classification-management entry.
|
|
380
|
+
- Client: Room chips carry a "pre-registered / self-grown" source badge; orphan chips carry a pending-recheck semantics.
|
|
381
|
+
|
|
382
|
+
## [0.20.0-beta.3] — 2026-10-01
|
|
383
|
+
|
|
384
|
+
### Added
|
|
385
|
+
|
|
386
|
+
- **Record panel Room classification improvements**: ① expand/collapse (collapse = header + a preview of the top 8 high-frequency Rooms, open/close state persisted); ② full paging in the expanded state (40 per page, ◀▶ to page), replacing the old hard cut of "only the first 40 shown"; ③ **orphan memory filter** — a leading "no binding · N" chip that shows only memories with no Room binding at all (`list-records` gains an `untagged` filter channel, `rooms-get` gains `orphanCount`, same definition as the Room count); ④ filter conditions instantly visible + one-click clear. The retrieval path has the same orphan filter.
|
|
387
|
+
|
|
388
|
+
## [0.20.0-beta.2] — 2026-10-01
|
|
389
|
+
|
|
390
|
+
> dsh-0.2.0-beta channel +1: full-context rumination optimization (repo soft fence / per-project scene migration / closed loop). Packaged with longtask (see beta.1), real-machine feedback merged in.
|
|
391
|
+
|
|
392
|
+
### Added
|
|
393
|
+
|
|
394
|
+
- **Repo soft fence (ADR-0015, `recall.scopeFence.*`, default off)**: repoKey=basename(normalized cwd) computed at write time into L1 metadata (repo_key_name/repo_key_owner/applicability, DEFAULT zero backfill, not entering FTS or the snapshot hash); recall and memory_search exits soft-downrank by `this-repo`/`cross-project` (×0.2 tunable, **only downrank, never exclude**, the chat family and unattributed records are not fenced, a dedup-path sentinel guards against mis-entry). Zero drift: when off by default, the recall order sha1 roundtrips identical.
|
|
395
|
+
- **Per-project scene migration (L2 repo awareness + re-clustering)**: the L2 consolidation prompt sees repoKeyName/applicability — this-repo records are no longer merged into cross-project scenes; a `scene_recluster_jobs` queue + a rumination idle-tier consumer (snapshot → delete-summary projection → full rollback on failure, zero new LLM channel); after a repo attribution patch it auto-queries affected scenes by repoKey and enqueues a recompute.
|
|
396
|
+
- **Compaction closed loop**: a 10-minute debounced rumination after a tail-compaction enqueue succeeds (flush → L2 → L3 → relabel → re-clustering consumption), fixing the break of "compacted records stranded in the distillation bucket".
|
|
397
|
+
|
|
398
|
+
## [0.20.0-beta.1] — 2026-10-01
|
|
399
|
+
|
|
400
|
+
> The first beta-channel release of the dsh-0.2.0 line (`dsh-0.2.0-beta` tag): long-task mode real-machine preview. Beyond the items below, this version also carries all prior main changes parked in `[Unreleased]` (activation slots / source anchors / evidence reader / memory retirement loop / three-axis conflicts etc.) — they shipped with the 0.1.7 line but the main line had no corresponding version number.
|
|
401
|
+
|
|
402
|
+
### Added
|
|
403
|
+
|
|
404
|
+
- **Long-task mode (`longTask.*`, default off) — the three-piece set for "long-running sessions": context metering, task reference, tail compression, plus a non-blocking floating suggestion panel.**
|
|
405
|
+
- **Context usage (`store/context-usage.ts`)**: listens to the input side of `assistant/message`'s official `usage` (input + cache read/write), taking the **most-recent value** semantics (each round's input side already contains all history, no accumulation); zeroed and recounted after `compaction/summary`. A pure in-memory per-session Map — the first assistant message after a restart can rebuild it; persistence would only resurrect stale samples.
|
|
406
|
+
- **todo reference (`store/todo-ref.ts` + `hooks/long-task.ts`)**: listens to the host's structured `todo/write` event (a full snapshot; the package types had not declared it as of 0.2.0-rc.1, so the plugin self-augments via declare module — the same precedent as §E's dsh-compaction). **Long-task sessions only**: the snapshot is flushed into one pinned `todo` slot (`SlotStore.refreshByTitle` managed refresh — repeated writes by the same subject must update in place, otherwise within the ≤8 slot cap you pile up closed-slot trails), injected residently via slot-recall — after compaction evicts the old context, the task north-star is still there. Adjacent snapshots get a lexical Jaccard drift detection (repeated writes of the same snapshot do not dilute the signal); body ≤512 bytes, truncation stated.
|
|
407
|
+
- **Tail turn compression (`longtask-compress-tail` endpoint + `compressTailTurns`)**: immediately `enqueue(force:true)`-distills the most recent N turns within (compaction watermark, latest captured turn] into memory — landing the tail conversation into searchable memory right away rather than waiting for the distillation threshold. The watermark (`SessionModeStore.lastTailCompressedTurn`) only moves forward, and repeated presses are naturally idempotent; the off tier is fully invisible; un-anchored old data is only included on the first compression (watermark 0) — rather take less than re-distill.
|
|
408
|
+
- **Suggestion state (`longtask-hint-get`) + floating ball (`client/src/longtask-fab.ts`)**: an ego-browser-style vanilla overlay (FAB + panel, drag / position persistence / viewport clamping), **the suggestion does not block** — the glow lights only when "context occupancy reaches `contextThresholdPct`" or "todo drift reaches `driftThreshold`" and long-task is off; inside the panel: the long-task toggle (temporary, per-session, **carries no mode** — flipping the switch does not reset the user's tier), the occupancy / drift progress bars, a manual tail-compaction button (only usable when long-task is on). Polling busy 2s / idle 5s, RPC failures silent; the seat contract is unchanged (settings.section exactly one, the body singleton occupies no seat).
|
|
409
|
+
- **`session-mode-set`'s `mode` made optional**: either it or `longTask` is required — flipping only the long-task switch is no longer forced to send a tier (old clients always send mode, behavior unchanged). The response `mode` is changed back to the currently effective value.
|
|
410
|
+
|
|
10
411
|
## [0.19.0] — 2026-09-29
|
|
11
412
|
|
|
12
413
|
### Changed
|