instar 1.3.528 → 1.3.530

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 (42) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +114 -0
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +29 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/CoherenceJournal.d.ts +1 -1
  8. package/dist/core/CoherenceJournal.d.ts.map +1 -1
  9. package/dist/core/CoherenceJournal.js +27 -2
  10. package/dist/core/CoherenceJournal.js.map +1 -1
  11. package/dist/core/EvolutionManager.d.ts +35 -0
  12. package/dist/core/EvolutionManager.d.ts.map +1 -1
  13. package/dist/core/EvolutionManager.js +49 -0
  14. package/dist/core/EvolutionManager.js.map +1 -1
  15. package/dist/core/KnowledgeReplicatedStore.d.ts +310 -0
  16. package/dist/core/KnowledgeReplicatedStore.d.ts.map +1 -0
  17. package/dist/core/KnowledgeReplicatedStore.js +526 -0
  18. package/dist/core/KnowledgeReplicatedStore.js.map +1 -0
  19. package/dist/core/LearningsReplicatedStore.d.ts +298 -0
  20. package/dist/core/LearningsReplicatedStore.d.ts.map +1 -0
  21. package/dist/core/LearningsReplicatedStore.js +574 -0
  22. package/dist/core/LearningsReplicatedStore.js.map +1 -0
  23. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  24. package/dist/core/PostUpdateMigrator.js +49 -1
  25. package/dist/core/PostUpdateMigrator.js.map +1 -1
  26. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  27. package/dist/core/devGatedFeatures.js +10 -0
  28. package/dist/core/devGatedFeatures.js.map +1 -1
  29. package/dist/knowledge/KnowledgeManager.d.ts +37 -0
  30. package/dist/knowledge/KnowledgeManager.d.ts.map +1 -1
  31. package/dist/knowledge/KnowledgeManager.js +45 -0
  32. package/dist/knowledge/KnowledgeManager.js.map +1 -1
  33. package/dist/scaffold/templates.d.ts.map +1 -1
  34. package/dist/scaffold/templates.js +3 -1
  35. package/dist/scaffold/templates.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/data/builtin-manifest.json +20 -20
  38. package/src/scaffold/templates.ts +3 -1
  39. package/upgrades/1.3.529.md +33 -0
  40. package/upgrades/1.3.530.md +33 -0
  41. package/upgrades/side-effects/ws22-learnings.md +74 -0
  42. package/upgrades/side-effects/ws24-knowledge.md +77 -0
