@tenphi/akno-core 0.13.0 → 0.13.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 (98) hide show
  1. package/dist/bench/language-corpus-v23.d.ts +4 -0
  2. package/dist/bench/language-corpus-v23.d.ts.map +1 -0
  3. package/dist/bench/language-corpus-v23.js +203 -0
  4. package/dist/bench/language-corpus-v23.js.map +1 -0
  5. package/dist/bench/language-review.d.ts +26 -0
  6. package/dist/bench/language-review.d.ts.map +1 -1
  7. package/dist/bench/language-review.js +15 -1
  8. package/dist/bench/language-review.js.map +1 -1
  9. package/dist/bench/language.d.ts +885 -27
  10. package/dist/bench/language.d.ts.map +1 -1
  11. package/dist/bench/language.js +94 -7
  12. package/dist/bench/language.js.map +1 -1
  13. package/dist/context.d.ts +3 -0
  14. package/dist/context.d.ts.map +1 -1
  15. package/dist/context.js.map +1 -1
  16. package/dist/index/indexer.d.ts +10 -0
  17. package/dist/index/indexer.d.ts.map +1 -1
  18. package/dist/index/indexer.js +21 -1
  19. package/dist/index/indexer.js.map +1 -1
  20. package/dist/kb/prose.d.ts +1 -1
  21. package/dist/kb/prose.d.ts.map +1 -1
  22. package/dist/kb/prose.js +120 -10
  23. package/dist/kb/prose.js.map +1 -1
  24. package/dist/maintenance/brain-migration.d.ts +4 -1
  25. package/dist/maintenance/brain-migration.d.ts.map +1 -1
  26. package/dist/maintenance/brain-migration.js +29 -6
  27. package/dist/maintenance/brain-migration.js.map +1 -1
  28. package/dist/maintenance/dream.d.ts +2 -0
  29. package/dist/maintenance/dream.d.ts.map +1 -1
  30. package/dist/maintenance/dream.js +270 -64
  31. package/dist/maintenance/dream.js.map +1 -1
  32. package/dist/maintenance/observation-scope.d.ts +74 -0
  33. package/dist/maintenance/observation-scope.d.ts.map +1 -0
  34. package/dist/maintenance/observation-scope.js +259 -0
  35. package/dist/maintenance/observation-scope.js.map +1 -0
  36. package/dist/maintenance/observe.d.ts +2 -0
  37. package/dist/maintenance/observe.d.ts.map +1 -1
  38. package/dist/maintenance/observe.js +28 -24
  39. package/dist/maintenance/observe.js.map +1 -1
  40. package/dist/maintenance/plans.d.ts +20 -1
  41. package/dist/maintenance/plans.d.ts.map +1 -1
  42. package/dist/maintenance/plans.js +251 -35
  43. package/dist/maintenance/plans.js.map +1 -1
  44. package/dist/memory/intent.d.ts +1 -1
  45. package/dist/memory/intent.d.ts.map +1 -1
  46. package/dist/memory/intent.js +49 -14
  47. package/dist/memory/intent.js.map +1 -1
  48. package/dist/observations/marker.d.ts +2 -0
  49. package/dist/observations/marker.d.ts.map +1 -1
  50. package/dist/observations/marker.js +16 -4
  51. package/dist/observations/marker.js.map +1 -1
  52. package/dist/observations/projection.d.ts +1 -1
  53. package/dist/observations/projection.d.ts.map +1 -1
  54. package/dist/observations/projection.js +14 -5
  55. package/dist/observations/projection.js.map +1 -1
  56. package/dist/open.d.ts.map +1 -1
  57. package/dist/open.js +5 -0
  58. package/dist/open.js.map +1 -1
  59. package/dist/ops/folder.d.ts.map +1 -1
  60. package/dist/ops/folder.js +3 -0
  61. package/dist/ops/folder.js.map +1 -1
  62. package/dist/ops/forget.d.ts.map +1 -1
  63. package/dist/ops/forget.js +9 -0
  64. package/dist/ops/forget.js.map +1 -1
  65. package/dist/ops/graph.js +5 -1
  66. package/dist/ops/graph.js.map +1 -1
  67. package/dist/ops/move.d.ts.map +1 -1
  68. package/dist/ops/move.js +15 -7
  69. package/dist/ops/move.js.map +1 -1
  70. package/dist/ops/remember.d.ts.map +1 -1
  71. package/dist/ops/remember.js +34 -8
  72. package/dist/ops/remember.js.map +1 -1
  73. package/dist/ops/retain.d.ts.map +1 -1
  74. package/dist/ops/retain.js +119 -2
  75. package/dist/ops/retain.js.map +1 -1
  76. package/dist/ops/write.d.ts.map +1 -1
  77. package/dist/ops/write.js +17 -4
  78. package/dist/ops/write.js.map +1 -1
  79. package/dist/store/db.d.ts.map +1 -1
  80. package/dist/store/db.js +18 -1
  81. package/dist/store/db.js.map +1 -1
  82. package/dist/store/migrations.d.ts +4 -2
  83. package/dist/store/migrations.d.ts.map +1 -1
  84. package/dist/store/migrations.js +41 -2
  85. package/dist/store/migrations.js.map +1 -1
  86. package/dist/write/journal.d.ts +2 -0
  87. package/dist/write/journal.d.ts.map +1 -1
  88. package/dist/write/journal.js +11 -0
  89. package/dist/write/journal.js.map +1 -1
  90. package/dist/write/mutation-receipts.d.ts +32 -0
  91. package/dist/write/mutation-receipts.d.ts.map +1 -0
  92. package/dist/write/mutation-receipts.js +331 -0
  93. package/dist/write/mutation-receipts.js.map +1 -0
  94. package/dist/write/retain.d.ts +6 -2
  95. package/dist/write/retain.d.ts.map +1 -1
  96. package/dist/write/retain.js +76 -9
  97. package/dist/write/retain.js.map +1 -1
  98. package/package.json +3 -2
