@sema-agent/core 5.57.0 → 5.59.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 (192) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/dist/agents/cascade.d.ts +1 -1
  3. package/dist/agents/cumulative-stats.d.ts +1 -1
  4. package/dist/agents/observer.d.ts +2 -2
  5. package/dist/agents/peer-admission.d.ts +1 -1
  6. package/dist/agents/retain-ledger.d.ts +2 -2
  7. package/dist/agents/roster-store.d.ts +8 -8
  8. package/dist/agents/send-message-tool.d.ts +2 -2
  9. package/dist/agents/subagent-steps.d.ts +1 -1
  10. package/dist/agents/subagent.d.ts +13 -13
  11. package/dist/agents/team.d.ts +5 -5
  12. package/dist/agents/tool-filter.d.ts +2 -2
  13. package/dist/agents/verify.d.ts +1 -1
  14. package/dist/bench/metrics.d.ts +35 -35
  15. package/dist/brain/degrading.d.ts +1 -1
  16. package/dist/brain/errors.d.ts +3 -3
  17. package/dist/brain/reasoning.d.ts +2 -2
  18. package/dist/brain/repetition.d.ts +1 -1
  19. package/dist/brain/route-adjudicator.d.ts +8 -1
  20. package/dist/brain/route-adjudicator.js +8 -1
  21. package/dist/brain/status-sink.d.ts +2 -2
  22. package/dist/brain/stream-shared.d.ts +1 -1
  23. package/dist/config/catalog.d.ts +5 -5
  24. package/dist/core/arg-summary.d.ts +4 -4
  25. package/dist/core/ask-class.d.ts +2 -2
  26. package/dist/core/ask-question.d.ts +1 -1
  27. package/dist/core/auto-compaction.d.ts +15 -15
  28. package/dist/core/auto-mode.d.ts +5 -5
  29. package/dist/core/background-agent-store.d.ts +20 -20
  30. package/dist/core/background-shell.d.ts +4 -4
  31. package/dist/core/checkpoint-store.d.ts +35 -27
  32. package/dist/core/context-edit.d.ts +1 -1
  33. package/dist/core/context-guard.d.ts +1 -1
  34. package/dist/core/exec-output-tail.d.ts +6 -6
  35. package/dist/core/file-snapshot-store.d.ts +8 -8
  36. package/dist/core/git-worktree-env.d.ts +3 -3
  37. package/dist/core/governance-codes.d.ts +37 -10
  38. package/dist/core/governance-codes.js +54 -1
  39. package/dist/core/hooks.d.ts +73 -33
  40. package/dist/core/hooks.js +87 -25
  41. package/dist/core/image-downsample.d.ts +1 -1
  42. package/dist/core/locked-config.d.ts +1 -1
  43. package/dist/core/lsp.d.ts +1 -1
  44. package/dist/core/mailbox-store.d.ts +1 -1
  45. package/dist/core/mcp.d.ts +3 -3
  46. package/dist/core/memory-engine/consolidation-driver.d.ts +211 -0
  47. package/dist/core/memory-engine/consolidation-driver.js +427 -0
  48. package/dist/core/memory-engine/consolidation.d.ts +119 -3
  49. package/dist/core/memory-engine/consolidation.js +22 -1
  50. package/dist/core/memory-engine/data-plane.d.ts +1 -1
  51. package/dist/core/memory-engine/distiller.d.ts +550 -0
  52. package/dist/core/memory-engine/distiller.js +598 -0
  53. package/dist/core/memory-engine/dual-root.d.ts +1 -1
  54. package/dist/core/memory-engine/engine.d.ts +143 -10
  55. package/dist/core/memory-engine/engine.js +149 -23
  56. package/dist/core/memory-engine/file-backend.d.ts +14 -2
  57. package/dist/core/memory-engine/file-backend.js +3 -0
  58. package/dist/core/memory-engine/index.d.ts +6 -3
  59. package/dist/core/memory-engine/index.js +4 -2
  60. package/dist/core/memory-engine/layout.js +20 -6
  61. package/dist/core/memory-engine/origin-clearance.d.ts +1 -1
  62. package/dist/core/memory-engine/scope-contract.d.ts +4 -4
  63. package/dist/core/memory-engine/sync-client.d.ts +16 -16
  64. package/dist/core/memory-engine/sync.d.ts +4 -4
  65. package/dist/core/memory-engine/types.d.ts +17 -0
  66. package/dist/core/memory-recall.d.ts +1 -1
  67. package/dist/core/memory.d.ts +2 -2
  68. package/dist/core/permission-rule-consent.d.ts +185 -36
  69. package/dist/core/permission-rule-consent.js +219 -44
  70. package/dist/core/permission-rule-model.d.ts +235 -31
  71. package/dist/core/permission-rule-model.js +105 -35
  72. package/dist/core/permission-rules.d.ts +9 -9
  73. package/dist/core/remote-env.d.ts +8 -8
  74. package/dist/core/roles.d.ts +3 -3
  75. package/dist/core/roles.js +1 -0
  76. package/dist/core/runner/assemble-result.d.ts +2 -2
  77. package/dist/core/runner/compaction-call-options.d.ts +3 -3
  78. package/dist/core/runner/memory-consolidation-driver.d.ts +49 -0
  79. package/dist/core/runner/memory-consolidation-driver.js +60 -0
  80. package/dist/core/runner/memory-consolidation.d.ts +1 -1
  81. package/dist/core/runner/prepare-config-doors.d.ts +3 -3
  82. package/dist/core/runner/prepare-task.d.ts +21 -21
  83. package/dist/core/runner/prepare-task.js +24 -17
  84. package/dist/core/runner/prepare-workspace-restore.d.ts +2 -2
  85. package/dist/core/runner/runtask.d.ts +11 -11
  86. package/dist/core/runner/runtask.js +4 -4
  87. package/dist/core/runner/session-rule-policy.d.ts +1 -1
  88. package/dist/core/runner/teardown-bounded.d.ts +1 -1
  89. package/dist/core/runner/tool-disclosure.d.ts +2 -2
  90. package/dist/core/runner/turn-attachments.d.ts +11 -11
  91. package/dist/core/scheduler.d.ts +5 -5
  92. package/dist/core/secret-env.d.ts +1 -1
  93. package/dist/core/sensitive-path-policy.d.ts +1 -1
  94. package/dist/core/session-policy-store.d.ts +2 -2
  95. package/dist/core/session-reconcile.d.ts +2 -2
  96. package/dist/core/session-store.d.ts +3 -3
  97. package/dist/core/session.d.ts +1 -1
  98. package/dist/core/shutdown-debug.d.ts +2 -2
  99. package/dist/core/side-query.d.ts +2 -2
  100. package/dist/core/spec-contract.d.ts +1 -1
  101. package/dist/core/store-contracts/contract-harness.d.ts +2 -2
  102. package/dist/core/store-contracts/contract-kit-version.d.ts +2 -2
  103. package/dist/core/store-contracts/mailbox-store-contract.d.ts +1 -1
  104. package/dist/core/store-contracts/mailbox-store-contract.js +1 -1
  105. package/dist/core/task-notification.d.ts +5 -5
  106. package/dist/core/task-registry-agent.d.ts +12 -12
  107. package/dist/core/task-registry-monitor.d.ts +1 -1
  108. package/dist/core/task-registry-shared.d.ts +41 -41
  109. package/dist/core/task-registry.d.ts +12 -12
  110. package/dist/core/tool-detach.d.ts +2 -2
  111. package/dist/core/tool-errors.d.ts +3 -3
  112. package/dist/core/tool-policy.d.ts +113 -28
  113. package/dist/core/tool-policy.js +80 -1
  114. package/dist/core/tool-result-budget.d.ts +1 -1
  115. package/dist/core/tool-result-store.d.ts +2 -2
  116. package/dist/core/tools.d.ts +1 -1
  117. package/dist/core/trace.d.ts +26 -23
  118. package/dist/core/types.d.ts +164 -86
  119. package/dist/core/types.js +4 -3
  120. package/dist/core/untrusted-egress.d.ts +1 -1
  121. package/dist/core/untrusted-text.d.ts +7 -7
  122. package/dist/core/wiring-manifest.d.ts +5 -5
  123. package/dist/core/workflow-journal-store.d.ts +14 -14
  124. package/dist/core/workflow-run-store-contract.d.ts +1 -1
  125. package/dist/core/workflow-run-store-contract.js +1 -1
  126. package/dist/core/workflow-run-store.d.ts +4 -4
  127. package/dist/engine/compaction/compaction.d.ts +3 -3
  128. package/dist/engine/compaction/utils.d.ts +2 -2
  129. package/dist/engine/execution-env/kill-tree.d.ts +1 -1
  130. package/dist/engine/execution-env/node-execution-env.d.ts +8 -8
  131. package/dist/engine/harness/agent-harness.d.ts +6 -6
  132. package/dist/engine/harness/messages.d.ts +1 -1
  133. package/dist/engine/harness/types.d.ts +10 -10
  134. package/dist/engine/llm/types.d.ts +14 -14
  135. package/dist/engine/loop/agent-loop.d.ts +3 -3
  136. package/dist/engine/loop/types.d.ts +4 -4
  137. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  138. package/dist/engine/session/import-validate.d.ts +1 -1
  139. package/dist/engine/session/log-digest.d.ts +1 -1
  140. package/dist/engine/session/memory-repo.d.ts +2 -2
  141. package/dist/engine/session/session.d.ts +4 -4
  142. package/dist/fixtures/index.d.ts +4 -4
  143. package/dist/index.d.ts +6 -5
  144. package/dist/index.js +5 -4
  145. package/dist/orchestration/goal.d.ts +1 -1
  146. package/dist/orchestration/run-spec.d.ts +1 -1
  147. package/dist/orchestration/run-workflow-tool.d.ts +12 -12
  148. package/dist/orchestration/workflow-governance.d.ts +4 -4
  149. package/dist/orchestration/workflow-observe.d.ts +1 -1
  150. package/dist/orchestration/workflow-script-runner.d.ts +1 -1
  151. package/dist/orchestration/workflow-script-store.d.ts +9 -9
  152. package/dist/orchestration/workflow-size-guideline.d.ts +1 -1
  153. package/dist/orchestration/workflow-types.d.ts +5 -5
  154. package/dist/orchestration/workflow.d.ts +10 -10
  155. package/dist/prompt-assembly/artifact-store.d.ts +1 -1
  156. package/dist/prompt-assembly/artifact.d.ts +1 -1
  157. package/dist/prompt-assembly/assemble.d.ts +1 -1
  158. package/dist/prompt-assembly/composer.d.ts +2 -2
  159. package/dist/prompt-assembly/epoch.d.ts +2 -2
  160. package/dist/prompt-assembly/event-registry.d.ts +1 -1
  161. package/dist/prompt-assembly/explain.d.ts +3 -3
  162. package/dist/prompt-assembly/tool-catalog.d.ts +1 -1
  163. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -4
  164. package/dist/prompt-assembly/types.d.ts +12 -12
  165. package/dist/prompts/coordinator.d.ts +1 -1
  166. package/dist/prompts/default.d.ts +8 -8
  167. package/dist/prompts/simple-sections.d.ts +3 -3
  168. package/dist/prompts/supervisor.d.ts +2 -2
  169. package/dist/scenarios/full-body.d.ts +3 -3
  170. package/dist/scenarios/scenario-registry.d.ts +1 -1
  171. package/dist/stores/cc/sidecar-transcript.d.ts +3 -3
  172. package/dist/stores/file/fs-atomic.d.ts +2 -2
  173. package/dist/stores/file/index.d.ts +1 -1
  174. package/dist/stores/file/session-store.d.ts +2 -2
  175. package/dist/stores/file/workflow-journal-store.d.ts +4 -4
  176. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  177. package/dist/tools/fs/encoding.d.ts +4 -4
  178. package/dist/tools/fs/fs-bash.d.ts +3 -3
  179. package/dist/tools/fs/fs-pdf.d.ts +1 -1
  180. package/dist/tools/fs/fs-shared.d.ts +6 -6
  181. package/dist/tools/fs/index.d.ts +2 -2
  182. package/dist/tools/fs/notebook.d.ts +1 -1
  183. package/dist/tools/fs/pdf.d.ts +1 -1
  184. package/dist/tools/fs/read-deny.d.ts +1 -1
  185. package/dist/tools/fs/safety.d.ts +9 -9
  186. package/dist/tools/fs/search.d.ts +2 -2
  187. package/dist/tools/monitor.d.ts +3 -3
  188. package/dist/tools/task-list.d.ts +2 -2
  189. package/dist/tools/web.d.ts +4 -4
  190. package/dist/tools/worktree.d.ts +5 -5
  191. package/package.json +1 -1
  192. package/test/export-surface.snapshot.json +1826 -3
