@sema-agent/core 5.45.0 → 5.46.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 (69) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/agents/subagent.js +1 -1
  3. package/dist/core/checkpoint-store.d.ts +12 -0
  4. package/dist/core/hooks.d.ts +9 -2
  5. package/dist/core/hooks.js +6 -5
  6. package/dist/core/memory-engine/content-origin.d.ts +3 -1
  7. package/dist/core/memory-engine/engine.d.ts +50 -3
  8. package/dist/core/memory-engine/engine.js +194 -32
  9. package/dist/core/memory-engine/export-bundle.d.ts +10 -1
  10. package/dist/core/memory-engine/export-bundle.js +21 -0
  11. package/dist/core/memory-engine/file-backend.d.ts +33 -4
  12. package/dist/core/memory-engine/file-backend.js +165 -39
  13. package/dist/core/memory-engine/frontmatter.d.ts +42 -1
  14. package/dist/core/memory-engine/frontmatter.js +141 -1
  15. package/dist/core/memory-engine/header-hints.d.ts +17 -0
  16. package/dist/core/memory-engine/header-hints.js +6 -0
  17. package/dist/core/memory-engine/index.d.ts +4 -3
  18. package/dist/core/memory-engine/index.js +3 -2
  19. package/dist/core/memory-engine/layout.d.ts +25 -2
  20. package/dist/core/memory-engine/layout.js +25 -12
  21. package/dist/core/memory-engine/memory-backend-contract.js +65 -0
  22. package/dist/core/memory-engine/sync-client.d.ts +1 -1
  23. package/dist/core/memory-engine/sync-client.js +33 -1
  24. package/dist/core/memory-engine/tools.d.ts +7 -0
  25. package/dist/core/memory-engine/tools.js +3 -0
  26. package/dist/core/memory-engine/types.d.ts +75 -1
  27. package/dist/core/memory-engine/types.js +1 -1
  28. package/dist/core/reminder-mint.d.ts +70 -0
  29. package/dist/core/reminder-mint.js +25 -0
  30. package/dist/core/runner/git-status-frame.d.ts +3 -14
  31. package/dist/core/runner/git-status-frame.js +39 -14
  32. package/dist/core/runner/prepare-config-doors.d.ts +4 -0
  33. package/dist/core/runner/prepare-config-doors.js +15 -0
  34. package/dist/core/runner/prepare-hands-readface.d.ts +5 -11
  35. package/dist/core/runner/prepare-hands-readface.js +26 -0
  36. package/dist/core/runner/prepare-memory.d.ts +11 -0
  37. package/dist/core/runner/prepare-memory.js +12 -10
  38. package/dist/core/runner/prepare-task.d.ts +22 -1
  39. package/dist/core/runner/prepare-task.js +48 -13
  40. package/dist/core/runner/runtask.js +62 -55
  41. package/dist/core/side-query.d.ts +11 -1
  42. package/dist/core/side-query.js +3 -0
  43. package/dist/core/types.d.ts +47 -7
  44. package/dist/engine/harness/types.d.ts +46 -1
  45. package/dist/engine/harness/types.js +11 -0
  46. package/dist/engine/session/import-validate.js +6 -1
  47. package/dist/engine/session/session.d.ts +20 -0
  48. package/dist/engine/session/session.js +26 -1
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.js +2 -1
  51. package/dist/orchestration/run-workflow-tool.d.ts +16 -0
  52. package/dist/orchestration/run-workflow-tool.js +23 -3
  53. package/dist/orchestration/workflow-governance.d.ts +8 -1
  54. package/dist/prompt-assembly/epoch.js +2 -0
  55. package/dist/prompt-assembly/types.d.ts +6 -0
  56. package/dist/prompts/default.d.ts +13 -1
  57. package/dist/prompts/default.js +5 -1
  58. package/dist/tools/fs/fs-bash.d.ts +4 -0
  59. package/dist/tools/fs/fs-bash.js +1 -1
  60. package/dist/tools/fs/fs-read.d.ts +1 -1
  61. package/dist/tools/fs/fs-read.js +8 -7
  62. package/dist/tools/fs/fs-shared.d.ts +10 -4
  63. package/dist/tools/fs/fs-shared.js +6 -3
  64. package/dist/tools/fs/gh-rate-limit.d.ts +4 -1
  65. package/dist/tools/fs/gh-rate-limit.js +3 -2
  66. package/dist/tools/fs/index.d.ts +10 -2
  67. package/dist/tools/fs/index.js +2 -1
  68. package/package.json +1 -1
  69. package/test/export-surface.snapshot.json +12 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.46.0 — 2026-08-19