@@ -0,0 +1,526 @@
1
+ /**
2
+ * KnowledgeReplicatedStore — the FOURTH concrete consumer of the HLC replicated-store
3
+ * foundation (WS2.4) and the THIRD memory-family kind (after WS2.3 relationships and
4
+ * WS2.2 learnings). It layers the `knowledge-record` replicated kind onto the generic
5
+ * substrate (ReplicatedRecordEnvelope / UnionReader / ConflictStore / RollbackUnmerge /
6
+ * ReplicationBudget / StoreSnapshot) so that a knowledge SOURCE the agent ingested on
7
+ * machine A is known on machine B — ONE knowledge catalog, not one-per-machine.
8
+ *
9
+ * It is the literal analog of `LearningsReplicatedStore.ts` (the WS2.2 memory-family
10
+ * reference consumer) and `RelationshipsReplicatedStore.ts` (the WS2.3 PII reference
11
+ * consumer). A knowledge source is a POINTER + SUMMARY (a `title`/`url`/`type` +
12
+ * `summary`/`tags`/`wordCount`), lower-PII than a relationship — but its
13
+ * `title`/`summary`/`url` CAN reference people or content, so it REUSES the established
14
+ * PII machinery (type-clamp, disclosure-min projection, tombstones, flag-coherence)
15
+ * rather than reinventing or downgrading it. THIS IS PURE LOGIC. No fs, no Date directly,
16
+ * no network. It defines:
17
+ *
18
+ * A. The `knowledge-record` store schema — a STRICT typed validator that
19
+ * TYPE-CLAMPS every known field: `ingestedAt` ISO-8601-only, `type` ∈ the
20
+ * {article,transcript,doc} enum, `wordCount` a finite number, `tags[]`/free text
21
+ * length-clamped. The schema is a DISCRIMINATED UNION on `op` — an `op:'put'` VALUE
22
+ * schema AND an `op:'delete'` TOMBSTONE schema coexist under the one kind, so a
23
+ * tombstone is never marked invalid by the value schema.
24
+ *
25
+ * B. The disclosure-minimized PROJECTION (fork #2) — `buildKnowledgeRecordData` emits
26
+ * ONLY the enumerated catalog-metadata fields, NEVER the markdown file BODY (the
27
+ * separate `filePath` file can be a huge transcript — full-content sync is a
28
+ * TRACKED follow-up, CMT-1416) and NEVER the local generated `id` OR the local
29
+ * `filePath` (a per-machine artifact path — meaningless and a mild info-leak on a
30
+ * peer). `recordKey` is the cross-machine IDENTITY SURFACE, derived deterministically
31
+ * from the stable content (normalize(url || title) + normalize(type)) — never the
32
+ * per-machine `generateId()` id (the cross-machine-UNSTABLE id, exactly the
33
+ * relationship-UUID / LRN-id trap the prior kinds solved with a stable identity
34
+ * surface). The SAME article ingested on two machines collapses to ONE record.
35
+ *
36
+ * C. The TOMBSTONE builder — `buildKnowledgeTombstoneData` emits an `op:'delete'`
37
+ * record `{ recordKey, op, hlc, origin, deletedAt }` so a `remove()` propagates as a
38
+ * positive signal across an offline-then-rejoining peer instead of a record absence.
39
+ * CRITICAL: the KnowledgeManager.remove() path MUST emit a tombstone per removed
40
+ * source, else a peer re-replicates the locally-removed source forever (resurrection).
41
+ *
42
+ * D. The union-aware read — `mergeUnionToKnowledge` collapses a
43
+ * `Map<recordKey, UnionResult>` into the merged catalog view. Knowledge is
44
+ * HIGH-impact at the REPLICATION layer (a concurrent divergent edit to the SAME
45
+ * recordKey — e.g. two machines re-summarize the same url differently — goes through
46
+ * APPEND-BOTH-AND-FLAG; both versions surface, never a silent clobber). The CONSUMER
47
+ * READ path is ADVISORY (fork #3): it injects BOTH variants of an open conflict as
48
+ * guidance — a knowledge source is REFERENCE, not authority — and NEVER blocks on an
49
+ * unresolved conflict. The read NEVER writes a foreign record into the local store.
50
+ *
51
+ * E. Foreign-record render safety — `renderForeignKnowledgeContext` wraps a replicated
52
+ * record in an explicit `<replicated-untrusted-data origin="…">` envelope and
53
+ * sanitizes EVERY rendered field. There is no "trusted because machine-set" render
54
+ * slot for a foreign record.
55
+ *
56
+ * DECIDED FORKS (Echo, 2026-06-13 — recorded verbatim in the PR ELI16):
57
+ * 1. recordKey = a content fingerprint over the STABLE source identity
58
+ * (sha256(normalize(url || title) + '\x1f' + normalize(type))), NEVER the local
59
+ * generated `id` (cross-machine identity surface — see deriveKnowledgeRecordKey).
60
+ * 2. Replicate the CATALOG ENTRY (metadata) ONLY — NOT the markdown file body. The
61
+ * projection carries { title, url, type, ingestedAt, tags[], summary, wordCount }
62
+ * and STRIPS the local `id` + `filePath`. Full-content-body sync is a TRACKED
63
+ * follow-up (CMT-1416).
64
+ * 3. Impact tier = HIGH at the REPLICATION layer (append-both-and-flag), ADVISORY at
65
+ * the READ layer (both variants injected as hints, never blocking) — a knowledge
66
+ * source is reference, not authority. See mergeUnionToKnowledge + KNOWLEDGE_IMPACT_TIER.
67
+ *
68
+ * SAFETY POSTURE: MECHANISM, dark by default. Nothing here blocks a user-initiated
69
+ * action. The local `id` + `filePath` are NEVER part of the replicated schema and are
70
+ * stripped from every emitted projection (disclosure minimization).
71
+ */
72
+ import { createHash } from 'node:crypto';
73
+ import { jailStoreStringField } from './ReplicatedRecordEnvelope.js';
74
+ // ───────────────────────────────────────────────────────────────────────────
75
+ // A. Identity, tier, schema, bounds, caps
76
+ // ───────────────────────────────────────────────────────────────────────────
77
+ /** The stateSync config sub-key + advert suffix for this store (e.g.
78
+ * `multiMachine.stateSync.knowledge.enabled`). Equal to the advert flag key
79
+ * `stateSyncReceive['knowledge']`. */
80
+ export const KNOWLEDGE_STORE_KEY = 'knowledge';
81
+ /** The JournalKind string this store rides — the DUAL-REGISTRY's dynamic half.
82
+ * MUST also be present in CoherenceJournal.JOURNAL_KINDS (the static half), or the
83
+ * store advertises receive=true yet serves/applies/pulls nothing. */
84
+ export const KNOWLEDGE_RECORD_KIND = 'knowledge-record';
85
+ /**
86
+ * Knowledge is HIGH-impact at the REPLICATION layer (fork #3): a concurrent divergent
87
+ * VALUE edit to the SAME recordKey from different origins goes through
88
+ * APPEND-BOTH-AND-FLAG — both versions preserved, ONE deduped conflict, never a silent
89
+ * overwrite. The READ path (mergeUnionToKnowledge) is ADVISORY — both variants surface as
90
+ * guidance hints, the read never blocks on an open conflict — a knowledge source is
91
+ * reference, not authority. Operator resolution via POST /state/resolve-conflict is
92
+ * OPTIONAL cleanup that collapses the flag, never a gate on the hint.
93
+ */
94
+ export const KNOWLEDGE_IMPACT_TIER = 'high';
95
+ /** The valid `type` enum for a knowledge source (KnowledgeManager.KnowledgeSource). A
96
+ * foreign record whose `type` is outside this set is REJECTED (markup cannot survive an
97
+ * enum slot). */
98
+ export const KNOWLEDGE_TYPES = Object.freeze(['article', 'transcript', 'doc']);
99
+ // ── Local-record caps mirrored on RECEIVE (length-clamp discipline). A value over a
100
+ // cap REJECTS the whole record (never truncate-and-accept), EXCEPT free text which
101
+ // is length-clamped on receive (a flood is bounded, not record-rejected). ───────
102
+ /** A knowledge `summary` can be a paragraph. Clamp on receive (NOT the file body — the
103
+ * body is never replicated; only this short catalog summary crosses the wire). */
104
+ export const MAX_SUMMARY_LENGTH = 20_000;
105
+ /** Per-free-text-string clamp for title / each tag. */
106
+ export const MAX_FREETEXT_LENGTH = 2_000;
107
+ /** A url is bounded (the catalog url; never a file body). */
108
+ export const MAX_URL_LENGTH = 2_048;
109
+ /** Tags cap (mirrors a reasonable per-source tag count). */
110
+ export const MAX_TAGS = 50;
111
+ /**
112
+ * Per-kind replication bounds. The knowledge store is FEW + bounded (a catalog of
113
+ * ingested sources), so the per-store retention mirrors the learning-record sibling (a
114
+ * small window with a few archives). NEVER `rotateKeep: 0` (rotate-but-never-delete
115
+ * would be a compliance defect for any memory-family kind). The rate cap COALESCES
116
+ * (latest state per recordKey per interval) so a churny re-ingest loop does not flood
117
+ * the stream.
118
+ */
119
+ export const KNOWLEDGE_RECORD_BOUNDS = {
120
+ retention: { maxFileBytes: 4 * 1024 * 1024, rotateKeep: 4 },
121
+ // Few records, coalesced: capacity is the burst, refill the sustained rate.
122
+ rateCap: { capacity: 30, refillPerSec: 5 },
123
+ };
124
+ /**
125
+ * Per-entry size cap RAISED to 64KB for this kind. The default
126
+ * APPLIER_MAX_ENTRY_BYTES = 8KB is SMALLER than a fat knowledge summary (a 20K summary
127
+ * alone exceeds it), so under it the longest summaries would never replicate AND would
128
+ * wedge the stream. 64KB is provably above the disclosure-minimized projection's maximum:
129
+ * summary(20k) is the dominant term — we additionally enforce a HARD post-projection
130
+ * ceiling: a record that STILL exceeds 64KB after projection is REJECTED with a named
131
+ * error (never silent-truncate, never suspect-wedge). See assertProjectionUnderCap.
132
+ */
133
+ export const KNOWLEDGE_MAX_ENTRY_BYTES = 64 * 1024;
134
+ /**
135
+ * The store-specific field names the `knowledge-record` VALUE schema OWNS (the
136
+ * unknown-field counter's allowlist). The local generated `id` AND the local `filePath`
137
+ * are DELIBERATELY ABSENT — `id` is per-machine + generated and `filePath` is a local
138
+ * artifact path; NEITHER is replicated (the recordKey keys on the content fingerprint,
139
+ * not the id; the body the filePath points at is a tracked follow-up, CMT-1416).
140
+ * `recordKey`/`hlc`/`op`/`origin`/`observed` are reserved envelope fields, never store
141
+ * fields.
142
+ */
143
+ export const KNOWLEDGE_STORE_KNOWN_FIELDS = Object.freeze([
144
+ 'title',
145
+ 'url',
146
+ 'type',
147
+ 'ingestedAt',
148
+ 'tags',
149
+ 'summary',
150
+ 'wordCount',
151
+ ]);
152
+ /** The tombstone's store-owned fields beyond the reserved envelope set. `deletedAt`
153
+ * is the only store field a delete carries. */
154
+ export const KNOWLEDGE_TOMBSTONE_KNOWN_FIELDS = Object.freeze([
155
+ 'deletedAt',
156
+ ]);
157
+ /** The full set of known store fields across BOTH op-branches (the schema's
158
+ * knownFields the registry uses for unknown-field counting — a field legal in EITHER
159
+ * branch is "known", and the branch validate() enforces which is legal for THIS op). */
160
+ const ALL_KNOWN_FIELDS = Object.freeze([
161
+ ...KNOWLEDGE_STORE_KNOWN_FIELDS,
162
+ ...KNOWLEDGE_TOMBSTONE_KNOWN_FIELDS,
163
+ ]);
164
+ // ── ISO-8601 type-clamp: ingestedAt is the load-bearing date field. On a foreign
165
+ // record it MUST validate as a real date or be normalized, so markup cannot survive
166
+ // the clamp. ──────────────────────────────────────────────────────────────────
167
+ /** Is `v` a valid ISO-8601 date string (and ONLY a date — no smuggled markup)? A
168
+ * string Date.parse rejects, or that contains an injection char (`<`, `>`, `"`), is
169
+ * not a clean ISO date. */
170
+ export function isIso8601(v) {
171
+ if (typeof v !== 'string' || v.length === 0 || v.length > 64)
172
+ return false;
173
+ const ms = Date.parse(v);
174
+ if (!Number.isFinite(ms))
175
+ return false;
176
+ if (v.includes('<') || v.includes('>') || v.includes('"'))
177
+ return false;
178
+ return true;
179
+ }
180
+ function clampFreeText(v, max = MAX_FREETEXT_LENGTH) {
181
+ if (typeof v !== 'string')
182
+ return null;
183
+ return v.length > max ? v.slice(0, max) : v;
184
+ }
185
+ /**
186
+ * The `knowledge-record` store schema — a DISCRIMINATED UNION on `op`. Strict typed
187
+ * validation on top of the envelope: reject free text beyond the known fields,
188
+ * TYPE-CLAMP every known field (`ingestedAt` ISO-8601, `type` enum, `wordCount` finite
189
+ * number, `tags`/`summary`/`title` length-clamped, `url` jailed against a path-shaped
190
+ * value) so markup cannot smuggle through a render slot that bypasses sanitize().
191
+ * Returns the validated store-specific object (known fields only), or null to reject the
192
+ * WHOLE record. PURE (no I/O, no mutation of `raw`).
193
+ *
194
+ * The envelope validator has ALREADY validated `op` ∈ {put,delete} before calling this.
195
+ * We branch on it so a tombstone `{recordKey, op:'delete', hlc, origin, deletedAt}`
196
+ * passes (only `deletedAt` is a legal store field for a delete) WITHOUT being marked
197
+ * invalid by the rich VALUE schema.
198
+ */
199
+ export const knowledgeRecordStoreSchema = {
200
+ knownFields: ALL_KNOWN_FIELDS,
201
+ validate(raw, ctx) {
202
+ const op = raw.op;
203
+ // ── DELETE (tombstone) branch. Only `deletedAt` is a legal store field; any
204
+ // VALUE field present is counted as a dropped field but does not reject — the
205
+ // tombstone's recordKey + hlc + op (envelope, already validated) carry the
206
+ // suppression. ────────────────────────────────────────────────────────────
207
+ if (op === 'delete') {
208
+ const deletedAt = isIso8601(raw.deletedAt) ? raw.deletedAt : undefined;
209
+ for (const k of Object.keys(raw)) {
210
+ if (k === 'op' || k === 'deletedAt')
211
+ continue;
212
+ if (KNOWLEDGE_STORE_KNOWN_FIELDS.includes(k))
213
+ ctx.countDroppedField();
214
+ }
215
+ return deletedAt !== undefined ? { deletedAt } : {};
216
+ }
217
+ // ── VALUE (put) branch. ──────────────────────────────────────────────────
218
+ // title — required non-empty free text, clamped.
219
+ const title = clampFreeText(raw.title);
220
+ if (title === null || title.length === 0)
221
+ return null;
222
+ // type — required enum membership (markup cannot survive an enum slot).
223
+ if (typeof raw.type !== 'string' || !KNOWLEDGE_TYPES.includes(raw.type))
224
+ return null;
225
+ const type = raw.type;
226
+ // ingestedAt — required ISO-8601. A non-date coerces to epoch-0 (tolerant-read
227
+ // posture, the manager treats catalog dates as soft) — never record-rejects, but
228
+ // markup can never survive the clamp.
229
+ const ingestedAt = isIso8601(raw.ingestedAt) ? raw.ingestedAt : new Date(0).toISOString();
230
+ // url — OPTIONAL (null when absent). A url is path-sensitive: jail it against a
231
+ // path-shaped value (defense-in-depth — a peer could smuggle a relative artifact
232
+ // path into `url`). null when absent, jailed-out, or over-cap-clamped.
233
+ let url = null;
234
+ if (typeof raw.url === 'string' && raw.url.length > 0) {
235
+ const clampedUrl = raw.url.length > MAX_URL_LENGTH ? raw.url.slice(0, MAX_URL_LENGTH) : raw.url;
236
+ url = jailStoreStringField(clampedUrl, ctx) !== null ? clampedUrl : null;
237
+ }
238
+ // summary — free text, length-clamped on receive (a flood is bounded). NEVER the
239
+ // markdown file body — only this short catalog summary crosses the wire (fork #2).
240
+ const summary = typeof raw.summary === 'string'
241
+ ? (raw.summary.length > MAX_SUMMARY_LENGTH ? raw.summary.slice(0, MAX_SUMMARY_LENGTH) : raw.summary)
242
+ : '';
243
+ // wordCount — a FINITE number (a non-finite/non-number coerces to 0; markup cannot
244
+ // survive a numeric slot).
245
+ const wordCount = typeof raw.wordCount === 'number' && Number.isFinite(raw.wordCount) ? raw.wordCount : 0;
246
+ // tags — array of clamped strings, ≤ MAX_TAGS.
247
+ const tags = Array.isArray(raw.tags)
248
+ ? raw.tags
249
+ .filter((t) => typeof t === 'string')
250
+ .slice(0, MAX_TAGS)
251
+ .map((t) => (t.length > MAX_FREETEXT_LENGTH ? t.slice(0, MAX_FREETEXT_LENGTH) : t))
252
+ : [];
253
+ return {
254
+ title,
255
+ url,
256
+ type,
257
+ ingestedAt,
258
+ tags,
259
+ summary,
260
+ wordCount,
261
+ };
262
+ },
263
+ };
264
+ // ───────────────────────────────────────────────────────────────────────────
265
+ // recordKey — the cross-machine IDENTITY SURFACE (fork #1)
266
+ // ───────────────────────────────────────────────────────────────────────────
267
+ /** Normalize a string for the content fingerprint: trim + lowercase + collapse
268
+ * internal whitespace, so trivial formatting differences across machines do not split
269
+ * the same source into two records. */
270
+ export function normalizeForKey(v) {
271
+ return String(v).trim().toLowerCase().replace(/\s+/g, ' ');
272
+ }
273
+ /**
274
+ * Derive the cross-machine-stable recordKey for a knowledge source (fork #1). A source is
275
+ * "the same" across machines by its STABLE CONTENT IDENTITY, NOT by the per-machine
276
+ * `generateId()` id — VM-A and VM-B mint different `kb_…` ids for the same article, so an
277
+ * id-keyed record could never collide them (exactly the relationship-UUID / LRN-id trap
278
+ * the prior kinds solved with a stable identity surface).
279
+ *
280
+ * The key is a deterministic, collision-resistant hash:
281
+ * sha256(normalize(url || title) + '\x1f' + normalize(type))
282
+ * hex-truncated to 32 chars (the same shape UnionReader.conflictId uses). The `\x1f`
283
+ * (unit separator) is an un-typeable delimiter so two sources cannot collide by
284
+ * straddling the field boundary.
285
+ *
286
+ * `url` is the NATURAL identity when present (the same article fetched on two machines
287
+ * has the same url even if its title was edited); when ABSENT we fall back to the title.
288
+ * Returns null when the identity anchor (url || title) is empty (a degenerate record with
289
+ * no stable identity surface — the caller skips emission; it can never collide a stranger
290
+ * by an empty key).
291
+ *
292
+ * COLLISION SAFETY: two DIFFERENT sources share a key ONLY if they share the EXACT same
293
+ * normalized (url || title) AND type — which IS the definition of "the same source".
294
+ * SPLIT-IDENTITY SAFETY: the same source derives the SAME key on both machines IFF both
295
+ * hold the same anchor + type; the normalization absorbs trivial formatting drift.
296
+ */
297
+ export function deriveKnowledgeRecordKey(title, url, type) {
298
+ const anchor = (typeof url === 'string' && url.trim().length > 0)
299
+ ? normalizeForKey(url)
300
+ : normalizeForKey(title ?? '');
301
+ const t = normalizeForKey(type ?? '');
302
+ if (anchor.length === 0)
303
+ return null;
304
+ const h = createHash('sha256');
305
+ h.update(`${anchor}\x1f${t}`);
306
+ return h.digest('hex').slice(0, 32);
307
+ }
308
+ /** The named error a record-over-cap surfaces: not silent-truncate, not suspect-wedge. */
309
+ export class KnowledgeRecordTooLargeError extends Error {
310
+ recordKey;
311
+ bytes;
312
+ constructor(recordKey, bytes) {
313
+ super(`knowledge-record ${recordKey} is ${bytes} bytes after projection — over the ${KNOWLEDGE_MAX_ENTRY_BYTES}-byte per-entry cap; not replicated`);
314
+ this.recordKey = recordKey;
315
+ this.bytes = bytes;
316
+ this.name = 'KnowledgeRecordTooLargeError';
317
+ }
318
+ }
319
+ function clampFreeTextEmit(v, max = MAX_FREETEXT_LENGTH) {
320
+ return typeof v === 'string' && v.length > max ? v.slice(0, max) : (v ?? '');
321
+ }
322
+ /**
323
+ * Build the disclosure-minimized `knowledge-record` envelope `data` for an `op:'put'`
324
+ * (fork #2). Emits ONLY the enumerated CATALOG-METADATA projection — NEVER the markdown
325
+ * file BODY (the `filePath` file), NEVER the local generated `id`, NEVER the local
326
+ * `filePath` (a local artifact path — meaningless + a mild info-leak on a peer).
327
+ * recordKey = the derived content-fingerprint identity surface (fork #1).
328
+ *
329
+ * Returns null when the record has no stable identity surface (empty url+title ⇒
330
+ * deriveKnowledgeRecordKey null — the caller skips emission). Throws
331
+ * KnowledgeRecordTooLargeError when the projection STILL exceeds the 64KB per-entry cap
332
+ * (a NAMED, surfaced rejection — never silent-truncate).
333
+ */
334
+ export function buildKnowledgeRecordData(input) {
335
+ const { record, hlc, origin, observed } = input;
336
+ const recordKey = deriveKnowledgeRecordKey(record.title, record.url, record.type);
337
+ if (recordKey === null)
338
+ return null;
339
+ const data = {
340
+ title: clampFreeTextEmit(record.title),
341
+ // url — emit as a string when present, else null (a NULL url is a legal absence; the
342
+ // local filePath is NEVER emitted — fork #2).
343
+ url: typeof record.url === 'string' && record.url.length > 0
344
+ ? clampFreeTextEmit(record.url, MAX_URL_LENGTH)
345
+ : null,
346
+ type: record.type,
347
+ ingestedAt: record.ingestedAt,
348
+ tags: Array.isArray(record.tags) ? record.tags.slice(0, MAX_TAGS).map((t) => clampFreeTextEmit(t)) : [],
349
+ summary: typeof record.summary === 'string'
350
+ ? (record.summary.length > MAX_SUMMARY_LENGTH ? record.summary.slice(0, MAX_SUMMARY_LENGTH) : record.summary)
351
+ : '',
352
+ wordCount: typeof record.wordCount === 'number' && Number.isFinite(record.wordCount) ? record.wordCount : 0,
353
+ // envelope fields (recordKey = identity surface).
354
+ recordKey,
355
+ hlc,
356
+ op: 'put',
357
+ origin,
358
+ ...(observed !== undefined ? { observed } : {}),
359
+ };
360
+ assertProjectionUnderCap(recordKey, data);
361
+ return data;
362
+ }
363
+ /** Throw KnowledgeRecordTooLargeError if the projected data serializes over the
364
+ * per-entry cap. The cap is set so a legal disclosure-minimized record can never reach
365
+ * it; this is the belt-and-suspenders named rejection. */
366
+ export function assertProjectionUnderCap(recordKey, data) {
367
+ const bytes = Buffer.byteLength(JSON.stringify(data), 'utf-8');
368
+ if (bytes > KNOWLEDGE_MAX_ENTRY_BYTES) {
369
+ throw new KnowledgeRecordTooLargeError(recordKey, bytes);
370
+ }
371
+ }
372
+ /**
373
+ * Build an `op:'delete'` TOMBSTONE `data` for a knowledge-source removal. recordKey = the
374
+ * SAME content-fingerprint identity surface the value records key on, so the tombstone
375
+ * reaches the same source's record on every machine even though the local ids differ.
376
+ * Returns null when the identity anchor (url || title) is empty (no identity surface to
377
+ * tombstone).
378
+ *
379
+ * CRITICAL (fork-adjacent): the KnowledgeManager.remove() path MUST call this for the
380
+ * removed source, else a peer re-replicates the locally-removed source forever
381
+ * (resurrection). The delete-resurrection guard lives in the merge (a later `delete` hlc
382
+ * wins over an earlier `put`).
383
+ */
384
+ export function buildKnowledgeTombstoneData(input) {
385
+ const recordKey = deriveKnowledgeRecordKey(input.title, input.url, input.type);
386
+ if (recordKey === null)
387
+ return null;
388
+ return {
389
+ deletedAt: input.deletedAt,
390
+ recordKey,
391
+ hlc: input.hlc,
392
+ op: 'delete',
393
+ origin: input.origin,
394
+ ...(input.observed !== undefined ? { observed: input.observed } : {}),
395
+ };
396
+ }
397
+ /** Reconstruct a MergedKnowledgeView from an OriginRecord (the envelope stripped). */
398
+ function viewFromOriginRecord(rec, conflicted) {
399
+ return { recordKey: rec.envelope.recordKey, origin: rec.origin, data: rec.data, conflicted };
400
+ }
401
+ /**
402
+ * Collapse a `Map<recordKey, UnionResult>` into the merged knowledge view.
403
+ * HIGH-impact-at-replication / ADVISORY-at-read contract (fork #3):
404
+ * - A resolved single value ⇒ that one view entry.
405
+ * - An OPEN concurrent conflict ⇒ BOTH (all) `put` variants as separate entries
406
+ * (append-both — both surface as ADVISORY guidance; the read NEVER suppresses a
407
+ * usable view AND NEVER BLOCKS waiting on operator resolution — a knowledge source is
408
+ * reference, not authority). A `delete` variant contributes nothing to display.
409
+ * - A delete-resolved key (every origin's latest is a tombstone) ⇒ nothing (the
410
+ * delete-resurrection guard: a later delete wins over an earlier put).
411
+ * The read is READ-ONLY: a replicated record NEVER clobbers a divergent local record —
412
+ * the local store files are never written here.
413
+ */
414
+ export function mergeUnionToKnowledge(union) {
415
+ const out = [];
416
+ for (const result of union.values()) {
417
+ if (result.conflict) {
418
+ for (const v of result.conflict.versions) {
419
+ if (v.envelope.op === 'delete')
420
+ continue;
421
+ out.push(viewFromOriginRecord(v, true));
422
+ }
423
+ continue;
424
+ }
425
+ if (result.value && result.value.envelope.op !== 'delete') {
426
+ out.push(viewFromOriginRecord(result.value, false));
427
+ }
428
+ }
429
+ return out;
430
+ }
431
+ // ───────────────────────────────────────────────────────────────────────────
432
+ // E. Foreign-record render safety — quoted untrusted data
433
+ // ───────────────────────────────────────────────────────────────────────────
434
+ /** Sanitize a string for inclusion in a context block (escape the envelope-break +
435
+ * markup vectors). */
436
+ function sanitize(s) {
437
+ return String(s).replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
438
+ }
439
+ /**
440
+ * Render a FOREIGN (replicated) knowledge record into a session-context block, wrapped in
441
+ * an explicit `<replicated-untrusted-data origin="…">` envelope so the session model
442
+ * treats it as a PEER'S knowledge source to re-ground against, never a directive. EVERY
443
+ * rendered field is escaped — there is no "trusted because machine-set" slot. A null
444
+ * `data.title` (a malformed view) yields null.
445
+ */
446
+ export function renderForeignKnowledgeContext(view) {
447
+ const d = view.data;
448
+ if (typeof d.title !== 'string' || d.title.length === 0)
449
+ return null;
450
+ const safeOrigin = sanitize(view.origin);
451
+ const lines = [
452
+ `<replicated-untrusted-data origin="${safeOrigin}">`,
453
+ `Knowledge source: ${sanitize(d.title)}`,
454
+ ];
455
+ if (typeof d.type === 'string')
456
+ lines.push(`Type: ${sanitize(d.type)}`);
457
+ if (typeof d.url === 'string' && d.url.length > 0)
458
+ lines.push(`URL: ${sanitize(d.url)}`);
459
+ if (typeof d.ingestedAt === 'string')
460
+ lines.push(`Ingested: ${sanitize(d.ingestedAt)}`);
461
+ if (Array.isArray(d.tags) && d.tags.length > 0)
462
+ lines.push(`Tags: ${d.tags.map(sanitize).join(', ')}`);
463
+ if (typeof d.wordCount === 'number')
464
+ lines.push(`Word count: ${d.wordCount}`);
465
+ if (typeof d.summary === 'string' && d.summary.length > 0)
466
+ lines.push(`Summary: ${sanitize(d.summary)}`);
467
+ lines.push('</replicated-untrusted-data>');
468
+ return lines.join('\n');
469
+ }
470
+ // ───────────────────────────────────────────────────────────────────────────
471
+ // Own-origin materialization for the union reader (mirrors WS2.2)
472
+ // ───────────────────────────────────────────────────────────────────────────
473
+ /**
474
+ * Build an OriginRecord for the OWN knowledge store (the single-origin materialization
475
+ * the union reader merges against peer replicas). recordKey = derived content-fingerprint
476
+ * identity surface; the envelope carries a SYNTHETIC own-origin HLC stamp derived
477
+ * deterministically from `ingestedAt` (physical) so the own record has a well-formed,
478
+ * stable position relative to peer records. Returns null for a degenerate record (no
479
+ * identity surface). The local `id` + `filePath` are NEVER carried into the replicated
480
+ * namespace.
481
+ */
482
+ export function knowledgeToOriginRecord(record, origin) {
483
+ const recordKey = deriveKnowledgeRecordKey(record.title, record.url, record.type);
484
+ if (recordKey === null)
485
+ return null;
486
+ const physical = Date.parse(record.ingestedAt ?? '');
487
+ const hlc = {
488
+ physical: Number.isFinite(physical) ? physical : 0,
489
+ logical: 0,
490
+ node: origin,
491
+ };
492
+ const data = {
493
+ title: record.title,
494
+ url: typeof record.url === 'string' && record.url.length > 0 ? record.url : null,
495
+ type: record.type,
496
+ ingestedAt: record.ingestedAt,
497
+ tags: Array.isArray(record.tags) ? record.tags : [],
498
+ summary: record.summary ?? '',
499
+ wordCount: typeof record.wordCount === 'number' && Number.isFinite(record.wordCount) ? record.wordCount : 0,
500
+ };
501
+ const envelope = { recordKey, hlc, op: 'put', origin };
502
+ return { origin, envelope, data };
503
+ }
504
+ // ───────────────────────────────────────────────────────────────────────────
505
+ // Registration descriptor (consumed by server.ts to register the dual registry)
506
+ // ───────────────────────────────────────────────────────────────────────────
507
+ /** The ReplicatedKindRegistry registration for the `knowledge-record` store. server.ts
508
+ * registers this onto the shared registry; the dual-registry coupling test asserts
509
+ * `kind` is also present in JOURNAL_KINDS. */
510
+ export const KNOWLEDGE_KIND_REGISTRATION = {
511
+ kind: KNOWLEDGE_RECORD_KIND,
512
+ store: KNOWLEDGE_STORE_KEY,
513
+ schema: knowledgeRecordStoreSchema,
514
+ };
515
+ /** Convenience: the store's contributing journal kinds (for rollback-unmerge's
516
+ * kindsForStore('knowledge') wiring). */
517
+ export function knowledgeContributingKinds() {
518
+ return [KNOWLEDGE_RECORD_KIND];
519
+ }
520
+ /** The store's impact tier resolver, for ReplicatedStoreReader.tierOf. Returns HIGH for
521
+ * the `knowledge` store (and HIGH for any unknown store — the conservative
522
+ * append-both-and-flag direction, never a silent clobber). */
523
+ export function knowledgeTierOf(_store) {
524
+ return KNOWLEDGE_IMPACT_TIER;
525
+ }
526
+ //# sourceMappingURL=KnowledgeReplicatedStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KnowledgeReplicatedStore.js","sourceRoot":"","sources":["../../src/core/KnowledgeReplicatedStore.ts"],"names":[],"mappings":"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"}