@@ -1,11 +1,11 @@
1
1
  import type { EngineNotice } from "../types.js";
2
- import { type ConsolidationGateRow, type ConsolidationPlanFile, type ConsolidationProposal, type MemoryConsolidationOptions } from "./consolidation.js";
2
+ import { type ConsolidationGateRead, type ConsolidationGateRow, type ConsolidationPlanFile, type ConsolidationProposal, type ConsolidationRunStopReason, type MemoryConsolidationOptions } from "./consolidation.js";
3
3
  import { foreignDanglingSessionAccounts, type EffectiveSettlement, type HoldRow } from "./delegation-settlement.js";
4
4
  import { type OriginClearanceRow } from "./origin-clearance.js";
5
5
  import { type CommittedBinding, type EraseMemoryEntriesInput, type MemoryErasureAttestation, type TransferEvidence } from "./file-backend.js";
6
6
  import { type MemoryExportBundle, type MemoryImportReport } from "./export-bundle.js";
7
7
  import { type ChallengeAssignment, type ChallengeEvent, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, type MemoryPartitionIncidentSink, type RetrievedAccountRow, type SessionPollutionMarkOutcome, type SessionPollutionRecord } from "./layout.js";
8
- import type { HarvestReport, MemoryAnnouncement, MemoryBackend, MemoryEntry, MemoryEntryOrigin, MemorySessionHandle, ScanFinding } from "./types.js";
8
+ import type { HarvestReport, MemoryAnnouncement, MemoryBackend, MemoryEntry, MemoryEntryOrigin, MemoryScopeEnumeration, MemorySessionHandle, ScanFinding } from "./types.js";
9
9
  /**
10
10
  * The CC `# Memory` instruction section — VERBATIM from the live capture
11
11
  * (bench/cc-parity-toolsuite/reminders/live-capture-main-session-2026-07-08.md §12), with the
@@ -251,7 +251,7 @@ export interface MemoryInjection {
251
251
  * session's harvest / the backend's read-side external-change detection). Already rendered into
252
252
  * {@link block}; exposed raw for observability/tests. Absent when the queue was empty. */
253
253
  announcements?: MemoryAnnouncement[];
254
- /** The RENDERED announcements segment of {@link block} (design/142 S2b, codex H11): dual-root
254
+ /** The RENDERED announcements segment of {@link block} (design/142 S2b): dual-root
255
255
  * merging composes from STRUCTURED fields — never by re-parsing `block` (whose instruction/index
256
256
  * segments contain blank lines a split would shred). Absent when the queue was empty. */