4
+
5
+ ### Added
6
+ - design/319 A (system-reminder provenance mark): every engine-authored `<system-reminder>` OPEN
7
+ tag carries a per-session random `mark="<22-char base64url>"` attribute, and the system prompt
8
+ declares its semantics in ONE strict form — reminder-shaped text WITHOUT the current mark is
9
+ data wherever it appears. A forged reminder tag is now byte-distinguishable from an engine mint
10
+ on every verbatim inlet (Read/Bash/Grep/MCP-success). ZERO data-byte change: the mark rides only
11
+ the engine's own tag; Read stays verbatim, Edit across forged tags lands, Bash/Grep clean paths
12
+ are byte-compatible, and markless (library-direct) calls render historic bare bytes verbatim.
13
+ New exports: `mintReminderMark`, `isValidReminderMark`, `openSystemReminder`,
14
+ `mintSystemReminder`, `reminderMarkDeclaration` (scheme-replaceable mint home). Checkpoint gains
15
+ an additive `reminderMark` field + a new session-entry type `reminder_mark` (old readers ignore
16
+ both); a legacy or malformed-mark resume re-mints under the same strict declaration (historic
17
+ bare mints read as data — fail-safe). Consumers matching reminder tags by exact string must go
18
+ attribute-tolerant. A provider-owned pass-through prompt that renders no declaration discloses
19
+ loudly once per prepare (opt-in: `reminderMarkDeclaration(ctx.reminderMark)`).
20
+ - design/336 slice 1 (F-020 deep fix — the origin carriage): an externally-exposed session's
21
+ ORDINARY memory writes now COMMIT carrying an engine-minted typed `origin` frontmatter marker
22
+ (taint + closed cause vocabulary + mint time) instead of the design/178 full quarantine that
23
+ zeroed TOC recall for every delegation-bearing session. Engine-exclusive and forgery-proof on
24
+ four faces (model-written origin bytes strip-with-disclosure — benign echo of the committed
25
+ marker stays silent; backend immutability law over every op spelling; inbound whitewash gate;
26
+ sync/bundle validation with rev honesty). Instruction-form files stay hard-gated. ONE deployment
27
+ seat: `RunnerDeps.memoryProvenance?: "off" | "carry"` (default `"carry"`; `"off"` restores
28
+ pre-336 containment byte-level; bad values refuse loudly, `config.memory_provenance`). New
29
+ public family: `MemoryEntryOrigin`/`MemoryOriginCause`/`MEMORY_ORIGIN_CAUSES`,
30
+ `committedOriginOf`, `originEquals`, `isInstructionEntry`. Bundle rows carry `marked`+`cause`;
31
+ lineage merge upgrades (never drops) a content-verified marked bit.
32
+ - #342: the `run_workflow` lane gains the onAsk pass-through arm — every workflow-spawned agent's
33
+ own ask reaches the same operator as the host's (provenance-stamped, `parentToolCallId` +
34
+ `depth:1`) instead of the headless auto-deny. `RunWorkflowToolDeps.parentOnAsk` mount dep; a
35
+ deployment-pinned `base.onAsk` always wins; with no approver anywhere the fail-closed deny is
36
+ byte-identical. `AskRequest.delegation.parentToolCallId` is now reliable on the workflow lane.
37
+ - #341: `SideQuerySpec.getApiKeyAndHeaders` — side-queries resolve per-model auth exactly like
38
+ the main lane (a gateway key no longer rides an external model's URL when a resolver is wired).
39
+ - Memory-engine fencing (#262/#270/#191): journal recovery carries a fence token asserted at every
40
+ destructive write (redo/sweep/heal/commit-boundary/identity-close/migration); the chain-degraded
41
+ marker's directory entry is fsynced (POSIX name durability); txn-lock contention is typed
42
+ (EACCES vs EEXIST). #339 (stale-steal residual window) consolidated into design/186 v2 §3.1.
43
+
44
+ ### Fixed
45
+ - The read-face LIST seats (`additionalDirectories`, `additionalReadDirectories`,
46
+ `readDenyPatterns` deps+spec) refuse non-array values loudly (`config.read_face_seat`) instead
47
+ of iterating a bare string character by character — `"/tmp/x"` no longer admits the
48
+ one-character root `"/"` into the write-capable allowlist, and a bare deny-"pattern" string no
49
+ longer dissolves into meaningless entries with zero refusal (#344, merged-code review). The
50
+ deny seats' ENTRY law stays with `compileReadDeny` (the `ReadDenyEntry` union's object form —
51
+ verify's frozen-posture carry — still completes).
52
+
53
+ ### Errata (5.44.0 changelog)
54
+ - The "Tool contract revisions move: search 1→2, get 2→3" line overstated the rule — revisions
55
+ bump on execute-visible text changes, per the in-code note.
56
+ - The #318 scope line ("single explicit FILE target's own spelling") was narrower than the shipped
57
+ behavior; see the path-prefix handling in `search.ts` (`relOut`).
58
+
3
59
  ## 5.45.0 — 2026-08-19
4
60
 
5
61
  ### Added
@@ -1915,7 +1915,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
1915
1915
  const wt = await finishWorktree();
1916
1916
  return { isError: true, content: `Sub-agent not started: source session not found or fork unavailable.${wt ? `\n${wt}` : ""}`, details: { error: "source not found", forkLane: ctx.hostSessionFork ? "host" : "child-runner", ...(ctx.sessionId !== undefined ? { sourceSessionId: ctx.sessionId } : {}) } };
1917
1917
  }
1918
- const forkInternals = { ...childInternals, insideFork: true };
1918
+ const forkInternals = { ...childInternals, insideFork: true, ...(ctx.reminderMark !== undefined ? { reminderMark: ctx.reminderMark } : {}) };
1919
1919
  stepRecorder.lockTo(forkedId);
1920
1920
  const forkWorktreeNote = worktreeDir !== undefined ? forkWorktreeTranslationNote(ctx.parentCwd, worktreeDir) : undefined;
1921
1921
  const forkObjective = `${FORK_DIRECTIVE_FRAME}${prompt}${forkWorktreeNote !== undefined ? `\n\n${forkWorktreeNote}` : ""}`;
@@ -807,6 +807,18 @@ export interface CheckpointState {
807
807
  * scope for any in-row invariant). Absent = the row was minted ungoverned. */
808
808
  realApproval?: true;
809
809
  };
810
+ /**
811
+ * design/319 (A ticket) — the session's reminder provenance mark
812
+ * ({@link import("./reminder-mint.js").mintReminderMark}), persisted so a durable resume keeps
813
+ * minting the SAME mark its transcript's engine reminders and system-prompt declaration carry
814
+ * ("resume reuses" — one declaration, one mark). Additive on the existing checkpoint version —
815
+ * a reader that ignores it is unchanged (the :646 precedent; no version bump). Resume goes
816
+ * through the VERIFY port ({@link import("./reminder-mint.js").isValidReminderMark}): a missing
817
+ * field (pre-319 row) or an unrecognized value-shape (corrupt / foreign / old-scheme after a
818
+ * scheme change) RE-MINTS instead of adopting — the declaration stays strict, and the historic
819
+ * legs' reminders simply read as data (fail-safe downgrade, design/319 a-2).
820
+ */
821
+ reminderMark?: string;
810
822
  /**
811
823
  * design/78 Slice-1: the SAFE-tier self-repair loop's durable state (`failureTrace`/`diagnostics`/
812
824
  * `rejectedHypotheses`/`attemptCount`/`oracleTier` — all JSON/`structuredClone`-safe, no fn/Date). Set ONLY
@@ -583,8 +583,11 @@ export interface UserPromptSubmitResult {
583
583
  * NOTE (council design/74 #6): this does NOT escape a literal `</system-reminder>` in `text` — callers MUST
584
584
  * pass trusted, first-party strings (every current caller does: fixed gate/limit messages). If a future
585
585
  * caller needs to relay UNTRUSTED content (tool output, user data), it must sanitize the close tag first
586
- * (or use the `delimitUntrusted` fence), or a crafted payload could break out of the reminder framing. */
587
- export declare function formatHookFeedback(text: string): string;
586
+ * (or use the `delimitUntrusted` fence), or a crafted payload could break out of the reminder framing.
587
+ * design/319 (A ticket): `mark` is the session's reminder provenance mark — run-scoped callers thread it
588
+ * so the open tag carries the value the system-prompt declaration names (rendered by the mint home; the
589
+ * body is byte-untouched). Absent ⇒ the historic bare open tag (a caller outside a run). */
590
+ export declare function formatHookFeedback(text: string, mark?: string): string;
588
591
  /** The outcome of the two-phase tool gate, mapped onto the harness `tool_call` hook return shape. */
589
592
  export interface ToolGateResult {
590
593
  /** Block execution (the loop emits an error tool result with `reason`). */
@@ -799,6 +802,10 @@ export interface ToolGateInput {
799
802
  * per-leg mint; a host driving the gate directly may omit it, and the contexts then carry no
800
803
  * identity (honest absence — this layer never fabricates a leg). */
801
804
  identity?: HookInvocationIdentity;
805
+ /** design/319 (A ticket) — the run's reminder provenance mark: the gate's own model-facing deny
806
+ * reasons ride `formatHookFeedback`, so their open tags must carry the same mark the run's
807
+ * system-prompt declaration names. Absent (a host driving the gate directly) ⇒ bare tags. */
808
+ reminderMark?: string;
802
809
  preToolUse?: Hooks["preToolUse"];
803
810
  /** The read-only env capability face put on every {@link HookToolContext} this gate call
804
811
  * builds ({@link HookEnvCapabilities}). Built ONCE per task by the runner (after the env is minted) and
@@ -1,6 +1,7 @@
1
1
  import { decisionText, describeThrown, refuseOutOfContractDecision } from "./tool-policy.js";
2
2
  import { brandPolicyAskClass } from "./ask-class.js";
3
3
  import { inlineUntrusted } from "./untrusted-text.js";
4
+ import { mintSystemReminder } from "./reminder-mint.js";
4
5
  import { PROBE_REASON_MAX, normalizeProbeCause } from "./checkpoint-store.js";
5
6
  import { ASK_USER_QUESTION_TOOL_NAME } from "./ask-question.js";
6
7
  import { createSafeNotifier } from "./safe-notify.js";
@@ -90,8 +91,8 @@ export function mintHookInvocationIdentity(facts) {
90
91
  ...(facts.parentToolCallId !== undefined ? { parentToolCallId: facts.parentToolCallId } : {}),
91
92
  }));
92
93
  }
93
- export function formatHookFeedback(text) {
94
- return `<system-reminder>\n${text}\n</system-reminder>`;
94
+ export function formatHookFeedback(text, mark) {
95
+ return mintSystemReminder(text, mark);
95
96
  }
96
97
  const PARK_FAILURE_CAUSE_MAX = 600;
97
98
  function withParkFailureCause(reason, parkFailed) {
@@ -304,7 +305,7 @@ export async function runToolGate(input) {
304
305
  if (input.permissionDenied) {
305
306
  await notifier.notifyAsync(() => input.permissionDenied?.({ toolName, input: cloneObserverInput(currentInput), toolCallId, reason, source: "hook", ...(input.identity !== undefined ? { identity: input.identity } : {}) }), "toolGate.permissionDenied");
306
307
  }
307
- return { block: true, reason: formatHookFeedback(reason), preToolContext };
308
+ return { block: true, reason: formatHookFeedback(reason, input.reminderMark), preToolContext };
308
309
  }
309
310
  if (r) {
310
311
  if (r.additionalContext) {
@@ -313,7 +314,7 @@ export async function runToolGate(input) {
313
314
  if (r.action === "deny") {
314
315
  return {
315
316
  block: true,
316
- reason: formatHookFeedback(decisionText(r) ?? `tool "${toolName}" blocked by a PreToolUse hook`),
317
+ reason: formatHookFeedback(decisionText(r) ?? `tool "${toolName}" blocked by a PreToolUse hook`, input.reminderMark),
317
318
  preToolContext,
318
319
  };
319
320
  }
@@ -813,7 +814,7 @@ export async function runToolGate(input) {
813
814
  const denyApprover = denySettledBy !== undefined ? resolvedApprover : undefined;
814
815
  return {
815
816
  block: true,
816
- reason: formatHookFeedback(denyReason),
817
+ reason: formatHookFeedback(denyReason, input.reminderMark),
817
818
  ...(denySettledBy !== undefined ? { settledBy: denySettledBy } : {}),
818
819
  ...(denyApprover !== undefined ? { approver: denyApprover } : {}),
819
820
  preToolContext,
@@ -6,7 +6,9 @@
6
6
  * into long-term memory? Three tiers:
7
7
  *
8
8
  * - "external" — network-retrieval families and external protocol channels. Invocation marks the
9
- * session's memory POLLUTED (one-way, durable; the polluted harvest quarantines).
9
+ * session's memory EXTERNALLY EXPOSED (one-way, durable; what the mark does at
10
+ * harvest is the provenance mode's question — design/336: tag-admit with an origin
11
+ * marker under "carry", full quarantine under "off").
10
12
  * - "execution" — general execution (shell/exec). A NAMED residual channel: it can reach external
11
13
  * content indirectly, but the two industry anchors this tier is calibrated against
12
14
  * gate on network/protocol families only, and excluding every shell session would
@@ -114,6 +114,29 @@ export interface MemoryEngineOptions {
114
114
  maxFiles?: number;
115
115
  /** Max nesting depth under the writable root (default {@link DEFAULT_MAX_ENTRY_DEPTH}). */
116
116
  maxDepth?: number;
117
+ /**
118
+ * design/336 §13-3 — the memory-provenance master switch (the deployment threads
119
+ * {@link import("../types.js").RunnerDeps.memoryProvenance} here; engine-direct hosts set it
120
+ * directly). Two exact spellings:
121
+ * - `"carry"` (absent ≡ this; the default) — the 336 posture: an externally-exposed session's
122
+ * ORDINARY memory writes commit WITH an engine-minted `origin` marker (tag-admit; the content
123
+ * scan gates still run in full — a marker is not an exemption), instruction-form files
124
+ * (type: feedback / v2 injection hints) are withheld and quarantined (the narrow `polluted`
125
+ * rejection), the derived index's session prose still rolls back to its materialize-time
126
+ * baseline, and exposure carries the SAME file-count cap and harvest budget as a clean
127
+ * session;
128
+ * - `"off"` — the pre-336 behavior: an exposed session's harvest admits nothing (every changed/
129
+ * new file quarantines, host-auditable), no origin marker is ever MINTED, and the read side
130
+ * mounts no origin decorations. One stated deviation from the byte level: origin-form
131
+ * frontmatter written by the model is STILL stripped-with-warning from what commits (the
132
+ * origin seat is engine-authored in both modes — preserving model-authored marker bytes under
133
+ * "off" would hand a forgeable typed field to the next "carry" period), and an EXISTING
134
+ * committed origin still carries forward on edits (the backend's immutability law is
135
+ * structural and mode-independent — "off" stops minting, it never strips standing facts).
136
+ * Any other value refuses loudly at construction (`config.memory_provenance`, #123 — exact
137
+ * spellings, never truthiness).
138
+ */
139
+ provenance?: "off" | "carry";
117
140
  /** M7 — harvest deadline in ms (default {@link DEFAULT_HARVEST_DEADLINE_MS}); over-deadline files
118
141
  * are deferred to the next harvest (report.degraded), never dropped. */
119
142
  harvestDeadlineMs?: number;
@@ -264,8 +287,13 @@ export interface EntryProvenanceAccount {
264
287
  * writing memory files, the harvest quarantined every one of them, and nothing said so while a host
265
288
  * could still act on it.
266
289
  *
290
+ * MODE-AWARE MESSAGE (design/336): the wording follows the engine's provenance mode — under
291
+ * `"carry"` (default) it states the tag-admit semantics (ordinary writes commit with an origin
292
+ * marker; instruction-form files are withheld); the `"off"`/absent spelling keeps the pre-336 text
293
+ * byte-identical. The caller passes the mode it constructed the engine with.
294
+ *
267
295
  * SCOPE OF THE CLAIM (adversarial-review round 1, P1 — the first cut PROMISED quarantine on every mark).
268
- * This notice states the VERDICT, not the mechanism's outcome: "no longer eligible", plus what a harvest
296
+ * This notice states the VERDICT, not the mechanism's outcome: "no longer eligible" (its "off" form), plus what a harvest
269
297
  * does WHEN IT COLLECTS. That distinction is load-bearing, because several real paths reach a polluted
270
298
  * harvest that quarantines nothing — a `writeScope`-null layering and a declared-unavailable session
271
299
  * both take `harvestCore`'s zero-admission return (nothing is collected, so nothing is captured), and a
@@ -290,6 +318,7 @@ export interface EntryProvenanceAccount {
290
318
  export declare function memorySessionPollutedNotice(input: {
291
319
  reason: string;
292
320
  sessionId?: string;
321
+ provenance?: "off" | "carry";
293
322
  }): EngineNotice;
294
323
  /**
295
324
  * The polluted harvest's loud half ({@link EngineNotice}): what the containment actually did, minted
@@ -340,6 +369,7 @@ export declare function memoryHarvestQuarantinedNotice(input: {
340
369
  escalated: number;
341
370
  reason?: string;
342
371
  sessionId?: string;
372
+ provenance?: "off" | "carry";
343
373
  }): EngineNotice;
344
374
  export declare class MemoryEngine {
345
375
  private readonly backend;
@@ -352,6 +382,8 @@ export declare class MemoryEngine {
352
382
  private readonly maxDepth;
353
383
  private readonly harvestDeadlineMs;
354
384
  private readonly harvestFileBudget;
385
+ /** {@link MemoryEngineOptions.provenance} — the design/336 master switch (screened at construction). */
386
+ private readonly provenance;
355
387
  /** {@link MemoryEngineOptions.onIncident} — the advisory disclosure seat (partition + announce codes). */
356
388
  private readonly onIncident;
357
389
  /** A backend-pinned directory (FileBackend zero-copy detection). */
@@ -394,7 +426,7 @@ export declare class MemoryEngine {
394
426
  * markers of one session would both read clean and both announce). Callers that do not disclose
395
427
  * ignore it exactly as before.
396
428
  */
397
- markSessionPolluted(sessionId: string, reason: string): SessionPollutionMarkOutcome;
429
+ markSessionPolluted(sessionId: string, reason: string, cause?: import("./types.js").MemoryOriginCause): SessionPollutionMarkOutcome;
398
430
  /** The session's pollution record (in-process mark first, then the durable marker) — undefined =
399
431
  * clean. Reads are side-effect-free. */
400
432
  sessionPollution(sessionId: string): SessionPollutionRecord | undefined;
@@ -587,6 +619,7 @@ export declare class MemoryEngine {
587
619
  }): Promise<MemorySessionHandle>;
588
620
  inject(handle: MemorySessionHandle, opts?: {
589
621
  writeToolMounted?: boolean;
622
+ reminderMark?: string;
590
623
  }): MemoryInjection;
591
624
  /**
592
625
  * design/138 S2-C — gate ONE tool write (Write/Edit/NotebookEdit) against the memory domain.
@@ -617,6 +650,7 @@ export declare class MemoryEngine {
617
650
  harvest(handle: MemorySessionHandle, opts?: {
618
651
  polluted?: {
619
652
  reason: string;
653
+ cause?: import("./types.js").MemoryOriginCause;
620
654
  };
621
655
  sessionId?: string;
622
656
  admitNothing?: {
@@ -652,6 +686,19 @@ export declare class MemoryEngine {
652
686
  * the deleted disk file WAS the backend's storage). Zero-copy skips getByIds: its read-side scan
653
687
  * cannot see a deleted file, and calling it mid-harvest would sync-adopt in-session edits. */
654
688
  private committedContentFor;
689
+ /**
690
+ * design/336 §2.2 (r4-9) — the COMMITTED frontmatter an origin carry-forward is computed against.
691
+ * Deliberately NOT {@link committedContentFor}'s non-zero-copy leg: that one calls the backend's
692
+ * plain `getByIds`, and the File backend's plain read path ADOPTS out-of-band disk changes (a
693
+ * read-side sync that advances revs and books retrievals) — a carry-forward read must be
694
+ * side-effect-free, or assembling one harvest mutates the store it is reading. Reading order:
695
+ * - zero-copy File: the control-plane shadow IS the committed state (the disk file is the
696
+ * session's own working copy — exactly what must NOT serve as the committed baseline);
697
+ * - copy-out with a `retrievalView` face (File): the lock-free non-adopting view;
698
+ * - twins (Pg/TiDB shapes): plain `getByIds` — naturally committed-state and side-effect-free
699
+ * (the contract clause on {@link MemoryBackend.getByIds}).
700
+ */
701
+ private committedFrontmatterFor;
655
702
  /** L4/C-F9 (S2-0) — capture a gate-rejected file into control-plane quarantine FROM THE SCANNED
656
703
  * CONTENT (never re-reading the path: the disk bytes may have been swapped since the scan —
657
704
  * TOCTOU), then remove the suspect from the model-visible plane (delete, falling back to clearing
@@ -712,6 +759,6 @@ export declare class MemoryEngine {
712
759
  }
713
760
  /** Render drained announcements as ONE engine-owned system-reminder block (the lead/frame is
714
761
  * trusted; item identifiers were neutralized at enqueue — see {@link MemoryAnnouncement.items}). */
715
- export declare function renderAnnouncements(queue: readonly MemoryAnnouncement[], folded: number): string;
762
+ export declare function renderAnnouncements(queue: readonly MemoryAnnouncement[], folded: number, reminderMark?: string): string;
716
763
  /** Truncate the derived index to the CC injection parameters (200 lines / 25KB). */
717
764
  export declare function truncateIndex(text: string): string;