@sema-agent/core 5.53.0 → 5.55.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +150 -0
  2. package/dist/agents/cumulative-stats.d.ts +26 -0
  3. package/dist/agents/cumulative-stats.js +56 -0
  4. package/dist/agents/observer.d.ts +11 -7
  5. package/dist/agents/observer.js +2 -4
  6. package/dist/agents/subagent.d.ts +4 -0
  7. package/dist/agents/subagent.js +1 -1
  8. package/dist/agents/verify.d.ts +27 -3
  9. package/dist/agents/verify.js +7 -2
  10. package/dist/core/governance-codes.js +14 -0
  11. package/dist/core/hooks.js +1 -1
  12. package/dist/core/lsp-diagnostics.d.ts +19 -17
  13. package/dist/core/lsp-diagnostics.js +11 -5
  14. package/dist/core/mcp.d.ts +214 -5
  15. package/dist/core/mcp.js +315 -30
  16. package/dist/core/memory-engine/consolidation.d.ts +378 -0
  17. package/dist/core/memory-engine/consolidation.js +342 -0
  18. package/dist/core/memory-engine/dual-root.js +3 -0
  19. package/dist/core/memory-engine/engine.d.ts +237 -4
  20. package/dist/core/memory-engine/engine.js +1111 -4
  21. package/dist/core/memory-engine/export-bundle.js +9 -0
  22. package/dist/core/memory-engine/file-backend.js +27 -1
  23. package/dist/core/memory-engine/frontmatter.d.ts +20 -1
  24. package/dist/core/memory-engine/frontmatter.js +111 -0
  25. package/dist/core/memory-engine/index.d.ts +4 -2
  26. package/dist/core/memory-engine/index.js +3 -1
  27. package/dist/core/memory-engine/memory-backend-contract.js +131 -0
  28. package/dist/core/memory-engine/sync-client.js +26 -0
  29. package/dist/core/memory-engine/tools.d.ts +9 -0
  30. package/dist/core/memory-engine/tools.js +57 -13
  31. package/dist/core/memory-engine/types.d.ts +99 -0
  32. package/dist/core/memory-recall.js +4 -3
  33. package/dist/core/memory.d.ts +33 -3
  34. package/dist/core/memory.js +6 -4
  35. package/dist/core/permission-rule-model.d.ts +140 -21
  36. package/dist/core/permission-rule-model.js +76 -17
  37. package/dist/core/permission-rule-org.d.ts +4 -3
  38. package/dist/core/permission-rule-org.js +12 -3
  39. package/dist/core/permission-rules.d.ts +22 -0
  40. package/dist/core/permission-rules.js +60 -6
  41. package/dist/core/reminder-disclosure.d.ts +29 -4
  42. package/dist/core/reminder-disclosure.js +60 -12
  43. package/dist/core/runner/prepare-memory.js +7 -2
  44. package/dist/core/runner/prepare-task.d.ts +31 -1
  45. package/dist/core/runner/prepare-task.js +31 -14
  46. package/dist/core/runner/runtask.d.ts +8 -1
  47. package/dist/core/runner/runtask.js +12 -10
  48. package/dist/core/runner/session-rule-policy.js +5 -3
  49. package/dist/core/runner/synthetic-tools.js +4 -2
  50. package/dist/core/runner/turn-attachments.d.ts +16 -6
  51. package/dist/core/runner/turn-attachments.js +34 -20
  52. package/dist/core/tool-policy.d.ts +18 -0
  53. package/dist/core/tool-policy.js +19 -8
  54. package/dist/core/types.d.ts +89 -6
  55. package/dist/core/untrusted-egress.js +12 -2
  56. package/dist/core/untrusted-text.d.ts +189 -3
  57. package/dist/core/untrusted-text.js +416 -6
  58. package/dist/engine/loop/types.d.ts +7 -0
  59. package/dist/index.d.ts +2 -2
  60. package/dist/index.js +2 -2
  61. package/dist/orchestration/workflow-types.d.ts +16 -6
  62. package/dist/orchestration/workflow-types.js +10 -4
  63. package/dist/orchestration/workflow.js +32 -6
  64. package/dist/prompts/default.d.ts +12 -2
  65. package/dist/stores/file/background-agent-store.js +1 -0
  66. package/dist/stores/file/checkpoint-store.d.ts +6 -2
  67. package/dist/stores/file/checkpoint-store.js +1 -0
  68. package/dist/stores/file/fs-atomic.d.ts +151 -10
  69. package/dist/stores/file/fs-atomic.js +208 -32
  70. package/dist/stores/file/index.d.ts +26 -3
  71. package/dist/stores/file/index.js +25 -2
  72. package/dist/stores/file/shared-ledger.d.ts +40 -5
  73. package/dist/stores/file/shared-ledger.js +24 -8
  74. package/dist/stores/file/workflow-run-store.d.ts +8 -1
  75. package/dist/stores/file/workflow-run-store.js +1 -0
  76. package/dist/tools/fs/bash-readonly-classifier.d.ts +71 -0
  77. package/dist/tools/fs/bash-readonly-classifier.js +58 -47
  78. package/dist/tools/fs/index.d.ts +3 -1
  79. package/package.json +1 -1
  80. package/test/export-surface.snapshot.json +30 -1
@@ -77,6 +77,15 @@ function entryInvalid(raw, scopes) {
77
77
  return `entry ${JSON.stringify(e.id)} frontmatter.origin is malformed`;
78
78
  }
79
79
  }
