dsh-loci 2.7.0 → 2.7.1

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.md CHANGED
@@ -4,6 +4,38 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the project follows
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html) from 1.0.0.
6
6
 
7
+ ## [2.7.1] — 2026-11-15
8
+
9
+ A correction, and a decision not to ship something.
10
+
11
+ ### Corrected
12
+
13
+ 2.7.0's acceptance note said the index does not scale — "arm C asked for 12/12 ids, so at 200
14
+ entries the model pulls the whole store". **That was wrong, and the error was in the
15
+ experiment.** Arm C asked **12 questions about 12 different entries**; fetching 12 bodies is
16
+ the correct answer to 12 questions. Concluding "it over-fetches" from `questions == fetches`
17
+ was a mistake in the arm's design, not a property of the product.
18
+
19
+ The fair version — **one** question against many candidates:
20
+
21
+ | Arm | Candidates | Result |
22
+ |---|---|---|
23
+ | D1 | 12 titles, 1 relevant | fetched **1**, the right one |
24
+ | D2 | 40 titles, 1 relevant, plus a decoy sharing the query word | fetched **1**, the right one |
25
+ | E | 40 titles, nothing relevant | answered `NOT_IN_MEMORY`, substituted nothing |
26
+
27
+ ### Not shipped, on purpose
28
+
29
+ The work item was "make the index guide the model to converge". It already converges, so no
30
+ steering text was added to the footer. Two arms tested a footer that explicitly said "do not
31
+ batch-fetch titles that merely look plausible": it changed nothing. The footer is 83 bytes on
32
+ every request, and this design's entire argument is that prompt bytes are the scarce
33
+ resource — a sentence that changes no behaviour is pure cost.
34
+
35
+ The lesson is worth more than the fix would have been: **a measurement that counts fetches
36
+ against questions must keep those two numbers independent.** `docs/ACCEPTANCE.md` now carries
37
+ the correction in place, rather than quietly deleting the wrong claim.
38
+
7
39
  ## [2.7.0] — 2026-11-15
8
40
 
9
41
  The acceptance was measuring less than it claimed. This release re-runs it properly and
@@ -104,7 +104,51 @@ Each arm answered in one turn with no tools.
104
104
  |---|---|---|---|
105
105
  | **A — no memory** | the 20 questions only | **0/20** | answered `UNKNOWN` to all 20 — it abstained rather than hallucinating |
106
106
  | **B — index only** | the 20 questions + 20 index lines whose titles *are* the facts | **20/20** | answered every question with the exact value |
107
- | **C — index + fetch** | 12 index lines whose titles are *summaries*; the values are only in bodies; allowed to request ids | asked for **12/12** ids | did not discriminate — requested the whole index |
107
+ | **C — index + fetch** | 12 questions, 12 summary titles, values only in bodies | asked for 12/12 ids | correct: 12 questions need 12 bodies — see the correction below |
108
+ | **D1 — one question, 12 candidates, one relevant** | one question + 12 summary titles | fetched **1/1**, the right one | no over-fetch |
109
+ | **D2 — one question, 40 candidates, one relevant** | one question + 40 summary titles (including a decoy sharing the word 发布) | fetched **1/1**, the right one | no over-fetch at 40 |
110
+ | **E — one question, 40 candidates, nothing relevant** | the same 40 titles, asking about something absent | answered `NOT_IN_MEMORY` | did not substitute a nearby entry |
111
+
112
+ ### Correction: arm C did not show what it first appeared to show
113
+
114
+ The first write-up of this section said arm C revealed greedy fetching — "asked for 12/12
115
+ ids, did not discriminate, pulls the whole index at 200 entries". **That was wrong, and the
116
+ error was in the experiment, not the product.** Arm C asked **12 questions about 12
117
+ different entries**; fetching 12 bodies is the *correct* answer to 12 questions. Concluding
118
+ "it over-fetches" from `questions == fetches` was a design mistake in the arm.
119
+
120
+ D1 and D2 are the fair version: **one** question, many candidates, exactly one relevant.
121
+ Both fetched a single body, and D2 found it among 40 titles while ignoring a decoy that
122
+ shares the query word (发布说明 vs 发布窗口).
123
+
124
+ Two follow-up arms then tested whether the instruction text changed the behaviour, using a
125
+ footer that explicitly said "do not batch-fetch titles that merely look plausible":
126
+
127
+ | Variant | Result |
128
+ |---|---|
129
+ | current footer | fetched the needed ids |
130
+ | steering footer | fetched the same ids |
131
+
132
+ The instruction made no difference, so it was **not** added to the shipped footer. The
133
+ footer is 83 bytes on every request; a sentence that changes no behaviour is pure prompt
134
+ cost, and this repository's whole argument for the index shape is that prompt bytes are the
135
+ scarce resource.
136
+
137
+ ### Decision: no code change, on purpose
138
+
139
+ The work item that produced arms C–E was "make the index guide the model to converge
140
+ instead of fetching everything". The evidence says it already converges:
141
+
142
+ | Situation | Behaviour |
143
+ |---|---|
144
+ | one question, one matching title among 12 | fetches that one |
145
+ | one question, one matching title among 40, with a decoy | fetches that one |
146
+ | one question, no matching title among 40 | `NOT_IN_MEMORY`, no substitute |
147
+ | N questions, N matching titles | fetches N — which is correct |
148
+
149
+ The only case that looked like over-fetching was the one where the experiment asked N
150
+ questions and counted N fetches. Shipping a fix for it would have been shipping a change
151
+ justified by a badly designed measurement.
108
152
 
109
153
  Read honestly:
110
154
 
@@ -113,10 +157,9 @@ Read honestly:
113
157
  - **The abstention in arm A is a good sign.** The model did not invent values; a
114
158
  memory-less assistant says "I don't know" instead of confabulating. So the value here is
115
159
  recall, not anti-hallucination.
116
- - **Arm C is the warning.** When titles are summaries, a model facing 12 entries fetches all
117
- 12. That is fine at 12 and untenable at 200: the "index keeps the prompt small" argument
118
- collapses if the model's response to ambiguity is to pull the whole store. Narrowing that
119
- is a design problem, not a formatting problem.
160
+ - **The index scales better than the first draft of this page claimed.** One question
161
+ against 40 candidate titles resolved to a single body. The scaling worry this section
162
+ raised was the author's, not the design's.
120
163
 
121
164
  ## B.5 What §B still does not measure
122
165
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-loci",
3
- "version": "2.7.0",
3
+ "version": "2.7.1",
4
4
  "description": "Layered long-term memory for DeepSeek Harness: the prompt sees only a stable index, full text is one lookup away. Bi-temporal facts, strict scope isolation, verified-only injection.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/host/index.js CHANGED
@@ -23,7 +23,7 @@ import { registerCommands } from './commands.js';
23
23
  import { runDoctor } from './doctor.js';
24
24
 
25
25
  /** Version stamped into the database and diagnostics. */
26
- export const VERSION = '2.7.0';
26
+ export const VERSION = '2.7.1';
27
27
 
28
28
  /** Optional collaborators; without them the plugin still serves tools. */
29
29
  export const inject = ['systemPrompt', 'tools'];
@@ -36,7 +36,7 @@ export function openFacadeStore(options = {}) {
36
36
  memoryRoot: root,
37
37
  paths,
38
38
  config,
39
- pluginVersion: '2.7.0',
39
+ pluginVersion: '2.7.1',
40
40
  readOnly: options.readOnly === true,
41
41
  });
42
42
  return { store, paths };