@@ -0,0 +1,331 @@
1
+ import path from 'node:path';
2
+ import { AknoError } from '@tenphi/akno-protocol';
3
+ import { sha256 } from "../store/ids.js";
4
+ import { normalizeSlug } from "../ops/write.js";
5
+ const REPLAY_SAFE_OPERATIONS = ['write', 'move', 'forget', 'folder'];
6
+ // A process can open the same knowledge base twice because its pid already owns the write lock.
7
+ // Key by database path as well as receipt identity so those handles still agree which call is live.
8
+ const activeReceipts = new Set();
9
+ const MAX_RESULT_BYTES = 64 * 1024;
10
+ export function isReplaySafeOperation(operation) {
11
+ return REPLAY_SAFE_OPERATIONS.includes(operation);
12
+ }
13
+ /**
14
+ * Bind a caller-owned key before the first effect and return a completed request without
15
+ * reapplying it. Incomplete rows fail closed: only a process that knows it never crossed the
16
+ * mutation boundary may discard its reservation and let the caller try again.
17
+ */
18
+ export async function executeReplaySafeMutation(ctx, operation, parsedInput, work) {
19
+ const { idempotency_key: key, ...operationInput } = parsedInput;
20
+ if (!key)
21
+ return work(ctx, operationInput);
22
+ const requestHash = mutationRequestHash(operation, operationInput);
23
+ const identity = receiptIdentity(ctx.config.dbPath, ctx.actor, operation, key);
24
+ const existing = readReceipt(ctx.store, ctx.actor, operation, key);
25
+ if (existing) {
26
+ assertSameRequest(existing, requestHash);
27
+ if (existing.state === 'completed') {
28
+ return replayResult(ctx, operation, operationInput, existing);
29
+ }
30
+ if (activeReceipts.has(identity)) {
31
+ throw new AknoError('busy', `${operation} with this idempotency key is still running`, {
32
+ operation,
33
+ idempotency_key: key,
34
+ state: existing.state,
35
+ });
36
+ }
37
+ throw interruptedError(existing);
38
+ }
39
+ const now = new Date().toISOString();
40
+ ctx.store.db
41
+ .prepare(`INSERT INTO mutation_receipts(
42
+ actor, operation, idempotency_key, request_hash, state, started_at
43
+ ) VALUES(?, ?, ?, ?, 'reserved', ?)`)
44
+ .run(ctx.actor, operation, key, requestHash, now);
45
+ const receipt = {
46
+ actor: ctx.actor,
47
+ operation,
48
+ idempotencyKey: key,
49
+ requestHash,
50
+ started: false,
51
+ };
52
+ activeReceipts.add(identity);
53
+ try {
54
+ const result = await work({ ...ctx, mutationReceipt: receipt }, operationInput);
55
+ if (!receipt.started && isRetryablePrecondition(result)) {
56
+ deleteReceipt(ctx.store, receipt);
57
+ return result;
58
+ }
59
+ if (receipt.started)
60
+ assertJournalCommit(ctx.store, receipt, result);
61
+ const stored = compactResult(operation, result);
62
+ const updated = ctx.store.db
63
+ .prepare(`UPDATE mutation_receipts
64
+ SET state = 'completed', result = ?, completed_at = ?
65
+ WHERE actor = ? AND operation = ? AND idempotency_key = ? AND request_hash = ?
66
+ AND state IN ('reserved', 'running', 'committed')`)
67
+ .run(stored, new Date().toISOString(), ctx.actor, operation, key, requestHash);
68
+ if (updated.changes !== 1) {
69
+ throw new AknoError('internal', `could not complete the ${operation} mutation receipt`);
70
+ }
71
+ return result;
72
+ }
73
+ catch (error) {
74
+ if (receipt.started) {
75
+ ctx.store.db
76
+ .prepare(`UPDATE mutation_receipts
77
+ SET state = 'interrupted', result = NULL, completed_at = NULL
78
+ WHERE actor = ? AND operation = ? AND idempotency_key = ? AND request_hash = ?
79
+ AND state IN ('running', 'committed')`)
80
+ .run(ctx.actor, operation, key, requestHash);
81
+ }
82
+ else {
83
+ deleteReceipt(ctx.store, receipt);
84
+ }
85
+ throw error;
86
+ }
87
+ finally {
88
+ activeReceipts.delete(identity);
89
+ }
90
+ }
91
+ /** Mark the durable boundary immediately before the first filesystem effect. */
92
+ export function beginMutation(ctx) {
93
+ const receipt = ctx.mutationReceipt;
94
+ if (!receipt || receipt.started)
95
+ return;
96
+ const updated = ctx.store.db
97
+ .prepare(`UPDATE mutation_receipts SET state = 'running'
98
+ WHERE actor = ? AND operation = ? AND idempotency_key = ? AND request_hash = ?
99
+ AND state = 'reserved'`)
100
+ .run(receipt.actor, receipt.operation, receipt.idempotencyKey, receipt.requestHash);
101
+ if (updated.changes !== 1) {
102
+ throw new AknoError('internal', `could not start the ${receipt.operation} mutation receipt`);
103
+ }
104
+ receipt.started = true;
105
+ }
106
+ /**
107
+ * A new writer proves the old process is gone. Reservations never reached the mutation boundary;
108
+ * every later state might have changed Markdown and therefore remains as an explicit interruption.
109
+ */
110
+ export function recoverInterruptedMutationReceipts(ctx) {
111
+ if (!ctx.writable)
112
+ return;
113
+ ctx.store.transaction(() => {
114
+ const rows = ctx.store.db
115
+ .prepare("SELECT actor, operation, idempotency_key, state FROM mutation_receipts WHERE state != 'completed'")
116
+ .all();
117
+ const remove = ctx.store.db.prepare(`DELETE FROM mutation_receipts
118
+ WHERE actor = ? AND operation = ? AND idempotency_key = ? AND state = 'reserved'`);
119
+ const interrupt = ctx.store.db.prepare(`UPDATE mutation_receipts SET state = 'interrupted', result = NULL, completed_at = NULL
120
+ WHERE actor = ? AND operation = ? AND idempotency_key = ?
121
+ AND state IN ('running', 'committed')`);
122
+ for (const row of rows) {
123
+ if (activeReceipts.has(receiptIdentity(ctx.config.dbPath, row.actor, row.operation, row.idempotency_key))) {
124
+ continue;
125
+ }
126
+ if (row.state === 'reserved')
127
+ remove.run(row.actor, row.operation, row.idempotency_key);
128
+ else
129
+ interrupt.run(row.actor, row.operation, row.idempotency_key);
130
+ }
131
+ });
132
+ }
133
+ function mutationRequestHash(operation, input) {
134
+ return sha256(stableJson({ operation, request: canonicalRequest(operation, input) }));
135
+ }
136
+ function canonicalRequest(operation, input) {
137
+ const request = withoutUndefined(input);
138
+ if (operation === 'write') {
139
+ if (typeof request.slug === 'string')
140
+ request.slug = normalizeSlug(request.slug);
141
+ if (typeof request.propose_slug === 'string')
142
+ request.propose_slug = normalizeSlug(request.propose_slug);
143
+ if (Array.isArray(request.documents)) {
144
+ request.documents = request.documents.map((document) => isRecord(document) && typeof document.path === 'string'
145
+ ? { ...document, path: path.resolve(document.path) }
146
+ : document);
147
+ }
148
+ request.dry_run = request.dry_run ?? false;
149
+ }
150
+ else if (operation === 'move') {
151
+ if (typeof request.from === 'string')
152
+ request.from = normalizeSlug(request.from);
153
+ if (typeof request.to === 'string')
154
+ request.to = normalizeSlug(request.to);
155
+ }
156
+ else if (operation === 'forget') {
157
+ if (typeof request.slug === 'string')
158
+ request.slug = request.slug.replace(/\.(md|markdown)$/i, '');
159
+ }
160
+ else {
161
+ if (typeof request.path === 'string')
162
+ request.path = normalizeSlug(request.path).replace(/\/\*+$/, '');
163
+ const role = typeof request.role === 'string' ? request.role : 'knowledge';
164
+ request.role = role;
165
+ request.remember = request.remember ?? (role === 'knowledge' ? 'integrate' : 'deny');
166
+ request.dry_run = request.dry_run ?? false;
167
+ }
168
+ return request;
169
+ }
170
+ function compactResult(operation, result) {
171
+ const safe = withoutUndefined({ ...result });
172
+ delete safe.removed;
173
+ delete safe.rule;
174
+ if (operation === 'folder' && result.rule !== undefined) {
175
+ if (result.outcome === 'noop') {
176
+ safe.rebuild_existing_rule = true;
177
+ safe.rule_hash = sha256(stableJson(result.rule));
178
+ }
179
+ else {
180
+ safe.rebuild_rule = true;
181
+ }
182
+ }
183
+ let encoded = stableJson(safe);
184
+ if (Buffer.byteLength(encoded) <= MAX_RESULT_BYTES)
185
+ return encoded;
186
+ const bounded = withoutUndefined({
187
+ status: result.status,
188
+ outcome: result.outcome,
189
+ change_id: result.change_id,
190
+ removed_from: result.removed_from,
191
+ trashed: result.trashed,
192
+ path: result.path,
193
+ glob: result.glob,
194
+ rules_file: result.rules_file,
195
+ result_truncated: true,
196
+ });
197
+ encoded = stableJson(bounded);
198
+ if (Buffer.byteLength(encoded) > MAX_RESULT_BYTES) {
199
+ throw new AknoError('internal', 'mutation result locator exceeded its storage bound');
200
+ }
201
+ return encoded;
202
+ }
203
+ function replayResult(ctx, operation, input, receipt) {
204
+ if (!receipt.result)
205
+ throw new AknoError('internal', 'completed mutation receipt has no result locator');
206
+ const result = JSON.parse(receipt.result);
207
+ if (result.rebuild_rule && operation === 'folder') {
208
+ result.rule = folderRuleFromRequest(input);
209
+ delete result.rebuild_rule;
210
+ }
211
+ if (result.rebuild_existing_rule && operation === 'folder' && typeof result.glob === 'string') {
212
+ const rule = currentFolderRule(ctx, result.glob);
213
+ if (rule && sha256(stableJson(rule)) === result.rule_hash)
214
+ result.rule = rule;
215
+ delete result.rebuild_existing_rule;
216
+ delete result.rule_hash;
217
+ }
218
+ if (operation === 'forget' && receipt.change_id && (input.fact || input.memory)) {
219
+ const removed = removedTextFromJournal(ctx.store, receipt.change_id);
220
+ if (removed !== null)
221
+ result.removed = removed;
222
+ }
223
+ delete result.result_truncated;
224
+ return { ...result, replayed: true };
225
+ }
226
+ function folderRuleFromRequest(input) {
227
+ const role = typeof input.role === 'string' ? input.role : 'knowledge';
228
+ return withoutUndefined({
229
+ description: input.description,
230
+ role,
231
+ remember: input.remember ?? (role === 'knowledge' ? 'integrate' : 'deny'),
232
+ about: input.about,
233
+ type: input.type,
234
+ ingest: input.ingest,
235
+ rank: input.rank,
236
+ route: input.route,
237
+ });
238
+ }
239
+ function currentFolderRule(ctx, glob) {
240
+ const compiled = ctx.config.rules.find((rule) => rule.glob === glob);
241
+ if (!compiled)
242
+ return null;
243
+ const { glob: _glob, source: _source, specificity: _specificity, ...rule } = compiled;
244
+ return withoutUndefined(rule);
245
+ }
246
+ function removedTextFromJournal(store, changeId) {
247
+ const row = store.db
248
+ .prepare(`SELECT before, after FROM change_files
249
+ WHERE change_id = ? AND before IS NOT NULL AND after IS NOT NULL ORDER BY ord LIMIT 1`)
250
+ .get(changeId);
251
+ if (!row)
252
+ return null;
253
+ const before = row.before.split('\n');
254
+ const after = row.after.split('\n');
255
+ let prefix = 0;
256
+ while (prefix < before.length && prefix < after.length && before[prefix] === after[prefix])
257
+ prefix++;
258
+ let suffix = 0;
259
+ while (suffix < before.length - prefix &&
260
+ suffix < after.length - prefix &&
261
+ before[before.length - 1 - suffix] === after[after.length - 1 - suffix]) {
262
+ suffix++;
263
+ }
264
+ const removed = before.slice(prefix, before.length - suffix);
265
+ return removed.length > 0 ? removed.join('\n') : null;
266
+ }
267
+ function readReceipt(store, actor, operation, key) {
268
+ return store.db
269
+ .prepare(`SELECT * FROM mutation_receipts
270
+ WHERE actor = ? AND operation = ? AND idempotency_key = ?`)
271
+ .get(actor, operation, key);
272
+ }
273
+ function assertSameRequest(receipt, requestHash) {
274
+ if (receipt.request_hash === requestHash)
275
+ return;
276
+ throw new AknoError('conflict', 'this idempotency key is already bound to a different request', {
277
+ operation: receipt.operation,
278
+ idempotency_key: receipt.idempotency_key,
279
+ });
280
+ }
281
+ function assertJournalCommit(store, receipt, result) {
282
+ const row = readReceipt(store, receipt.actor, receipt.operation, receipt.idempotencyKey);
283
+ if (row?.state !== 'committed' ||
284
+ typeof result.change_id !== 'string' ||
285
+ row.change_id !== result.change_id) {
286
+ throw new AknoError('internal', `${receipt.operation} crossed its mutation boundary without an atomic journal commit`);
287
+ }
288
+ }
289
+ function interruptedError(receipt) {
290
+ return new AknoError('interrupted', `${receipt.operation} with this idempotency key may already have changed the knowledge base`, {
291
+ operation: receipt.operation,
292
+ idempotency_key: receipt.idempotency_key,
293
+ state: receipt.state,
294
+ ...(receipt.change_id ? { change_id: receipt.change_id } : {}),
295
+ recovery: receipt.change_id
296
+ ? 'Inspect the recorded change before deciding whether to undo or continue with a new idempotency key.'
297
+ : 'Inspect the requested destination before continuing with a new idempotency key.',
298
+ });
299
+ }
300
+ function isRetryablePrecondition(result) {
301
+ return ['requires_folder', 'requires_approval', 'conflict'].includes(String(result.outcome));
302
+ }
303
+ function deleteReceipt(store, receipt) {
304
+ store.db
305
+ .prepare(`DELETE FROM mutation_receipts
306
+ WHERE actor = ? AND operation = ? AND idempotency_key = ? AND request_hash = ?`)
307
+ .run(receipt.actor, receipt.operation, receipt.idempotencyKey, receipt.requestHash);
308
+ }
309
+ function receiptIdentity(dbPath, actor, operation, key) {
310
+ return `${dbPath}\0${actor}\0${operation}\0${key}`;
311
+ }
312
+ function withoutUndefined(value) {
313
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
314
+ }
315
+ function stableJson(value) {
316
+ return JSON.stringify(sortValue(value));
317
+ }
318
+ function sortValue(value) {
319
+ if (Array.isArray(value))
320
+ return value.map(sortValue);
321
+ if (!isRecord(value))
322
+ return value;
323
+ return Object.fromEntries(Object.keys(value)
324
+ .filter((key) => value[key] !== undefined)
325
+ .sort()
326
+ .map((key) => [key, sortValue(value[key])]));
327
+ }
328
+ function isRecord(value) {
329
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
330
+ }
331
+ //# sourceMappingURL=mutation-receipts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutation-receipts.js","sourceRoot":"","sources":["../../src/write/mutation-receipts.ts"],"names":[],"mappings":"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"}
@@ -7,8 +7,8 @@ import type { FolderCatalogEntry } from '../kb/folders.ts';
7
7
  * consumed by keyed `retain` and unkeyed `remember`; keeping the interpretation here prevents