80
+ if (fm.distilled !== undefined) {
81
+ const d = fm.distilled;
82
+ const inputsOk = (v) => Array.isArray(v) &&
83
+ v.length > 0 &&
84
+ v.every((row) => isRecord(row) && typeof row.id === "string" && row.id.length > 0 && typeof row.rev === "string" && row.rev.length > 0 && (row.superseded === undefined || row.superseded === true));
85
+ if (!isRecord(d) || typeof d.planId !== "string" || d.planId.length === 0 || typeof d.at !== "number" || !Number.isFinite(d.at) || typeof d.carrierRev !== "string" || d.carrierRev.length === 0 || !inputsOk(d.inputs)) {
86
+ return `entry ${JSON.stringify(e.id)} frontmatter.distilled is malformed`;
87
+ }
88
+ }
80
89
  if (ambiguousOriginRepresentation(fm)) {
81
90
  return `entry ${JSON.stringify(e.id)} carries conflicting or duplicated origin representations (ambiguous marker representation)`;
82
91
  }
@@ -4,7 +4,7 @@ import { dirname, join, relative } from "node:path";
4
4
  import { jaccardDistance, termSet } from "../memory-vector.js";
5
5
  import { MAX_MEMORY_BYTES } from "../memory.js";
6
6
  import { inlineUntrusted } from "../untrusted-text.js";
7
- import { ambiguousOriginRepresentation, committedOriginOf, computeEntryRev, entryFromFile, isValidEntryId, originEquals, parseEntryFile, serializeEntryFile } from "./frontmatter.js";
7
+ import { ambiguousOriginRepresentation, committedDistilledOf, committedOriginOf, computeEntryRev, distilledEquals, entryFromFile, isValidEntryId, originEquals, parseEntryFile, serializeEntryFile } from "./frontmatter.js";
8
8
  import { ControlPlaneCorruptError, CURSORS_FILE, QUARANTINE_DIR, CHALLENGES_FILE, IMPORT_RECEIPTS_DIR, LINEAGE_FILE, SESSION_POLLUTION_DIR, appendChallengeEvents, atomicWriteFileSync, quarantineAndTombstone, captureAndClearLineageForEntries, claimRootScope, adoptCanonicalKeyedControlDir, deriveControlPlaneDir, ensureDirExists, enqueueMemoryAnnouncement, importLatchTxnId, importLineageCommitted, importSessionPollution, isContainedIn, lineageContributionsOfSession, listSessionPollution, readChallengeEvents, readLineageRecord, registerScope, registeredScopes, releaseImportLatch, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, stageImportLatch, writeAllSync, } from "./layout.js";
9
9
  import { screenInboundEntries } from "./data-plane.js";
10
10
  import { scanMemoryFileName, scanMemoryWrite } from "./scan.js";
@@ -2403,6 +2403,15 @@ export class FileMemoryEngineBackend {
2403
2403
  });
2404
2404
  return;
2405
2405
  }
2406
+ const committedDistilled = committedDistilledOf(committedFm);
2407
+ if (committedDistilled !== undefined && !distilledEquals(committedDistilled, committedDistilledOf(entry.frontmatter))) {
2408
+ report.conflicts.push({
2409
+ op: "add",
2410
+ id: patch.id,
2411
+ reason: `distilled lineage whitewash refused: the add strips or rewrites the distilled block of a consolidation product (malformed patch refused)`,
2412
+ });
2413
+ return;
2414
+ }
2406
2415
  }
2407
2416
  if (patch.guard === "absent") {
2408
2417
  if (existingAnywhere) {
@@ -2490,6 +2499,15 @@ export class FileMemoryEngineBackend {
2490
2499
  });
2491
2500
  return;
2492
2501
  }
2502
+ const committedDistilled = committedDistilledOf(committedFm);
2503
+ if (committedDistilled !== undefined && !distilledEquals(committedDistilled, committedDistilledOf(patch.entry.frontmatter))) {
2504
+ report.conflicts.push({
2505
+ op: "update",
2506
+ id: patch.id,
2507
+ reason: `distilled lineage whitewash refused: the update strips or rewrites the distilled block of a consolidation product (malformed patch refused)`,
2508
+ });
2509
+ return;
2510
+ }
2493
2511
  }
2494
2512
  const currentRev = rowsRev(rows, patch.id) ?? found.entry.rev;
2495
2513
  if (patch.baseRev !== undefined && patch.baseRev !== currentRev) {
@@ -3696,6 +3714,14 @@ function headerOf(e, path) {
3696
3714
  rev: e.rev,
3697
3715
  sizeBytes: Buffer.byteLength(serializeEntryFile(e), "utf8"),
3698
3716
  ...(committedOriginOf(e.frontmatter) !== undefined ? { exposure: "external" } : {}),
3717
+ ...(e.frontmatter.distilled !== undefined
3718
+ ? {
3719
+ distilled: {
3720
+ carrierRev: e.frontmatter.distilled.carrierRev,
3721
+ supersedes: e.frontmatter.distilled.inputs.filter((i) => i.superseded === true).map((i) => ({ id: i.id, rev: i.rev })),
3722
+ },
3723
+ }
3724
+ : {}),
3699
3725
  };
3700
3726
  }