257
257
  announceBlock?: string;
@@ -485,7 +485,7 @@ export interface ConsolidationReconcileReport {
485
485
  state: "completed" | "conflict";
486
486
  };
487
487
  releasedOrphanSeat?: string;
488
- /** codex r2 — a seat whose plan file is absent but whose claim is YOUNGER than the freeze grace:
488
+ /** a seat whose plan file is absent but whose claim is YOUNGER than the freeze grace:
489
489
  * a live commit is (very likely) mid-freeze; reconcile leaves it alone and reports it here. */
490
490
  seatInFlight?: string;
491
491
  corruptPlan?: {
@@ -514,6 +514,36 @@ export interface ConsolidationPlanSummary {
514
514
  directed?: number;
515
515
  intents?: number;
516
516
  }
517
+ /**
518
+ * design/376 slice ③ (#436) — one plan's MEMBER-LEVEL fold evidence
519
+ * ({@link MemoryEngine.readConsolidationPlanFoldEvidence}'s answer): which entry ids this plan's
520
+ * APPLIED products attest as superseded. Discriminated so an unreadable plan can never be told
521
+ * apart from an empty one by accident.
522
+ */
523
+ export type ConsolidationPlanFoldEvidence = {
524
+ state: "ok";
525
+ scope: string;
526
+ /** The commit call's requestId, frozen on the plan — the durable run-attribution anchor
527
+ * (the driver's per-cycle requestIds share the run's prefix, so a cycle whose receipt was
528
+ * lost to a crash is still attributable to its run through the plan file). */
529
+ requestId: string;
530
+ planState: ConsolidationPlanFile["state"];
531
+ /** Every supersession-edge target of an APPLIED product, deduplicated and sorted. Products
532
+ * still pending/conflicted attest nothing — the store never saw their edges land. */
533
+ supersededTargets: string[];
534
+ } | {
535
+ state: "absent";
536
+ } | {
537
+ state: "corrupt";
538
+ detail: string;
539
+ /** Present when the plan FILE parsed and only its product frontmatter is damaged (the deep
540
+ * per-product walk's corrupt arm): the frozen attribution anchors survive the damage, so a
541
+ * caller can still attribute the damaged plan to a run — the conservation wall uses this
542
+ * to fail closed ONLY on a run-owned damaged plan while a foreign/historical one is
543
+ * skipped with disclosure. Absent when the file itself is unreadable/unparseable. */
544
+ scope?: string;
545
+ requestId?: string;
546
+ };
517
547
  /** §2.2 — the recommendation notice, minted off the harvest report's advisory member (the runner's
518
548
  * hold-notice consumption point is its natural home). Undefined ⇔ this harvest crossed no edge. */
519
549
  export declare function memoryConsolidationRecommendedNotice(report: HarvestReport, sessionId?: string): EngineNotice | undefined;
@@ -543,6 +573,28 @@ export declare function memoryConsolidationConflictNotice(input: {
543
573
  planId: string;
544
574
  scope: string;
545
575
  }): EngineNotice;
576
+ /**
577
+ * design/376 §1.6-2 — the ADVISORY notice for a driver run that stopped short of its fixpoint
578
+ * (`memory.consolidation_incomplete`). Partial folds are measurably worse than no fold (currency
579
+ * queries regress to the unconsolidated baseline while the residue stays buried), so a run that
580
+ * committed some cycles and stopped must be visible as a TRANSITIONAL state — without this code an
581
+ * operator sees only a trail of `_committed` notices and cannot tell a settled library from one
582
+ * mid-fold. `stop` takes its value from the ONE closed set the run receipt uses
583
+ * ({@link ConsolidationRunStopReason}); the two channels never carry different vocabularies.
584
+ *
585
+ * The message branches on `cyclesDone` (truthfulness, both arms pinned): a run that stopped at
586
+ * the door — a parked seat, a failed mint — committed NOTHING, and its line says the library is
587
+ * unchanged by this run rather than asserting a partial fold this run never produced. (The
588
+ * PARTIAL-fold claim stays a per-run statement; whether the library was already mid-fold from an
589
+ * earlier run is the gate's account, not this line's.)
590
+ */
591
+ export declare function memoryConsolidationIncompleteNotice(input: {
592
+ scope: string;
593
+ runId: string;
594
+ stop: ConsolidationRunStopReason;
595
+ residueProducts: number;
596
+ cyclesDone: number;
597
+ }): EngineNotice;
546
598
  /** The refusal's notice dialect (the verb itself throws the coded {@link ConsolidationRefusedError};
547
599
  * a host converting the throw into its notice stream uses this one spelling). */
548
600
  export declare function memoryConsolidationRefusedNotice(input: {
@@ -934,10 +986,18 @@ export declare class MemoryEngine {
934
986
  }>;
935
987
  /**
936
988
  * §1.2-2/§1.2-3 — verb ②: mechanical acceptance + plan FREEZE + apply-to-terminal. Structural
937
- * violations (scan findings, out-of-snapshot attribution, caps, the instruction hard gate, the
938
- * supersession fuse) refuse the WHOLE plan — zero partial freeze; per-product eligibility drift
939
- * (an input's rev moved / an input got challenged between snapshot and freeze) refuses THAT
940
- * product with a disclosed reason while the rest freeze (§1.2-2 冻结时资格复验).
989
+ * violations (out-of-snapshot attribution, caps, the instruction hard gate, the supersession
990
+ * fuse, an empty plan) refuse the WHOLE plan — zero partial freeze. Per-product refusals, each
991
+ * disclosed on the receipt (`products.refused`): eligibility drift (an input's rev moved / an
992
+ * input got challenged between snapshot and freeze, §1.2-2 冻结时资格复验) AND scan findings
993
+ * (design/376 C-2① — the explicit revision of 339 §1.2-2's whole-plan clause: one product's
994
+ * refused bytes must not permanently deny service to every other fold in the plan). The scan
995
+ * seat keeps two whole-plan backstops: the scan-refusal fuse (C-2②, {@link scanRefusalCeiling})
996
+ * refuses a plan saturated with scan-refused products, and a plan the freeze emptied entirely
997
+ * refuses rather than settling as a vacuous completed run (C-2③ — completion writes `lastRunAt`
998
+ * and stamps the full eligible set into the fingerprint, blinding every later incremental
999
+ * snapshot). Intent (directed) scan findings stay whole-plan: intents are host-authored, not
1000
+ * driver products.
941
1001
  */
942
1002
  commitConsolidationPlan(cycleToken: string, proposal: ConsolidationProposal, opts: {
943
1003
  requestId: string;
@@ -987,7 +1047,12 @@ export declare class MemoryEngine {
987
1047
  * ABANDONED explicitly (audited; never a silent drop — unfulfilled and given-up stay two
988
1048
  * distinguishable account facts, G24) and the seat releases; `retry` = the plan's unfulfilled
989
1049
  * intents re-judge NOW into a NEW plan (fresh freeze, fresh baseRevs — the ONE authorized
990
- * re-judgment point) which applies immediately. Both audited by requestId.
1050
+ * re-judgment point) which applies immediately. A retry with NOTHING to re-judge (a
1051
+ * products-only conflict plan, or every unfulfilled intent already credentialed) refuses
1052
+ * instead of settling a vacuous completed run — C-2③'s empty-plan law at this corridor's door
1053
+ * (the completion would burn the time gate and stamp the original cycle's eligible map into
1054
+ * the fingerprint); `discard` is the exit that releases the seat without wearing the
1055
+ * completed-run label. Both audited by requestId.
991
1056
  */
992
1057
  resolveConsolidationPlan(planId: string, action: "discard" | "retry", opts: {
993
1058
  requestId: string;
@@ -1003,9 +1068,77 @@ export declare class MemoryEngine {
1003
1068
  private reconstructIntentsForRetry;
1004
1069
  /** §6.2 — host read face: every plan's summary (audit enumeration, zero model surface). */
1005
1070
  listConsolidationPlans(): ConsolidationPlanSummary[];
1071
+ /**
1072
+ * design/376 slice ③ (#436) — host read face: one plan's MEMBER-LEVEL fold evidence (which ids
1073
+ * its APPLIED products supersede). This is the conservation wall's terminal witness: the
1074
+ * driver's other two witnesses (per-cycle row delta, since-open store delta) are both
1075
+ * store-COUNT readings, and an unrelated fold interleaved into the run's scope can numerically
1076
+ * offset a planned member that was deleted mid-run — masking the shortfall behind a balanced
1077
+ * count. Member identity cannot be offset: a planned member either appears among some
1078
+ * run-attributed plan's applied supersession targets, sits in named residue, or the run must
1079
+ * not wear the converged label. Committed plan-file read, side-effect-free; the answer carries
1080
+ * the plan's frozen `requestId` so a caller can attribute plans to a run even across the
1081
+ * commit→receipt crash window (the plan file is durable before any receipt is).
1082
+ *
1083
+ * SCOPE of the attestation, disclosed (an outside review probed it; recorded as the designed
1084
+ * limit rather than patched): this is the committed HISTORICAL fact "this plan's edge landed" —
1085
+ * it does not re-derive whether the edge still stands NOW. A target edit or a carrier challenge
1086
+ * later SUSPENDS the edge (`deriveSupersededSet`'s revival law), and a competing writer may
1087
+ * re-fold the revived member before the run's next snapshot; the attestation still exempts it
1088
+ * and the run keeps its converged label. That label stays materially true in every reachable
1089
+ * arm: the member's content is preserved in THIS run's committed carrier either way, the store
1090
+ * is at a fixpoint (re-covered by a standing edge, or explicitly tombstoned), and the next full
1091
+ * mint re-judges the live world. A LIVE-standing re-derivation here would instead false-red the
1092
+ * honestly converged re-covered case, and the ruled evidence form is the per-plan applied edge.
1093
+ */
1094
+ readConsolidationPlanFoldEvidence(planId: string): ConsolidationPlanFoldEvidence;
1006
1095
  /** §6.2 — host read face: one scope's gate row (undefined when the store has no row — reading
1007
- * never creates the file, so the OFF deployment stays byte-identical, G1). */
1096
+ * never creates the file, so the OFF deployment stays byte-identical, G1). A corrupt store
1097
+ * ALSO answers undefined here — this face cannot distinguish the two; a consumer that needs
1098
+ * the difference reads {@link readConsolidationGateState} (#437②). */
1008
1099
  readConsolidationGate(scope: string): ConsolidationGateRow | undefined;
1100
+ /**
1101
+ * design/376 slice ③ (#437②) — host read face: one scope's gate row as a DISCRIMINATED answer.
1102
+ * The undiscriminated face above folds a corrupt store into `undefined`, so a healthy never-run
1103
+ * scope and a store every verb will refuse fail-closed were indistinguishable to an operator or
1104
+ * a scheduling read. `present` carries the row; `absent` = readable store, no row (reading never
1105
+ * creates the file — the OFF deployment stays byte-identical, G1); `corrupt` carries the
1106
+ * refusal detail. Additive; the undiscriminated face is unchanged.
1107
+ */
1108
+ readConsolidationGateState(scope: string): ConsolidationGateRead;
1109
+ /**
1110
+ * design/376 片② — host read face: one scope's committed FOLD STATE, in the freeze's own
1111
+ * accounting (`active` counts entries neither superseded nor excluded — byte-for-byte the
1112
+ * denominator `commitConsolidationPlan` re-derives for the supersession fuse). The driver plans
1113
+ * UNDER the fuse instead of discovering it as a refusal, and every count it publishes is a store
1114
+ * delta read through here — the fuse denominator and the published counts are store facts, never
1115
+ * driver assumptions. Side-effect-free committed read; an unreadable governance overlay refuses
1116
+ * coded (a silently wrong denominator would mis-schedule every remaining cycle).
1117
+ */
1118
+ readConsolidationFoldState(scope: string): Promise<{
1119
+ active: number;
1120
+ superseded: number;
1121
+ products: number;
1122
+ }>;
1123
+ /**
1124
+ * Host read face: the engine's RESOLVED control-plane directory (the same coordinate a
1125
+ * directory-pinned backend already publishes as `controlPlaneRoot`; this accessor answers it
1126
+ * after the engine's own precedence — backend pin > constructor argument > derived default).
1127
+ * The shipped consolidation driver keeps its run account and mint archives in this plane
1128
+ * (design/376 §1.6-4); path knowledge is not authority — nothing here bypasses a verb.
1129
+ */
1130
+ get controlPlaneRoot(): string;
1131
+ /**
1132
+ * design/376 slice ③ (#437③) — host read face: the store's scope enumeration, capability-probed
1133
+ * on the backend (`listScopes`, the audit-face probe family). A backend WITHOUT the face
1134
+ * answers `supported: false` — never an empty array: "cannot enumerate" and "hosts no scopes"
1135
+ * must stay two different answers, or every audit sweep over a non-enumerating backend would
1136
+ * silently claim a clean store. The File backend derives the answer from the store root's
1137
+ * durable scope registry (store-level fact — never a session roster); the SQL twins gain the
1138
+ * face through the store-contracts extension (separate ticket). A supporting backend's corrupt
1139
+ * registry THROWS fail-closed — the same reason an unsupported one never reads as empty.
1140
+ */
1141
+ listMemoryScopes(): Promise<MemoryScopeEnumeration>;
1009
1142
  /** The committed, side-effect-free audit read: the adoption-restricted committed view when the
1010
1143
  * backend offers one (zero-copy File — ledger+shadow, no disk adoption), else the non-adopting
1011
1144
  * retrieval view (copy-out File), else the backend itself (Pg/TiDB shapes — naturally committed
@@ -9,7 +9,7 @@ import { formatMemoryAge } from "../memory-recall.js";
9
9
  import { committedDistilledOf, committedOriginOf, computeEntryRev, distilledEquals, hasDistilledFormExtra, hasOriginFormExtra, isValidEntryId, originEquals, parseEntryFile, serializeEntryFile, stripModelWrittenDistilled, stripModelWrittenOrigin } from "./frontmatter.js";
10
10
  import { MEMORY_PROVENANCE_RECALL_SENTENCE, memoryExposureIndexRow, parseMemoryExposureIndexRow } from "./provenance-wording.js";
11
11
  import { isInstructionEntry } from "./header-hints.js";
12
- import { ConsolidationRefusedError, CONSOLIDATION_FORCE_THROTTLE_FLOOR_MS, CONSOLIDATION_SEAT_FREEZE_GRACE_MS, consolidationTypeEligible, deriveProductSlug, deriveSupersededSet, isValidConsolidationPlanId, listConsolidationPlanIds, productAddPatch, quarantineCorruptPlan, readConsolidationGateFile, readConsolidationPlan, readIntentCredentials, recordActiveSetBaseline, recordConsolidationSession, recordIntentCredentials, screenConsolidationOptions, supersessionFuseCeiling, updateConsolidationGate, writeConsolidationPlan, } from "./consolidation.js";
12
+ import { ConsolidationRefusedError, CONSOLIDATION_FORCE_THROTTLE_FLOOR_MS, CONSOLIDATION_SEAT_FREEZE_GRACE_MS, consolidationTypeEligible, deriveProductSlug, deriveSupersededSet, isValidConsolidationPlanId, listConsolidationPlanIds, productAddPatch, quarantineCorruptPlan, readConsolidationGateFile, readConsolidationPlan, readIntentCredentials, recordActiveSetBaseline, recordConsolidationSession, recordIntentCredentials, scanRefusalCeiling, screenConsolidationOptions, supersessionFuseCeiling, updateConsolidationGate, writeConsolidationPlan, } from "./consolidation.js";
13
13
  import { classifySessionSettlements, clearHoldResolution, closeSessionAccount, disposeHold, effectiveSettlements, expireOverdueSettlements, foreignDanglingSessionAccounts, markHoldReleased, openInstructionHold, openSessionAccount, readHoldCustody, readHolds, reconcileHolds, replayExternalSettlementEffects, resolveHoldRecord, resolveSessionAccountRecord, resolveSettlementRecord, sessionSettlements, sessionUnattributedSet, } from "./delegation-settlement.js";
14
14
  import { noReplaceRestore } from "./delegation-settlement.js";
15
15
  import { markOriginClearanceTombstoned, openOriginClearance, readOriginClearances, settleOriginClearance } from "./origin-clearance.js";
@@ -197,6 +197,15 @@ export function memoryConsolidationConflictNotice(input) {
197
197
  detail: { planId: input.planId, scope: inlineUntrusted(input.scope, 80) },
198
198
  };
199
199
  }
200
+ export function memoryConsolidationIncompleteNotice(input) {
201
+ return {
202
+ code: "memory.consolidation_incomplete",
203
+ message: input.cyclesDone === 0
204
+ ? `Memory consolidation run ${input.runId} for scope ${inlineUntrusted(input.scope, 80)} stopped ${input.stop} after 0 committed cycle(s) — this run made no writes and the library is unchanged by it (the stop reason names the block; a fresh run re-distills from a full snapshot).`
205
+ : `Memory consolidation run ${input.runId} for scope ${inlineUntrusted(input.scope, 80)} stopped ${input.stop} after ${input.cyclesDone} committed cycle(s) with ${input.residueProducts} proposed product(s) unfolded — the library is in a PARTIAL fold (committed cycles stand; the next run's full snapshot re-distills the remainder).`,
206
+ detail: { scope: inlineUntrusted(input.scope, 80), runId: input.runId, stop: input.stop, residueProducts: input.residueProducts, cyclesDone: input.cyclesDone },
207
+ };
208
+ }
200
209
  export function memoryConsolidationRefusedNotice(input) {
201
210
  return {
202
211
  code: "memory.consolidation_refused",
@@ -2579,7 +2588,7 @@ export class MemoryEngine {
2579
2588
  const marked = candidates.some((c) => c.marked);
2580
2589
  const epoch = row?.epoch ?? 0;
2581
2590
  const cycleToken = createHash("sha256").update(JSON.stringify([scope, epoch, at, Object.entries(candidateRevs).sort()]), "utf8").digest("hex").slice(0, 32);
2582
- updateConsolidationGate(this.controlDir, (file) => {
2591
+ const announceForce = updateConsolidationGate(this.controlDir, (file) => {
2583
2592
  const fresh = file.scopes[scope] ?? { sessions: { count: 0, ring: [] }, epoch: 0 };
2584
2593
  if (fresh.openPlanId !== undefined) {
2585
2594
  throw new ConsolidationRefusedError("memory.consolidation_busy", `memory consolidation refused: plan ${fresh.openPlanId} claimed the ${JSON.stringify(scope)} seat during the snapshot read.`);
@@ -2588,10 +2597,15 @@ export class MemoryEngine {
2588
2597
  throw new ConsolidationRefusedError("memory.consolidation_stale_snapshot", `memory consolidation refused: the ${JSON.stringify(scope)} watermark advanced during the snapshot read — retake the snapshot.`);
2589
2598
  }
2590
2599
  fresh.snapshot = { token: cycleToken, at, epoch, candidates: candidateRevs, eligible: eligibleRevs, marked };
2600
+ let announce = false;
2601
+ if (opts.force !== undefined && fresh.lastForcedRequestId !== opts.force.requestId) {
2602
+ fresh.lastForcedRequestId = opts.force.requestId;
2603
+ announce = true;
2604
+ }
2591
2605
  file.scopes[scope] = fresh;
2592
- return { next: file, result: undefined };
2606
+ return { next: file, result: announce };
2593
2607
  });
2594
- if (opts.force !== undefined) {
2608
+ if (opts.force !== undefined && announceForce) {
2595
2609
  try {
2596
2610
  enqueueMemoryAnnouncement(this.controlDir, { kind: "gate", at, items: [`memory consolidation snapshot FORCED past the time/session gates for scope ${inlineUntrusted(scope, 80)} (requestId ${inlineUntrusted(opts.force.requestId, 80)})`] });
2597
2611
  }
@@ -2642,6 +2656,9 @@ export class MemoryEngine {
2642
2656
  else if (p.inputs.length > screened.maxInputsPerProduct)
2643
2657
  reasons.push(`product #${i}: ${p.inputs.length} inputs > maxInputsPerProduct ${screened.maxInputsPerProduct}`);
2644
2658
  }
2659
+ if (proposal.products.length === 0 && intents.length === 0) {
2660
+ reasons.push("empty plan: zero products and zero directed intents — a plan with nothing to apply must not settle as a completed run (the vacuous completion would stamp the eligible set into the fingerprint and blind the incremental face)");
2661
+ }
2645
2662
  if (reasons.length > 0)
2646
2663
  throw new ConsolidationRefusedError("memory.consolidation_refused", "memory consolidation plan refused (structural)", reasons);
2647
2664
  const planId = uuidv7();
@@ -2723,21 +2740,7 @@ export class MemoryEngine {
2723
2740
  }
2724
2741
  }
2725
2742
  const activeSetSize = headers.filter((h) => !superseded.has(h.id) && !exclusions.has(h.id)).length;
2726
- const edgeTargets = new Set();
2727
- for (const p of proposal.products)
2728
- for (const i2 of p.inputs)
2729
- if (i2.supersede === true)
2730
- edgeTargets.add(i2.id);
2731
2743
  const ceiling = supersessionFuseCeiling(activeSetSize, screened);
2732
- if (edgeTargets.size > ceiling) {
2733
- wholeReasons.push(`supersession fuse: ${edgeTargets.size} distinct targets > ceiling ${ceiling} (active set ${activeSetSize}, ratio ${screened.supersedeRatioCap}, floor ${screened.supersedeAbsoluteFloor}, N-1 unconditional)`);
2734
- try {
2735
- enqueueMemoryAnnouncement(this.controlDir, { kind: "gate", at, items: [`memory consolidation plan for scope ${inlineUntrusted(scope, 80)} REFUSED by the supersession fuse (${edgeTargets.size} targets over the ${ceiling} ceiling)`] });
2736
- }
2737
- catch (err) {
2738
- this.discloseAnnounceFailure("consolidation fuse enqueue", err);
2739
- }
2740
- }
2741
2744
  let visibleMarked = snapshot.marked;
2742
2745
  if (!visibleMarked) {
2743
2746
  const inputIds = [...new Set(proposal.products.flatMap((p) => p.inputs.map((i2) => i2.id)))];
@@ -2747,12 +2750,18 @@ export class MemoryEngine {
2747
2750
  const foldedOrigin = visibleMarked ? { taint: "external", cause: "derived", at } : undefined;
2748
2751
  for (let i = 0; i < proposal.products.length; i++) {
2749
2752
  const p = proposal.products[i];
2750
- if (visibleMarked && isInstructionEntry({ ...(p.type !== undefined ? { type: p.type } : {}) })) {
2751
- wholeReasons.push(`product #${i}: instruction-form product (type ${JSON.stringify(p.type)}) refused — the run's visible set contains marked content (the laundering hard gate, G7/G26)`);
2753
+ if (!isInstructionEntry({ ...(p.type !== undefined ? { type: p.type } : {}) }))
2754
+ continue;
2755
+ if (visibleMarked) {
2756
+ wholeReasons.push(`product #${i}: instruction-form product (type ${JSON.stringify(p.type)}) refused — the run's visible set contains marked content (the laundering hard gate, G7/G26; no option opens this arm)`);
2757
+ }
2758
+ else if (!screened.allowInstructionProducts) {
2759
+ wholeReasons.push(`product #${i}: instruction-form product (type ${JSON.stringify(p.type)}) refused — instruction-form consolidation products are refused unconditionally by default (a consolidation must not mint privileged entries out of ordinary notes); the host escape hatch is consolidation.allowInstructionProducts: true`);
2752
2760
  }
2753
2761
  }
2754
2762
  const assembled = [];
2755
2763
  const refusedProducts = [];
2764
+ const scanRefused = [];
2756
2765
  for (let i = 0; i < proposal.products.length; i++) {
2757
2766
  const p = proposal.products[i];
2758
2767
  const drift = [];
@@ -2799,11 +2808,31 @@ export class MemoryEngine {
2799
2808
  const nameFinding = scanMemoryFileName(`${slug}.md`);
2800
2809
  const findings = [...(nameFinding !== undefined ? [nameFinding] : []), ...scanMemoryWrite(serializeEntryFile(entry), { maxBytes: this.perFileBytes })];
2801
2810
  if (findings.length > 0) {
2802
- wholeReasons.push(`product #${i}: scan gate (${findings.map((f) => `${f.code}: ${f.reason}`).join("; ")})`);
2811
+ const reason = `scan gate (${findings.map((f) => `${f.code}: ${f.reason}`).join("; ")})`;
2812
+ refusedProducts.push({ index: i, reason });
2813
+ scanRefused.push({ index: i, reason });
2803
2814
  continue;
2804
2815
  }
2805
2816
  assembled.push(entry);
2806
2817
  }
2818
+ const edgeTargets = new Set();
2819
+ for (const e of assembled)
2820
+ for (const i2 of e.frontmatter.distilled?.inputs ?? [])
2821
+ if (i2.superseded === true)
2822
+ edgeTargets.add(i2.id);
2823
+ if (edgeTargets.size > ceiling) {
2824
+ wholeReasons.push(`supersession fuse: ${edgeTargets.size} distinct targets > ceiling ${ceiling} (active set ${activeSetSize}, ratio ${screened.supersedeRatioCap}, floor ${screened.supersedeAbsoluteFloor}, N-1 unconditional)`);
2825
+ try {
2826
+ enqueueMemoryAnnouncement(this.controlDir, { kind: "gate", at, items: [`memory consolidation plan for scope ${inlineUntrusted(scope, 80)} REFUSED by the supersession fuse (${edgeTargets.size} targets over the ${ceiling} ceiling)`] });
2827
+ }
2828
+ catch (err) {
2829
+ this.discloseAnnounceFailure("consolidation fuse enqueue", err);
2830
+ }
2831
+ }
2832
+ const scanCeiling = scanRefusalCeiling(proposal.products.length, screened);
2833
+ if (scanRefused.length > scanCeiling) {
2834
+ wholeReasons.push(`scan-refusal fuse: ${scanRefused.length} of ${proposal.products.length} product(s) failed the write scan > ceiling ${scanCeiling} (ratio ${screened.scanRefusalRatioCap}, per-plan max ${screened.scanRefusalMaxPerPlan}) — ${scanRefused.map((r) => `#${r.index}: ${r.reason}`).join(" | ")}`);
2835
+ }
2807
2836
  const directed = [];
2808
2837
  const intents = proposal.intents ?? [];
2809
2838
  const targetIds = intents.map((it) => it.entryId);
@@ -2861,6 +2890,9 @@ export class MemoryEngine {
2861
2890
  directed.push({ intentRequestId: intent.requestId, op: "update", id: intent.entryId, baseRev: committed.rev, plannedPostRev: terminal.rev, entry: terminal, state: "pending" });
2862
2891
  }
2863
2892
  }
2893
+ if (wholeReasons.length === 0 && assembled.length === 0 && directed.length === 0) {
2894
+ wholeReasons.push(`empty plan after freeze: every product was refused (${refusedProducts.map((r) => `#${r.index}: ${r.reason}`).join(" | ")}) — a plan with nothing left to apply must not settle as a completed run (the vacuous completion would stamp the eligible set into the fingerprint and blind the incremental face)`);
2895
+ }
2864
2896
  if (wholeReasons.length > 0)
2865
2897
  throw new ConsolidationRefusedError("memory.consolidation_refused", "memory consolidation plan refused", wholeReasons);
2866
2898
  try {
@@ -2874,8 +2906,9 @@ export class MemoryEngine {
2874
2906
  throw err;
2875
2907
  throw new ConsolidationRefusedError("memory.consolidation_gate_corrupt", `memory consolidation refused: the gate store could not be re-read at the freeze boundary (fail-closed): ${err instanceof Error ? err.message : String(err)}`);
2876
2908
  }
2909
+ const freezeRefusedInputIds = [...new Set(refusedProducts.flatMap((r) => (proposal.products[r.index]?.inputs ?? []).map((i2) => i2.id)))].sort();
2877
2910
  const plan = {
2878
- v: 1,
2911
+ v: freezeRefusedInputIds.length > 0 ? 2 : 1,
2879
2912
  planId,
2880
2913
  scope,
2881
2914
  requestId: input.requestId,
@@ -2886,6 +2919,7 @@ export class MemoryEngine {
2886
2919
  ...(foldedOrigin !== undefined ? { foldedOrigin } : {}),
2887
2920
  products: assembled,
2888
2921
  productStates: Object.fromEntries(assembled.map((e) => [e.id, "pending"])),
2922
+ ...(freezeRefusedInputIds.length > 0 ? { freezeRefusedInputIds } : {}),
2889
2923
  directed,
2890
2924
  intents: intents.map((it) => ({ requestId: it.requestId, state: "pending" })),
2891
2925
  state: "open",
@@ -3085,6 +3119,7 @@ export class MemoryEngine {
3085
3119
  }
3086
3120
  writeConsolidationPlan(this.controlDir, plan);
3087
3121
  const currentlyEligible = await this.settleFingerprintFilter(plan.scope);
3122
+ const freezeRefused = new Set(plan.freezeRefusedInputIds ?? []);
3088
3123
  updateConsolidationGate(this.controlDir, (file) => {
3089
3124
  const row = file.scopes[plan.scope];
3090
3125
  if (row?.openPlanId !== plan.planId)
@@ -3097,6 +3132,8 @@ export class MemoryEngine {
3097
3132
  if (currentlyEligible !== undefined) {
3098
3133
  const fp = {};
3099
3134
  for (const [id, rev] of Object.entries(row.snapshot.eligible)) {
3135
+ if (freezeRefused.has(id))
3136
+ continue;
3100
3137
  if (!currentlyEligible(id, rev))
3101
3138
  continue;
3102
3139
  fp[id] = { rev };
@@ -3220,6 +3257,7 @@ export class MemoryEngine {
3220
3257
  }
3221
3258
  async settleGateForTerminalPlan(plan) {
3222
3259
  const currentlyEligible = await this.settleFingerprintFilter(plan.scope);
3260
+ const freezeRefused = new Set(plan.freezeRefusedInputIds ?? []);
3223
3261
  updateConsolidationGate(this.controlDir, (file) => {
3224
3262
  const row = file.scopes[plan.scope];
3225
3263
  if (row?.openPlanId !== plan.planId)
@@ -3233,6 +3271,8 @@ export class MemoryEngine {
3233
3271
  if (currentlyEligible !== undefined) {
3234
3272
  const fp = {};
3235
3273
  for (const [id, rev] of Object.entries(row.snapshot.eligible)) {
3274
+ if (freezeRefused.has(id))
3275
+ continue;
3236
3276
  if (!currentlyEligible(id, rev))
3237
3277
  continue;
3238
3278
  fp[id] = { rev };
@@ -3334,6 +3374,24 @@ export class MemoryEngine {
3334
3374
  throw new ConsolidationRefusedError("memory.consolidation_gate_corrupt", `memory consolidation retry refused: the intent-credential account cannot be trusted (fail-closed): ${err instanceof Error ? err.message : String(err)}`);
3335
3375
  }
3336
3376
  const pendingIntents = plan.intents.filter((i) => i.state === "pending" && standingCredentials[i.requestId] === undefined).map((i) => i.requestId);
3377
+ if (pendingIntents.length === 0) {
3378
+ throw new ConsolidationRefusedError("memory.consolidation_refused", `memory consolidation retry refused: plan ${planId} has nothing to re-judge — ` +
3379
+ (plan.intents.length === 0
3380
+ ? "it carries no intents (a conflicted product never rides a retry)"
3381
+ : "every unfulfilled intent already carries a credential (consumed by an earlier retry or a racing plan)") +
3382
+ ` — a plan with nothing to apply must not settle as a completed run (the vacuous completion would stamp the eligible set into the fingerprint and blind the incremental face); resolve with "discard" to release the seat.`);
3383
+ }
3384
+ const conflictProductInputIds = [];
3385
+ for (const p of plan.products) {
3386
+ if (plan.productStates[p.id] !== "conflict")
3387
+ continue;
3388
+ const inputs = p.frontmatter?.distilled?.inputs;
3389
+ if (!Array.isArray(inputs) || inputs.some((i) => typeof i?.["id"] !== "string")) {
3390
+ throw new ConsolidationRefusedError("memory.consolidation_refused", `memory consolidation retry refused: conflicted product ${p.id} carries no readable distilled attribution rows (every frozen product is minted with them — this is control-plane damage); the plan stays parked, resolve with "discard" (the bytes remain on the plan file for host review).`);
3391
+ }
3392
+ for (const i of inputs)
3393
+ conflictProductInputIds.push(i.id);
3394
+ }
3337
3395
  const face = this.committedAuditFace();
3338
3396
  const originalIntents = await this.reconstructIntentsForRetry(plan, pendingIntents, face);
3339
3397
  const retryPlanId = uuidv7();
@@ -3347,8 +3405,9 @@ export class MemoryEngine {
3347
3405
  file.scopes[plan.scope] = row;
3348
3406
  return { next: file, result: undefined };
3349
3407
  });
3408
+ const inheritedRefusals = [...new Set([...(plan.freezeRefusedInputIds ?? []), ...conflictProductInputIds])].sort();
3350
3409
  const retryPlan = {
3351
- v: 1,
3410
+ v: inheritedRefusals.length > 0 ? 2 : 1,
3352
3411
  planId: retryPlanId,
3353
3412
  scope: plan.scope,
3354
3413
  requestId: opts.requestId,
@@ -3357,6 +3416,7 @@ export class MemoryEngine {
3357
3416
  visibleMarked: false,
3358
3417
  products: [],
3359
3418
  productStates: {},
3419
+ ...(inheritedRefusals.length > 0 ? { freezeRefusedInputIds: inheritedRefusals } : {}),
3360
3420
  directed: originalIntents.directed,
3361
3421
  intents: pendingIntents.map((r) => ({ requestId: r, state: "pending" })),
3362
3422
  state: "open",
@@ -3436,6 +3496,35 @@ export class MemoryEngine {
3436
3496
  }
3437
3497
  return out;
3438
3498
  }
3499
+ readConsolidationPlanFoldEvidence(planId) {
3500
+ const read = readConsolidationPlan(this.controlDir, planId);
3501
+ if (read.state === "absent")
3502
+ return { state: "absent" };
3503
+ if (read.state === "corrupt")
3504
+ return { state: "corrupt", detail: read.detail };
3505
+ const p = read.plan;
3506
+ const targets = new Set();
3507
+ for (const prod of p.products) {
3508
+ if (p.productStates[prod.id] !== "applied")
3509
+ continue;
3510
+ const inputs = prod.frontmatter?.distilled?.inputs;
3511
+ const anchors = { scope: p.scope, requestId: p.requestId };
3512
+ if (inputs === undefined)
3513
+ return { state: "corrupt", detail: `applied product ${prod.id} carries no distilled.inputs (every frozen product is minted with its attribution rows)`, ...anchors };
3514
+ if (!Array.isArray(inputs))
3515
+ return { state: "corrupt", detail: `applied product ${prod.id} carries a non-array distilled.inputs`, ...anchors };
3516
+ for (const i of inputs) {
3517
+ if (typeof i !== "object" || i === null)
3518
+ return { state: "corrupt", detail: `applied product ${prod.id} carries a malformed distilled input row`, ...anchors };
3519
+ if (i.superseded !== true)
3520
+ continue;
3521
+ if (typeof i.id !== "string")
3522
+ return { state: "corrupt", detail: `applied product ${prod.id} carries a supersession edge without a string target id`, ...anchors };
3523
+ targets.add(i.id);
3524
+ }
3525
+ }
3526
+ return { state: "ok", scope: p.scope, requestId: p.requestId, planState: p.state, supersededTargets: [...targets].sort() };
3527
+ }
3439
3528
  readConsolidationGate(scope) {
3440
3529
  try {
3441
3530
  return readConsolidationGateFile(this.controlDir).scopes[scope];
@@ -3444,6 +3533,43 @@ export class MemoryEngine {
3444
3533
  return undefined;
3445
3534
  }
3446
3535
  }
3536
+ readConsolidationGateState(scope) {
3537
+ let row;
3538
+ try {
3539
+ row = readConsolidationGateFile(this.controlDir).scopes[scope];
3540
+ }
3541
+ catch (err) {
3542
+ return { state: "corrupt", detail: err instanceof Error ? err.message : String(err) };
3543
+ }
3544
+ return row !== undefined ? { state: "present", row } : { state: "absent" };
3545
+ }
3546
+ async readConsolidationFoldState(scope) {
3547
+ const face = this.committedAuditFace();
3548
+ const headers = await face.listHeaders([scope]);
3549
+ let exclusions;
3550
+ try {
3551
+ exclusions = this.readChallengeExclusions();
3552
+ }
3553
+ catch (err) {
3554
+ throw new ConsolidationRefusedError("memory.consolidation_governance_unreadable", `memory consolidation fold-state read refused: the challenge/lineage ledger cannot be trusted (fail-closed): ${err instanceof Error ? err.message : String(err)}`);
3555
+ }
3556
+ const superseded = deriveSupersededSet(headers, { excluded: (id) => exclusions.has(id) });
3557
+ return {
3558
+ active: headers.filter((h) => !superseded.has(h.id) && !exclusions.has(h.id)).length,
3559
+ superseded: superseded.size,
3560
+ products: headers.filter((h) => h.distilled !== undefined).length,
3561
+ };
3562
+ }
3563
+ get controlPlaneRoot() {
3564
+ return this.controlDir;
3565
+ }
3566
+ async listMemoryScopes() {
3567
+ const b = this.backend;
3568
+ if (typeof b.listScopes !== "function") {
3569
+ return { supported: false, reason: "the backend does not implement scope enumeration (listScopes) — an absent capability must never read as an empty scope list" };
3570
+ }
3571
+ return await b.listScopes();
3572
+ }
3447
3573
  committedAuditFace() {
3448
3574
  const b = this.backend;
3449
3575
  return b.restrictedAdoptionView?.({ audit: false }) ?? b.retrievalView?.() ?? this.backend;
@@ -1,6 +1,6 @@
1
1
  import { scopeDirName, type ChallengeEvent, type MemoryPartitionIncidentSink } from "./layout.js";
2
2
  import type { MemoryBundleImportPlan, MemoryImportReport } from "./export-bundle.js";
3
- import type { HarvestRejection, MemoryBackend, MemoryEntry, MemoryEntryHeader, NotePatch, PatchReport, ScoredMemoryEntry } from "./types.js";
3
+ import type { HarvestRejection, MemoryBackend, MemoryEntry, MemoryEntryHeader, MemoryScopeEnumeration, NotePatch, PatchReport, ScoredMemoryEntry } from "./types.js";
4
4
  /** Files/dirs the entry scan never treats as entries: the derived index, dotfiles (`.hydrate`,
5
5
  * transaction staging files), and anything not `.md`. */
6
6
  export declare const MEMORY_INDEX_FILENAME = "MEMORY.md";
@@ -357,7 +357,7 @@ export interface FileMemoryEngineBackendOptions {
357
357
  onIncident?: MemoryPartitionIncidentSink;
358
358
  }
359
359
  /**
360
- * ⚠️ DEPLOYMENT BOUNDARY (N0 定谳,channel 给service-AI.md [412],2026-07-09):this backend — and the
360
+ * ⚠️ DEPLOYMENT BOUNDARY (ruled 2026-07-09): this backend — and the
361
361
  * file memory engine's materialize/harvest — operates on the WORKER-HOST fs plane (node:fs), matching
362
362
  * CC's `~/.claude` host-plane memory (the only behavior anchor). It is NOT ExecutionEnv-aware: when a
363
363
  * deployment routes the model's file tools to a REMOTE sandbox (e2b/k8s/ssh/adb/local-docker), the two
@@ -756,6 +756,18 @@ export declare class FileMemoryEngineBackend implements MemoryBackend {
756
756
  * while a live holder exists ({@link txnInFlight}), which now covers adoption holds too.
757
757
  */
758
758
  private readScopeAdopting;
759
+ /**
760
+ * design/376 slice ③ (#437③) — the File leg's scope-enumeration capability face: every scope
761
+ * this store has hosted, derived from the store root's durable scope registry (the control
762
+ * plane's `scopes.json` — the one source that can invert a scope's sanitized directory label
763
+ * back to its name; a listing of raw subdirectories could not). Side-effect-free committed
764
+ * read; a corrupt/unreadable registry THROWS its fail-closed refusal — enumeration over an
765
+ * untrustworthy registry must never answer an empty (= clean-looking) list. Honest residual,
766
+ * disclosed: the registry records scopes as they are first touched THROUGH this control plane,
767
+ * so a hand-assembled tree's never-touched scope dirs appear here only once a caller first
768
+ * names them — store-level fact, session-roster-free either way.
769
+ */
770
+ listScopes(): MemoryScopeEnumeration;
759
771
  listHeaders(scopes: readonly string[]): Promise<MemoryEntryHeader[]>;
760
772
  private listHeadersFrom;
761
773
  getByIds(ids: readonly string[]): Promise<MemoryEntry[]>;
@@ -1780,6 +1780,9 @@ export class FileMemoryEngineBackend {
1780
1780
  lock.release();
1781
1781
  }
1782
1782
  }
1783
+ listScopes() {
1784
+ return { supported: true, scopes: Object.keys(registeredScopes(this.controlPlaneRoot)).sort() };
1785
+ }
1783
1786
  async listHeaders(scopes) {
1784
1787
  return this.listHeadersFrom(scopes, (s) => this.readScopeAdopting(s));
1785
1788
  }
@@ -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, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationRefusedNotice, type ConsolidationCommitReceipt, type ConsolidationReconcileReport, type ConsolidationResolveReceipt, type ConsolidationPlanSummary, } 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, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, type ConsolidationCommitReceipt, type ConsolidationReconcileReport, type ConsolidationResolveReceipt, type ConsolidationPlanSummary, type ConsolidationPlanFoldEvidence, } 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";
@@ -8,9 +8,12 @@ export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlane
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
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";
11
+ export { CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, type ConsolidationGateRead, type ConsolidationGateRow, type ConsolidationIntent, type ConsolidationIntentCredentialRow, type ConsolidationLeaseSeat, type ConsolidationProductProposal, type ConsolidationProposal, type MemoryConsolidationOptions, CONSOLIDATION_RUN_STOP_REASONS, type ConsolidationRunStopReason, } from "./consolidation.js";
12
+ export { DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintLlmConsolidationPlan, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, type ConsolidationDistillFn, type ConsolidationDriveCycleRow, type ConsolidationDriveEngine, type ConsolidationDriveResult, type ConsolidationFoldState, type DistillerCandidate, type DistillerChatAnswer, type DistillerChatFn, type DistillerChatRequest, type FuseSchedule, type LlmConsolidationPlan, type LlmConsolidationPlanProduct, type LlmDistillerContract, type MintLlmConsolidationPlanResult, type PlanParseRepairs, type SanitizedLlmGroups, } from "./distiller.js";
13
+ export { CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, type ConsolidationDriverEngine, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type RunMemoryConsolidationOptions, } from "./consolidation-driver.js";
14
+ export type { OriginClearanceRow, OriginClearanceEvent } from "./origin-clearance.js";
12
15
  export { MEMORY_ORIGIN_CAUSES } 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";
16
+ export type { MemoryBackend, MemoryEntry, MemoryEntryFrontmatter, MemoryEntryOrigin, MemoryOriginCause, MemoryScopeEnumeration, MemoryEntryDistilled, MemoryEntryDistilledInput, MemoryEntryHeader, ScoredMemoryEntry, NotePatch, PatchReport, MaterializedFile, MemorySessionHandle, HarvestReport, HarvestRejection, HarvestRejectionCode, MemoryAnnouncement, ScanFinding, } from "./types.js";
14
17
  export { memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, } from "./memory-backend-contract.js";
15
18
  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";
16
19
  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, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationRefusedNotice, } 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, memoryConsolidationIncompleteNotice, 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";
@@ -8,7 +8,9 @@ export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlane
8
8
  export { readV2HeaderHints, isInstructionEntry } from "./header-hints.js";
9
9
  export { parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, committedOriginOf, originEquals, ambiguousOriginRepresentation } from "./frontmatter.js";
10
10
  export { committedDistilledOf, distilledEquals } from "./frontmatter.js";
11
- export { CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, } from "./consolidation.js";
11
+ export { CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, CONSOLIDATION_RUN_STOP_REASONS, } from "./consolidation.js";
12
+ export { DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintLlmConsolidationPlan, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, } from "./distiller.js";
13
+ export { CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, } from "./consolidation-driver.js";
12
14
  export { MEMORY_ORIGIN_CAUSES } from "./types.js";
13
15
  export { memoryBackendContract, assertMemoryBackendSearchEquivalence, } from "./memory-backend-contract.js";
14
16
  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";