8
8
  * the two public operations from gradually learning different meanings for the same source.
9
9
  */
10
- export declare const RETAIN_PROMPT_VERSION = "retain-extraction-language-v57";
11
- export declare const RETAIN_VERIFIER_VERSION = "retain-verifier-language-v41";
10
+ export declare const RETAIN_PROMPT_VERSION = "retain-extraction-language-v59";
11
+ export declare const RETAIN_VERIFIER_VERSION = "retain-verifier-language-v42";
12
12
  /** All fields are required or nullable so constrained-decoding endpoints can keep strict mode. */
13
13
  export declare const RETAIN_SCHEMA: z.ZodObject<{
14
14
  candidates: z.ZodArray<z.ZodObject<{
@@ -149,7 +149,10 @@ export type RetainCandidate = ProvidedRetainCandidate & {
149
149
  /** Compatibility fields consumed by the existing remember result and evidence archive. */
150
150
  origin?: 'user' | 'assistant';
151
151
  evidence?: string;
152
+ /** Verifier-derived boundary for automatic placement; never supplied by the extraction model. */
153
+ retention_scope?: RetentionScope;
152
154
  };
155
+ type RetentionScope = 'global' | 'entity' | 'document' | 'event' | 'task' | 'unknown';
153
156
  export interface RetainHeldCandidate {
154
157
  hold_stage?: 'validation' | 'verification';
155
158
  candidate_id: string;
@@ -203,4 +206,5 @@ export declare function cleanCandidateBatch(value: unknown, options: CandidateCl
203
206
  held: RetainHeldCandidate[];
204
207
  };
205
208
  export declare function modelCallReceipt(model: ModelClient, outcome: ModelOutcome<unknown>): RetainModelCallReceipt;
209
+ export {};
206
210
  //# sourceMappingURL=retain.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"retain.d.ts","sourceRoot":"","sources":["../../src/write/retain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"retain.d.ts","sourceRoot":"","sources":["../../src/write/retain.ts"],"names":[],"mappings":"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"}
@@ -21,8 +21,8 @@ import { SEMANTIC_COMPARISON_CONTRACT, PROPOSITION_SCOPE_CONTRACT, aggregateSema
21
21
  * consumed by keyed `retain` and unkeyed `remember`; keeping the interpretation here prevents
22
22
  * the two public operations from gradually learning different meanings for the same source.
23
23
  */
24
- export const RETAIN_PROMPT_VERSION = 'retain-extraction-language-v57';
25
- export const RETAIN_VERIFIER_VERSION = 'retain-verifier-language-v41';
24
+ export const RETAIN_PROMPT_VERSION = 'retain-extraction-language-v59';
25
+ export const RETAIN_VERIFIER_VERSION = 'retain-verifier-language-v42';
26
26
  const MAX_CANDIDATE_TEXT_UNITS = 400;
27
27
  const RETRIEVAL_UNIT_CONTRACT = `A retained record is one independently retrievable semantic unit:
28
28
  the selected proposition together with every source qualification governing its truth, knowledge state,
@@ -153,6 +153,9 @@ own sentence with an explicit subject, keeping exactly whether the person lacks
153
153
  or personally performed a check. Choose subject and page after that qualified record. They describe its source-supported canonical identity,
154
154
  not an action phrase constructed from its words. A proposed page is only a taxonomy suggestion, never proof
155
155
  of ownership; use only the supplied admitted pages or creatable folders, and keep an unresolved home null.
156
+ For a durable document-scoped preference, choose the named document as subject, not merely the person
157
+ who expressed the preference. Never propose that person's general page, a bare year, or a domain index
158
+ as the document's home. If the document identity or home is unresolved, leave the page null.
156
159
  When the outer narrator supplies a later corrective clarification of an inner report, close the inner
157
160
  speaker's reported clause before the clarification and explicitly name the narrator as its source.
158
161
  Keep both clauses in the same readable candidate with their shared verification limits. Do not move the
@@ -189,7 +192,12 @@ uses active, cancelled or superseded; question uses active or resolved. A questi
189
192
  none: uncertainty about its answer does not make the question itself tentative or asserted.
190
193
 
191
194
  Keep durable facts, accepted decisions, stated preferences, active plans, actual events, durable open
192
- questions, and proven experience. Keep a considered, rejected, tentative, hypothetical, cancelled,
195
+ questions, and proven experience. A command to finish or clean up this one document or task is not
196
+ a standing preference, even when phrased in the first person. A question asked only to complete the
197
+ current task is not automatically a durable open question; an unresolved question worth returning to is.
198
+ Keep the original document, person, project, trip, or event scope in the readable record. Do not turn
199
+ an advertisement, quotation, or nearby project mention into a fact about that project. Keep a
200
+ considered, rejected, tentative, hypothetical, cancelled,
193
201
  completed, or superseded item only when its readable sentence explicitly preserves that status.
194
202
  When relevant to the supplied retention mission, discussed hypotheses, fictional examples, suspicions,
195
203
  and unaccepted proposals are useful records too. Lack of established truth is not a reason to discard them.
@@ -319,6 +327,21 @@ actor, an asserted alternative, lost evidentiary limits or lost personal nonsele
319
327
  For ordinary_tentative, tentative qualifies the selected uncertain proposition normally. Do not interpret
320
328
  record-level metadata as syntactically modifying every verb regardless of the supplied label definition.
321
329
 
330
+ Independently classify retention admission from the complete source before approving placement.
331
+ For each candidate, retention.durability is durable only when the selected proposition remains useful
332
+ beyond this one source-processing task. A one-task command, a transient live reading, and a question
333
+ whose only purpose is finishing the current task are not durable. A genuine standing preference and
334
+ an unresolved question worth revisiting are durable, even if their wording is brief. Choose uncertain
335
+ when the source does not establish which. Classify source_scope from the selected source proposition,
336
+ not the candidate's proposed page or subject label. Classify candidate_scope from the readable text:
337
+ global for a standing preference across tasks, including a named person's cross-context preference;
338
+ entity for one named product/project/trip/booking or one person's specific profile fact,
339
+ document for one named document, event for one occurrence, task for a one-task instruction, and
340
+ unknown when the boundary is absent. A document-specific command restated as a global deletion
341
+ preference has source_scope=document and candidate_scope=global, even if its words are source-entailing
342
+ in isolation. Never widen a source's scope to make a destination convenient. Admission and factual
343
+ support are separate decisions: a faithful task-only record can still be held as not durable.
344
+
322
345
  For every supplied candidate id, first audit its exact frame and use comparison.source_meaning and
323
346
  comparison.candidate_meaning to identify the governing retained predicate and its actor separately from
324
347
  subordinate or coupled propositions. Preserve every selected predicate and qualification; naming a governing
@@ -728,7 +751,12 @@ export async function runRetain(text, model, options = {}) {
728
751
  modelUsage: { extraction: extractionReceipt, ...repairUsage, verification: verified.receipt },
729
752
  };
730
753
  }
731
- const accepted = cleaned.candidates.filter((candidate) => verified.accepted.has(candidate.candidate_id));
754
+ const accepted = cleaned.candidates
755
+ .filter((candidate) => verified.accepted.has(candidate.candidate_id))
756
+ .map((candidate) => ({
757
+ ...candidate,
758
+ retention_scope: verified.scopes.get(candidate.candidate_id),
759
+ }));
732
760
  const heldByVerification = cleaned.candidates
733
761
  .filter((candidate) => !verified.accepted.has(candidate.candidate_id))
734
762
  .map((candidate) => ({
@@ -762,6 +790,7 @@ async function verifyCandidates(model, source, candidates, repairObligations, re
762
790
  const outcomes = [];
763
791
  const accepted = new Set();
764
792
  const reasons = new Map();
793
+ const scopes = new Map();
765
794
  // Two disjoint candidates fit the default derive-role ceiling without truncating a large batch.
766
795
  // Relations still see the complete candidate context; candidates themselves are never evidence.
767
796
  for (let start = 0; start < candidates.length; start += 2) {
@@ -772,6 +801,7 @@ async function verifyCandidates(model, source, candidates, repairObligations, re
772
801
  return {
773
802
  accepted: new Set(),
774
803
  reasons: new Map(),
804
+ scopes: new Map(),
775
805
  error: checked.error,
776
806
  receipt: modelCallReceipt(model, aggregateSemanticOutcomes(outcomes)),
777
807
  };
@@ -779,6 +809,8 @@ async function verifyCandidates(model, source, candidates, repairObligations, re
779
809
  accepted.add(id);
780
810
  for (const [id, reason] of checked.reasons)
781
811
  reasons.set(id, reason);
812
+ for (const [id, scope] of checked.scopes)
813
+ scopes.set(id, scope);
782
814
  }
783
815
  // A source-supported relation still cannot persist when its target record was withheld.
784
816
  // Iterate because a rejected target may invalidate a chain spanning several verification batches.
@@ -797,6 +829,7 @@ async function verifyCandidates(model, source, candidates, repairObligations, re
797
829
  return {
798
830
  accepted,
799
831
  reasons,
832
+ scopes,
800
833
  error: null,
801
834
  receipt: modelCallReceipt(model, aggregateSemanticOutcomes(outcomes)),
802
835
  };
@@ -832,6 +865,11 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
832
865
  proposition_supported: semanticVerdictFields.proposition_supported,
833
866
  action_arguments_preserved: semanticVerdictFields.action_arguments_preserved,
834
867
  qualification_scope_preserved: semanticVerdictFields.qualification_scope_preserved,
868
+ retention: z.strictObject({
869
+ durability: z.enum(['durable', 'task_only', 'transient', 'uncertain']),
870
+ source_scope: z.enum(['global', 'entity', 'document', 'event', 'task', 'unknown']),
871
+ candidate_scope: z.enum(['global', 'entity', 'document', 'event', 'task', 'unknown']),
872
+ }),
835
873
  reason_code: reason.nullable(),
836
874
  });
837
875
  });
@@ -889,6 +927,7 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
889
927
  return {
890
928
  accepted: new Set(),
891
929
  reasons: new Map(),
930
+ scopes: new Map(),
892
931
  outcome,
893
932
  error: outcome.error ?? 'verification failed',
894
933
  };
@@ -915,7 +954,13 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
915
954
  verdict.qualification_scope_preserved) ||
916
955
  verdict.reason_code === null))) {
917
956
  model.reportInvalidResponse();
918
- return { accepted: new Set(), reasons: new Map(), outcome, error: 'verification returned invalid JSON' };
957
+ return {
958
+ accepted: new Set(),
959
+ reasons: new Map(),
960
+ scopes: new Map(),
961
+ outcome,
962
+ error: 'verification returned invalid JSON',
963
+ };
919
964
  }
920
965
  const byId = new Map(parsed.data.verdicts.map((verdict) => [verdict.candidate_id, verdict]));
921
966
  if (parsed.data.verdicts.length !== candidates.length ||
@@ -925,6 +970,7 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
925
970
  return {
926
971
  accepted: new Set(),
927
972
  reasons: new Map(),
973
+ scopes: new Map(),
928
974
  outcome,
929
975
  error: 'verification omitted or duplicated candidate verdicts',
930
976
  };
@@ -940,14 +986,35 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
940
986
  // A source-side classification is compared with immutable metadata, independently of
941
987
  // positive prose verdicts. Disagreement is a semantic hold, never permission to relabel.
942
988
  verdict.source_selected_polarity ===
943
- candidates.find((candidate) => candidate.candidate_id === verdict.candidate_id).polarity)
989
+ candidates.find((candidate) => candidate.candidate_id === verdict.candidate_id).polarity &&
990
+ admissionReason(verdict.retention) === null)
944
991
  .map((verdict) => verdict.candidate_id));
945
992
  const reasons = new Map();
993
+ const scopes = new Map();
946
994
  for (const verdict of parsed.data.verdicts) {
947
- if (!accepted.has(verdict.candidate_id))
948
- reasons.set(verdict.candidate_id, verdict.reason_code ?? 'discourse_uncertain');
995
+ if (accepted.has(verdict.candidate_id))
996
+ scopes.set(verdict.candidate_id, verdict.retention.source_scope);
997
+ if (!accepted.has(verdict.candidate_id)) {
998
+ const semanticFailure = !verdict.proposition_supported ||
999
+ !verdict.action_arguments_preserved ||
1000
+ !verdict.qualification_scope_preserved ||
1001
+ verdict.source_selected_polarity !==
1002
+ candidates.find((candidate) => candidate.candidate_id === verdict.candidate_id).polarity;
1003
+ reasons.set(verdict.candidate_id, semanticFailure
1004
+ ? (verdict.reason_code ?? 'discourse_uncertain')
1005
+ : (verdict.reason_code ?? admissionReason(verdict.retention) ?? 'discourse_uncertain'));
1006
+ }
949
1007
  }
950
- return { accepted, reasons, outcome, error: null };
1008
+ return { accepted, reasons, scopes, outcome, error: null };
1009
+ }
1010
+ function admissionReason(retention) {
1011
+ if (retention.durability === 'task_only' || retention.durability === 'transient')
1012
+ return 'not_durable';
1013
+ if (retention.durability === 'uncertain' || retention.source_scope === 'unknown')
1014
+ return 'noncanonical_without_context';
1015
+ if (retention.source_scope !== retention.candidate_scope)
1016
+ return 'scope_mismatch';
1017
+ return retention.source_scope === 'task' ? 'scope_mismatch' : null;
951
1018
  }
952
1019
  /** Source spellings help classification; generated subjects cannot certify their own language. */
953
1020
  function retentionLanguageReferences(source) {