3701
3727
  function readSafe(path) {
@@ -1,4 +1,4 @@
1
- import { type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryOrigin } from "./types.js";
1
+ import { type MemoryEntry, type MemoryEntryDistilled, type MemoryEntryFrontmatter, type MemoryEntryOrigin } from "./types.js";
2
2
  /** A parsed entry file: frontmatter (may be absent — CC allows bare files; harvest mints them) + body. */
3
3
  export interface ParsedEntryFile {
4
4
  /** The hidden immutable id (`id:` frontmatter line), when present. */
@@ -92,5 +92,24 @@ export declare function ambiguousOriginRepresentation(fm: Pick<MemoryEntryFrontm
92
92
  * caller discloses via a report warning).
93
93
  */
94
94
  export declare function stripModelWrittenOrigin(fm: MemoryEntryFrontmatter): boolean;
95
+ /** True ⇔ `extra` carries distilled-form bytes (a non-pristine/foreign block preserved verbatim). */
96
+ export declare function hasDistilledFormExtra(fm: Pick<MemoryEntryFrontmatter, "extra">): boolean;
97
+ /** The ONE reading of an entry's committed distilled block: the typed seat or nothing. Extra-form
98
+ * bytes deliberately do NOT answer here (they mint no edge — fewer edges is the safe direction
99
+ * for a suppression carrier). Returns a defensive copy. */
100
+ export declare function committedDistilledOf(fm: Pick<MemoryEntryFrontmatter, "distilled">): MemoryEntryDistilled | undefined;
101
+ /** Deep equality over the distilled block (every member, input order included) — the immutability
102
+ * law's comparator: a rewritten carrierRev, a dropped input row or a flipped superseded flag is as
103
+ * refused as a strip. */
104
+ export declare function distilledEquals(a: MemoryEntryDistilled | undefined, b: MemoryEntryDistilled | undefined): boolean;
105
+ /**
106
+ * design/339 §1.4.2-1 — the harvest-side STRIP of model-written distilled bytes (typed field AND
107
+ * distilled-form `extra` lines): the block is minted by the consolidation plan freeze EXCLUSIVELY —
108
+ * whatever a file on the model-writable plane says about its own lineage/supersession is not
109
+ * evidence (a model-writable edge would be the delete-attack channel add-only exists to close).
110
+ * Same seat and same disclosure discipline as {@link stripModelWrittenOrigin}. MUTATES the given
111
+ * (already-copied) frontmatter; returns true ⇔ anything was stripped.
112
+ */
113
+ export declare function stripModelWrittenDistilled(fm: MemoryEntryFrontmatter): boolean;
95
114
  /** Parse a file's text directly into a full MemoryEntry (id must already be present/decided). */
96
115
  export declare function entryFromFile(text: string, id: string, slug: string, scope: string): MemoryEntry;
@@ -37,6 +37,10 @@ export function parseEntryFile(text) {
37
37
  const originRaw = [];
38
38
  let originPristine = true;
39
39
  const orig = {};
40
+ let inDistilled = false;
41
+ const distilledRaw = [];
42
+ let distilledPristine = true;
43
+ const dist = { inputs: [] };
40
44
  for (let i = 1; i < end; i++) {
41
45
  const line = lines[i] ?? "";
42
46
  const trimmed = line.trim();
@@ -47,6 +51,7 @@ export function parseEntryFile(text) {
47
51
  inMetadata = false;
48
52
  inProvenance = false;
49
53
  inOrigin = false;
54
+ inDistilled = false;
50
55
  }
51
56
  if (inMetadata) {
52
57
  const m = /^\s+type:\s*(.+?)\s*$/.exec(line);
@@ -101,6 +106,35 @@ export function parseEntryFile(text) {
101
106
  }
102
107
  continue;
103
108
  }
109
+ if (inDistilled) {
110
+ distilledRaw.push(line);
111
+ const m = /^\s+([A-Za-z][A-Za-z0-9_-]*):\s*(.*?)\s*$/.exec(line);
112
+ if (m) {
113
+ const [, k = "", v = ""] = m;
114
+ if (k === "planId" && dist.planId === undefined && /^\S+$/.test(v))
115
+ dist.planId = v;
116
+ else if (k === "at" && dist.at === undefined && ORIGIN_AT_RE.test(v))
117
+ dist.at = Number(v);
118
+ else if (k === "carrierRev" && dist.carrierRev === undefined && /^\S+$/.test(v))
119
+ dist.carrierRev = v;
120
+ else if (k === "input") {
121
+ const parts = v.split(/\s+/);
122
+ const [inId, inRev, flag, ...rest] = parts;
123
+ if (inId !== undefined && isValidEntryId(inId) && inRev !== undefined && /^\S+$/.test(inRev) && rest.length === 0 && (flag === undefined || flag === "superseded")) {
124
+ dist.inputs.push({ id: inId, rev: inRev, ...(flag === "superseded" ? { superseded: true } : {}) });
125
+ }
126
+ else {
127
+ distilledPristine = false;
128
+ }
129
+ }
130
+ else
131
+ distilledPristine = false;
132
+ }
133
+ else {
134
+ distilledPristine = false;
135
+ }
136
+ continue;
137
+ }
104
138
  if (/^provenance:\s*$/.test(trimmed)) {
105
139
  inProvenance = true;
106
140
  provRaw.push(line);
@@ -111,6 +145,11 @@ export function parseEntryFile(text) {
111
145
  originRaw.push(line);
112
146
  continue;
113
147
  }
148
+ if (/^distilled:\s*$/.test(trimmed) && distilledRaw.length === 0) {
149
+ inDistilled = true;
150
+ distilledRaw.push(line);
151
+ continue;
152
+ }
114
153
  const kv = /^([A-Za-z_][A-Za-z0-9_-]*):\s*(.*?)\s*$/.exec(trimmed);
115
154
  if (!kv || indented) {
116
155
  extra.push(line);
@@ -172,6 +211,14 @@ export function parseEntryFile(text) {
172
211
  extra.push(...originRaw);
173
212
  }
174
213
  }
214
+ if (distilledRaw.length > 0) {
215
+ if (distilledPristine && dist.planId !== undefined && typeof dist.at === "number" && atSerializationStable(dist.at) && dist.carrierRev !== undefined && dist.inputs.length > 0) {
216
+ fm.distilled = { planId: dist.planId, at: dist.at, carrierRev: dist.carrierRev, inputs: dist.inputs };
217
+ }
218
+ else {
219
+ extra.push(...distilledRaw);
220
+ }
221
+ }
175
222
  if (extra.length > 0)
176
223
  fm.extra = extra;
177
224
  let body = lines.slice(end + 1).join("\n");
@@ -200,6 +247,9 @@ export function serializeEntryFile(entry) {
200
247
  if (fm.origin !== undefined) {
201
248
  lines.push("origin:", ` taint: ${fm.origin.taint}`, ...(fm.origin.cause !== undefined ? [` cause: ${fm.origin.cause}`] : []), ` at: ${fm.origin.at}`);
202
249
  }
250
+ if (fm.distilled !== undefined) {
251
+ lines.push("distilled:", ` planId: ${fm.distilled.planId}`, ` at: ${fm.distilled.at}`, ` carrierRev: ${fm.distilled.carrierRev}`, ...fm.distilled.inputs.map((i) => ` input: ${i.id} ${i.rev}${i.superseded === true ? " superseded" : ""}`));
252
+ }
203
253
  lines.push(FM_FENCE, "");
204
254
  const body = entry.body.replace(/\s+$/, "");
205
255
  return `${lines.join("\n")}${body}${body ? "\n" : ""}`;
@@ -220,6 +270,7 @@ export function computeEntryRev(entry) {
220
270
  ? [fm.trust ?? null, fm.provenance !== undefined ? [fm.provenance.kind, fm.provenance.path, fm.provenance.contentHash, fm.provenance.ingestedAt] : null]
221
271
  : []),
222
272
  ...(canonicalOrigin !== undefined ? [["origin", canonicalOrigin.taint, canonicalOrigin.cause ?? null, canonicalOrigin.at]] : []),
273
+ ...(fm.distilled !== undefined ? [["distilled", fm.distilled.planId, fm.distilled.at, fm.distilled.inputs.map((i) => [i.id, i.rev, i.superseded === true ? 1 : 0])]] : []),
223
274
  ]);
224
275
  return createHash("sha256").update(canonical, "utf8").digest("hex").slice(0, 16);
225
276
  }
@@ -325,6 +376,66 @@ export function stripModelWrittenOrigin(fm) {
325
376
  }
326
377
  return stripped;
327
378
  }
379
+ const DISTILLED_FORM_LINE_RE = /^\s*distilled\s*:/;
380
+ export function hasDistilledFormExtra(fm) {
381
+ return fm.extra !== undefined && fm.extra.some((line) => DISTILLED_FORM_LINE_RE.test(line));
382
+ }
383
+ export function committedDistilledOf(fm) {
384
+ const d = fm.distilled;
385
+ if (d === undefined)
386
+ return undefined;
387
+ return { planId: d.planId, at: d.at, carrierRev: d.carrierRev, inputs: d.inputs.map((i) => ({ id: i.id, rev: i.rev, ...(i.superseded === true ? { superseded: true } : {}) })) };
388
+ }
389
+ export function distilledEquals(a, b) {
390
+ if (a === undefined || b === undefined)
391
+ return a === b;
392
+ if (a.planId !== b.planId || a.at !== b.at || a.carrierRev !== b.carrierRev || a.inputs.length !== b.inputs.length)
393
+ return false;
394
+ for (let i = 0; i < a.inputs.length; i++) {
395
+ const x = a.inputs[i];
396
+ const y = b.inputs[i];
397
+ if (x.id !== y.id || x.rev !== y.rev || (x.superseded === true) !== (y.superseded === true))
398
+ return false;
399
+ }
400
+ return true;
401
+ }
402
+ function partitionDistilledLines(extra) {
403
+ const kept = [];
404
+ let removedAny = false;
405
+ let inBlock = false;
406
+ for (const line of extra) {
407
+ if (DISTILLED_FORM_LINE_RE.test(line)) {
408
+ inBlock = /^\s*distilled\s*:\s*$/.test(line);
409
+ removedAny = true;
410
+ continue;
411
+ }
412
+ if (inBlock && /^\s/.test(line)) {
413
+ removedAny = true;
414
+ continue;
415
+ }
416
+ inBlock = false;
417
+ kept.push(line);
418
+ }
419
+ return { kept, removedAny };
420
+ }
421
+ export function stripModelWrittenDistilled(fm) {
422
+ let stripped = false;
423
+ if (fm.distilled !== undefined) {
424
+ delete fm.distilled;
425
+ stripped = true;
426
+ }
427
+ if (fm.extra !== undefined) {
428
+ const { kept, removedAny } = partitionDistilledLines(fm.extra);
429
+ if (removedAny) {
430
+ stripped = true;
431
+ if (kept.length > 0)
432
+ fm.extra = kept;
433
+ else
434
+ delete fm.extra;
435
+ }
436
+ }
437
+ return stripped;
438
+ }
328
439
  export function entryFromFile(text, id, slug, scope) {
329
440
  const parsed = parseEntryFile(text);
330
441
  const entry = { id, slug, frontmatter: parsed.frontmatter, body: parsed.body, rev: "", scope };
@@ -1,4 +1,4 @@
1
- export { MemoryEngine, buildMemoryInstruction, truncateIndex, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, memoryRecallDisciplineSegment, entryFileHeadCarriesOrigin, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, renderAnnouncements, type MemoryEngineOptions, type MemoryInjection, type EntryProvenanceAccount, } from "./engine.js";
1
+ export { MemoryEngine, buildMemoryInstruction, truncateIndex, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, memoryRecallDisciplineSegment, entryFileHeadCarriesOrigin, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, renderAnnouncements, type MemoryEngineOptions, type MemoryInjection, type EntryProvenanceAccount, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationRefusedNotice, type ConsolidationCommitReceipt, type ConsolidationReconcileReport, type ConsolidationResolveReceipt, type ConsolidationPlanSummary, } from "./engine.js";
2
2
  export { MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type CleanMemorySearchHit, type ExposedMemorySearchHit, type MemoryGetDetails, } from "./tools.js";
3
3
  export { MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, MEMORY_PROVENANCE_RECALL_SENTENCE, MEMORY_PROVENANCE_SEARCH_SENTENCE, memoryExposureIndexRow, parseMemoryExposureIndexRow, } from "./provenance-wording.js";
4
4
  export { scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE } from "./scan.js";
@@ -7,8 +7,10 @@ export { computeBundleSectionHashes, computeMemoryBundleHash, memoryBundleInvali
7
7
  export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, claimRootScope, rootScopeOf, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAppendResult, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, } from "./layout.js";
8
8
  export { readV2HeaderHints, isInstructionEntry, type V2HeaderHints } from "./header-hints.js";
9
9
  export { parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, committedOriginOf, originEquals, ambiguousOriginRepresentation, type ParsedEntryFile } from "./frontmatter.js";
10
+ export { committedDistilledOf, distilledEquals } from "./frontmatter.js";
11
+ export { CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, type ConsolidationGateRow, type ConsolidationIntent, type ConsolidationIntentCredentialRow, type ConsolidationLeaseSeat, type ConsolidationProductProposal, type ConsolidationProposal, type MemoryConsolidationOptions, } from "./consolidation.js";
10
12
  export { MEMORY_ORIGIN_CAUSES } from "./types.js";
11
- export type { MemoryBackend, MemoryEntry, MemoryEntryFrontmatter, MemoryEntryOrigin, MemoryOriginCause, MemoryEntryHeader, ScoredMemoryEntry, NotePatch, PatchReport, MaterializedFile, MemorySessionHandle, HarvestReport, HarvestRejection, HarvestRejectionCode, MemoryAnnouncement, ScanFinding, } from "./types.js";
13
+ export type { MemoryBackend, MemoryEntry, MemoryEntryFrontmatter, MemoryEntryOrigin, MemoryOriginCause, MemoryEntryDistilled, MemoryEntryDistilledInput, MemoryEntryHeader, ScoredMemoryEntry, NotePatch, PatchReport, MaterializedFile, MemorySessionHandle, HarvestReport, HarvestRejection, HarvestRejectionCode, MemoryAnnouncement, ScanFinding, } from "./types.js";
12
14
  export { memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, } from "./memory-backend-contract.js";
13
15
  export { SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, type ParsedScopeKey, } from "./scope-contract.js";
14
16
  export { migrateScope, type MigrateScopeReport } from "./migrate.js";
@@ -1,4 +1,4 @@
1
- export { MemoryEngine, buildMemoryInstruction, truncateIndex, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, memoryRecallDisciplineSegment, entryFileHeadCarriesOrigin, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, renderAnnouncements, } from "./engine.js";
1
+ export { MemoryEngine, buildMemoryInstruction, truncateIndex, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, memoryRecallDisciplineSegment, entryFileHeadCarriesOrigin, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, renderAnnouncements, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationRefusedNotice, } from "./engine.js";
2
2
  export { MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, } from "./tools.js";
3
3
  export { MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, MEMORY_PROVENANCE_RECALL_SENTENCE, MEMORY_PROVENANCE_SEARCH_SENTENCE, memoryExposureIndexRow, parseMemoryExposureIndexRow, } from "./provenance-wording.js";
4
4
  export { scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE } from "./scan.js";
@@ -7,6 +7,8 @@ export { computeBundleSectionHashes, computeMemoryBundleHash, memoryBundleInvali
7
7
  export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, claimRootScope, rootScopeOf, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, } from "./layout.js";
8
8
  export { readV2HeaderHints, isInstructionEntry } from "./header-hints.js";
9
9
  export { parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, committedOriginOf, originEquals, ambiguousOriginRepresentation } from "./frontmatter.js";
10
+ export { committedDistilledOf, distilledEquals } from "./frontmatter.js";
11
+ export { CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, } from "./consolidation.js";
10
12
  export { MEMORY_ORIGIN_CAUSES } from "./types.js";
11
13
  export { memoryBackendContract, assertMemoryBackendSearchEquivalence, } from "./memory-backend-contract.js";
12
14
  export { SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, } from "./scope-contract.js";
@@ -513,6 +513,137 @@ export async function memoryBackendContract(hooks) {
513
513
  assert.deepStrictEqual((await b.getByIds([m0.id]))[0]?.frontmatter.origin, origin);
514
514
  assert.strictEqual((await b.getByIds([p0.id]))[0]?.frontmatter.trust, "untrusted");
515
515
  });
516
+ const distilledEntry = (id, scope, slug, body, inputs) => {
517
+ const e = { id, scope, slug, frontmatter: { name: slug, distilled: { planId: "plan-c35-0001", at: 1_700_000_000_000, carrierRev: "", inputs } }, body, rev: "" };
518
+ e.rev = computeEntryRev(e);
519
+ e.frontmatter.distilled.carrierRev = e.rev;
520
+ return e;
521
+ };
522
+ defer("design/339 c35: distilled round-trips deep-equal (typed block, superseded rows); rev is conditional — no-block entries keep their historical rev, carrierRev never participates", async () => {
523
+ const b = await hooks.make();
524
+ const inputs = [
525
+ { id: "id-input-0001", rev: "aaaaaaaaaaaaaaaa", superseded: true },
526
+ { id: "id-input-0002", rev: "bbbbbbbbbbbbbbbb" },
527
+ ];
528
+ const p = distilledEntry("id-prod-00001", "s1", "product", "the distilled abstraction", inputs);
529
+ const rep = await b.applyPatches([{ op: "add", id: p.id, entry: p, guard: "absent" }]);
530
+ assert.deepStrictEqual(rep.conflicts, []);
531
+ const [got] = await b.getByIds([p.id]);
532
+ assert.deepStrictEqual(got?.frontmatter.distilled, p.frontmatter.distilled, "the distilled block must round-trip deep-equal through storage");
533
+ const bare = { id: p.id, scope: p.scope, slug: p.slug, frontmatter: { name: p.frontmatter.name }, body: p.body, rev: "" };
534
+ bare.rev = computeEntryRev(bare);
535
+ assert.notStrictEqual(bare.rev, p.rev, "the distilled block participates in the rev");
536
+ const otherAnchor = { ...p, frontmatter: { ...p.frontmatter, distilled: { ...p.frontmatter.distilled, carrierRev: "different-anchor" } } };
537
+ assert.strictEqual(computeEntryRev(otherAnchor), p.rev, "carrierRev is outside the rev tuple");
538
+ const plainRow = entry("id-plain-0001", "s1", "plain", "plain body", { name: "Plain" });
539
+ await b.applyPatches([{ op: "add", id: plainRow.id, entry: plainRow }]);
540
+ assert.strictEqual((await b.getByIds([plainRow.id]))[0]?.rev, plainRow.rev);
541
+ });
542
+ defer("design/339 c36: distilled immutability across update strip/member rewrite, plain re-add, guard add and same-batch delete+re-add ⇒ /malformed patch refused/; committed tombstone is the legal exit", async () => {
543
+ const b = await hooks.make();
544
+ const p = distilledEntry("id-prod-00002", "s1", "prod-immutable", "product body", [{ id: "id-input-0003", rev: "cccccccccccccccc", superseded: true }]);
545
+ await b.applyPatches([{ op: "add", id: p.id, entry: p, guard: "absent" }]);
546
+ const expectMalformed = async (patch) => {
547
+ const rep = await b.applyPatches([patch]);
548
+ assert.strictEqual(rep.applied.filter((a) => a.id === p.id && a.op !== "delete").length, 0, "the touching op must not apply");
549
+ const bad = rep.conflicts.find((c) => c.id === p.id);
550
+ assert.match(bad?.reason ?? "", /malformed patch refused/);
551
+ const [committed] = await b.getByIds([p.id]);
552
+ assert.deepStrictEqual(committed?.frontmatter.distilled, p.frontmatter.distilled, "the committed block survives the refused op");
553
+ };
554
+ const stripped = { ...p, frontmatter: { name: p.frontmatter.name }, body: "edited" };
555
+ stripped.rev = computeEntryRev(stripped);
556
+ await expectMalformed({ op: "update", id: p.id, entry: stripped, baseRev: p.rev });
557
+ const flipped = { ...p, frontmatter: { ...p.frontmatter, distilled: { ...p.frontmatter.distilled, inputs: [{ id: "id-input-0003", rev: "cccccccccccccccc" }] } } };
558
+ flipped.rev = computeEntryRev(flipped);
559
+ await expectMalformed({ op: "update", id: p.id, entry: flipped, baseRev: p.rev });
560
+ const reanchored = { ...p, frontmatter: { ...p.frontmatter, distilled: { ...p.frontmatter.distilled, carrierRev: "forged-anchor-0001" } } };
561
+ reanchored.rev = computeEntryRev(reanchored);
562
+ assert.strictEqual(reanchored.rev, p.rev, "precondition: the carrierRev rewrite moves no rev");
563
+ await expectMalformed({ op: "update", id: p.id, entry: reanchored, baseRev: p.rev });
564
+ const bareAdd = { id: p.id, scope: p.scope, slug: p.slug, frontmatter: { name: p.frontmatter.name }, body: p.body, rev: "" };
565
+ bareAdd.rev = computeEntryRev(bareAdd);
566
+ await expectMalformed({ op: "add", id: p.id, entry: bareAdd });
567
+ await expectMalformed({ op: "add", id: p.id, entry: bareAdd, guard: "absent" });
568
+ const rep = await b.applyPatches([
569
+ { op: "delete", id: p.id, baseRev: p.rev },
570
+ { op: "add", id: p.id, entry: bareAdd },
571
+ ]);
572
+ assert.match(rep.conflicts.find((c) => c.op === "add")?.reason ?? "", /malformed patch refused/);
573
+ const rep2 = await b.applyPatches([{ op: "add", id: p.id, entry: bareAdd }]);
574
+ assert.deepStrictEqual(rep2.conflicts, []);
575
+ assert.strictEqual((await b.getByIds([p.id]))[0]?.frontmatter.distilled, undefined);
576
+ });
577
+ defer("design/339 c37: PRECEDENCE — a distilled strip riding a STALE baseRev still answers the malformed refusal, never the rev-mismatch conflict", async () => {
578
+ const b = await hooks.make();
579
+ const p = distilledEntry("id-prod-00003", "s1", "prod-precedence", "v1", [{ id: "id-input-0004", rev: "dddddddddddddddd", superseded: true }]);
580
+ await b.applyPatches([{ op: "add", id: p.id, entry: p, guard: "absent" }]);
581
+ const v2 = { ...p, body: "v2", frontmatter: { ...p.frontmatter, distilled: { ...p.frontmatter.distilled } } };
582
+ v2.rev = computeEntryRev(v2);
583
+ const repOk = await b.applyPatches([{ op: "update", id: p.id, entry: v2, baseRev: p.rev }]);
584
+ assert.deepStrictEqual(repOk.conflicts, []);
585
+ const stripped = { id: p.id, scope: p.scope, slug: p.slug, frontmatter: { name: p.frontmatter.name }, body: "v3", rev: "" };
586
+ stripped.rev = computeEntryRev(stripped);
587
+ const rep = await b.applyPatches([{ op: "update", id: p.id, entry: stripped, baseRev: p.rev }]);
588
+ assert.strictEqual(rep.applied.length, 0);
589
+ assert.match(rep.conflicts[0]?.reason ?? "", /malformed patch refused/);
590
+ assert.doesNotMatch(rep.conflicts[0]?.reason ?? "", /rev mismatch/);
591
+ });
592
+ defer("design/339 c38: the distilled fact rides BOTH header faces (listHeaders + search) as carrierRev + the superseded-row projection; block-free entries carry none on either face", async () => {
593
+ const b = await hooks.make();
594
+ const p = distilledEntry("id-prod-00004", "s1", "prod-header", "searchable distilled kumquat", [
595
+ { id: "id-input-0005", rev: "eeeeeeeeeeeeeeee", superseded: true },
596
+ { id: "id-input-0006", rev: "ffffffffffffffff" },
597
+ ]);
598
+ const plain = entry("id-plain-0001", "s1", "plain", "searchable plain kumquat");
599
+ await b.applyPatches([
600
+ { op: "add", id: p.id, entry: p, guard: "absent" },
601
+ { op: "add", id: plain.id, entry: plain },
602
+ ]);
603
+ const headers = await b.listHeaders(["s1"]);
604
+ const ph = headers.find((h) => h.id === p.id);
605
+ assert.deepStrictEqual(ph?.distilled, { carrierRev: p.rev, supersedes: [{ id: "id-input-0005", rev: "eeeeeeeeeeeeeeee" }] });
606
+ assert.strictEqual(headers.find((h) => h.id === plain.id)?.distilled, undefined);
607
+ const hits = await b.search("kumquat", ["s1"], { limit: 10 });
608
+ const psh = hits.find((h) => h.id === p.id);
609
+ assert.deepStrictEqual(psh?.distilled, { carrierRev: p.rev, supersedes: [{ id: "id-input-0005", rev: "eeeeeeeeeeeeeeee" }] }, "search reports the same committed fact");
610
+ assert.strictEqual(hits.find((h) => h.id === plain.id)?.distilled, undefined);
611
+ });
612
+ defer("design/339 c39: the plan-replay add spelling — a guard-absent re-add of the identical product is idempotent (one row, no overwrite, no conflict); a different-rev occupant answers add_guard_absent_conflict with currentRev", async () => {
613
+ const b = await hooks.make();
614
+ const p = distilledEntry("id-prod-00005", "s1", "prod-replay", "replayed product", [{ id: "id-input-0007", rev: "abababababababab", superseded: true }]);
615
+ await b.applyPatches([{ op: "add", id: p.id, entry: p, guard: "absent" }]);
616
+ const replay = await b.applyPatches([{ op: "add", id: p.id, entry: p, guard: "absent" }]);
617
+ assert.deepStrictEqual(replay.conflicts, [], "the identical replay is a no-op apply, never a conflict");
618
+ const rows = await b.getByIds([p.id]);
619
+ assert.strictEqual(rows.length, 1, "one row — a replay must not mint a duplicate");
620
+ assert.strictEqual(rows[0]?.rev, p.rev);
621
+ assert.strictEqual((await b.listHeaders(["s1"])).filter((h) => h.id === p.id).length, 1, "one projection");
622
+ const foreign = { ...p, body: "foreign occupant", frontmatter: { ...p.frontmatter, distilled: { ...p.frontmatter.distilled } } };
623
+ foreign.rev = computeEntryRev(foreign);
624
+ await b.applyPatches([{ op: "update", id: p.id, entry: foreign, baseRev: p.rev }]);
625
+ const conflicted = await b.applyPatches([{ op: "add", id: p.id, entry: p, guard: "absent" }]);
626
+ assert.strictEqual(conflicted.applied.length, 0);
627
+ assert.match(conflicted.conflicts[0]?.reason ?? "", /add_guard_absent_conflict/);
628
+ assert.strictEqual(conflicted.conflicts[0]?.currentRev, foreign.rev);
629
+ assert.strictEqual((await b.getByIds([p.id]))[0]?.body.replace(/\s+$/, ""), "foreign occupant", "the occupant survives");
630
+ });
631
+ defer("design/339 c40: the directed-arm judgment face — after an update-replay conflict, the reported currentRev and the committed read both answer the planned post-state's rev (already-applied is judgeable), and the judgment read is side-effect-free", async () => {
632
+ const b = await hooks.make();
633
+ const v1 = entry("id-directed-01", "s1", "directed", "v1");
634
+ await b.applyPatches([{ op: "add", id: v1.id, entry: v1 }]);
635
+ const terminal = entry("id-directed-01", "s1", "directed", "the intended terminal state");
636
+ const plannedPostRev = terminal.rev;
637
+ const first = await b.applyPatches([{ op: "update", id: v1.id, entry: terminal, baseRev: v1.rev }]);
638
+ assert.deepStrictEqual(first.conflicts, []);
639
+ const replay = await b.applyPatches([{ op: "update", id: v1.id, entry: terminal, baseRev: v1.rev }]);
640
+ assert.strictEqual(replay.applied.length, 0);
641
+ assert.strictEqual(replay.conflicts[0]?.currentRev, plannedPostRev, "the conflict's currentRev answers the already-applied judgment");
642
+ const read1 = await b.getByIds([v1.id]);
643
+ const read2 = await b.getByIds([v1.id]);
644
+ assert.strictEqual(read1[0]?.rev, plannedPostRev);
645
+ assert.strictEqual(read2[0]?.rev, plannedPostRev, "the judgment read advances no rev");
646
+ });
516
647
  defer("consolidation cursor round-trips per scope; unset → undefined", async () => {
517
648
  const b = await hooks.make();
518
649
  assert.strictEqual(await b.getConsolidationCursor("s1"), undefined);
@@ -89,6 +89,18 @@ function parseMemorySyncResponse(raw, scope, peer) {
89
89
  (originWire["cause"] !== undefined && !(typeof originWire["cause"] === "string" && MEMORY_ORIGIN_CAUSES.includes(originWire["cause"]))))) {
90
90
  fail('entry.frontmatter.origin must be { taint: "external", cause?, at } with a known cause when present');
91
91
  }
92
+ const distilledWire = fm["distilled"];
93
+ if (distilledWire !== undefined &&
94
+ (!isRecord(distilledWire) ||
95
+ !isNonEmptyString(distilledWire["planId"]) ||
96
+ typeof distilledWire["at"] !== "number" ||
97
+ !Number.isFinite(distilledWire["at"]) ||
98
+ !isNonEmptyString(distilledWire["carrierRev"]) ||
99
+ !(Array.isArray(distilledWire["inputs"]) &&
100
+ distilledWire["inputs"].length > 0 &&
101
+ distilledWire["inputs"].every((row) => isRecord(row) && isNonEmptyString(row["id"]) && isNonEmptyString(row["rev"]) && (row["superseded"] === undefined || row["superseded"] === true))))) {
102
+ fail("entry.frontmatter.distilled must be { planId, at, carrierRev, inputs: [{ id, rev, superseded? }, …] } when present");
103
+ }
92
104
  const extraRaw = fm["extra"];
93
105
  if (Array.isArray(extraRaw) && extraRaw.every((s) => typeof s === "string")) {
94
106
  const pickedOrigin = originWire !== undefined
@@ -133,6 +145,20 @@ function parseMemorySyncResponse(raw, scope, peer) {
133
145
  },
134
146
  }
135
147
  : {}),
148
+ ...(distilledWire !== undefined
149
+ ? {
150
+ distilled: {
151
+ planId: distilledWire["planId"],
152
+ at: distilledWire["at"],
153
+ carrierRev: distilledWire["carrierRev"],
154
+ inputs: distilledWire["inputs"].map((row) => ({
155
+ id: row["id"],
156
+ rev: row["rev"],
157
+ ...(row["superseded"] === true ? { superseded: true } : {}),
158
+ })),
159
+ },
160
+ }
161
+ : {}),
136
162
  ...(fm["extra"] !== undefined ? { extra: [...fm["extra"]] } : {}),
137
163
  },
138
164
  });
@@ -121,6 +121,9 @@ export interface CleanMemorySearchHit {
121
121
  mtimeMs: number;
122
122
  sizeBytes: number;
123
123
  exposure?: never;
124
+ /** design/339 §3.4 — present ⇔ this hit is SUPERSEDED (retrieved via `includeSuperseded`; the
125
+ * default face filters such hits out) — the value is the standing carrier entry's id. */
126
+ supersededBy?: string;
124
127
  }
125
128
  /**
126
129
  * design/336 §5.2 — a MARKED hit is an OPAQUE HANDLE: id/scope/score/age/size plus the exposure
@@ -140,6 +143,8 @@ export interface ExposedMemorySearchHit {
140
143
  slug?: never;
141
144
  name?: never;
142
145
  description?: never;
146
+ /** design/339 §3.4 — see {@link CleanMemorySearchHit.supersededBy} (same seat on the handle shape). */
147
+ supersededBy?: string;
143
148
  }
144
149
  /**
145
150
  * The search hit union (design/336 B5 — a DISCRIMINATED union on `exposure`, deliberately not an
@@ -181,6 +186,10 @@ export interface MemoryGetDetails {
181
186
  /** design/336 §5.3 — present on an `ok` delivery of a MARKED entry under `provenance: "carry"`
182
187
  * (the structured half of the banner). Absent under "off" and for unmarked entries. */
183
188
  exposure?: "external";
189
+ /** design/339 §3.4 — present on an `ok` delivery of a SUPERSEDED entry (mode-free, data-driven):
190
+ * the standing carrier entry's id (the disclosure note's structured half). Delivery proceeds —
191
+ * supersession is disclosure/ordering, never withholding. */
192
+ supersededBy?: string;
184
193
  }
185
194
  /** Cut `text` to at most `maxBytes` UTF-8 bytes on a CODE POINT boundary (a byte-wise slice would
186
195
  * strand half a character), reporting how many bytes were dropped. Unchanged text reports 0.