@sema-agent/core 5.57.0 → 5.58.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 (183) hide show
  1. package/CHANGELOG.md +48 -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/status-sink.d.ts +2 -2
  20. package/dist/brain/stream-shared.d.ts +1 -1
  21. package/dist/config/catalog.d.ts +5 -5
  22. package/dist/core/arg-summary.d.ts +4 -4
  23. package/dist/core/ask-class.d.ts +2 -2
  24. package/dist/core/ask-question.d.ts +1 -1
  25. package/dist/core/auto-compaction.d.ts +15 -15
  26. package/dist/core/auto-mode.d.ts +5 -5
  27. package/dist/core/background-agent-store.d.ts +20 -20
  28. package/dist/core/background-shell.d.ts +4 -4
  29. package/dist/core/checkpoint-store.d.ts +35 -27
  30. package/dist/core/context-edit.d.ts +1 -1
  31. package/dist/core/context-guard.d.ts +1 -1
  32. package/dist/core/exec-output-tail.d.ts +6 -6
  33. package/dist/core/file-snapshot-store.d.ts +8 -8
  34. package/dist/core/git-worktree-env.d.ts +3 -3
  35. package/dist/core/governance-codes.js +2 -0
  36. package/dist/core/hooks.d.ts +73 -33
  37. package/dist/core/hooks.js +87 -25
  38. package/dist/core/image-downsample.d.ts +1 -1
  39. package/dist/core/locked-config.d.ts +1 -1
  40. package/dist/core/lsp.d.ts +1 -1
  41. package/dist/core/mailbox-store.d.ts +1 -1
  42. package/dist/core/mcp.d.ts +3 -3
  43. package/dist/core/memory-engine/consolidation-driver.d.ts +207 -0
  44. package/dist/core/memory-engine/consolidation-driver.js +378 -0
  45. package/dist/core/memory-engine/consolidation.d.ts +46 -2
  46. package/dist/core/memory-engine/consolidation.js +1 -0
  47. package/dist/core/memory-engine/data-plane.d.ts +1 -1
  48. package/dist/core/memory-engine/distiller.d.ts +550 -0
  49. package/dist/core/memory-engine/distiller.js +598 -0
  50. package/dist/core/memory-engine/dual-root.d.ts +1 -1
  51. package/dist/core/memory-engine/engine.d.ts +47 -3
  52. package/dist/core/memory-engine/engine.js +37 -3
  53. package/dist/core/memory-engine/file-backend.d.ts +1 -1
  54. package/dist/core/memory-engine/index.d.ts +4 -2
  55. package/dist/core/memory-engine/index.js +4 -2
  56. package/dist/core/memory-engine/origin-clearance.d.ts +1 -1
  57. package/dist/core/memory-engine/scope-contract.d.ts +4 -4
  58. package/dist/core/memory-engine/sync-client.d.ts +16 -16
  59. package/dist/core/memory-engine/sync.d.ts +4 -4
  60. package/dist/core/memory-recall.d.ts +1 -1
  61. package/dist/core/memory.d.ts +2 -2
  62. package/dist/core/permission-rule-consent.d.ts +185 -36
  63. package/dist/core/permission-rule-consent.js +219 -44
  64. package/dist/core/permission-rule-model.d.ts +194 -31
  65. package/dist/core/permission-rule-model.js +93 -35
  66. package/dist/core/permission-rules.d.ts +9 -9
  67. package/dist/core/remote-env.d.ts +8 -8
  68. package/dist/core/roles.d.ts +3 -3
  69. package/dist/core/roles.js +1 -0
  70. package/dist/core/runner/assemble-result.d.ts +2 -2
  71. package/dist/core/runner/compaction-call-options.d.ts +3 -3
  72. package/dist/core/runner/memory-consolidation-driver.d.ts +49 -0
  73. package/dist/core/runner/memory-consolidation-driver.js +60 -0
  74. package/dist/core/runner/memory-consolidation.d.ts +1 -1
  75. package/dist/core/runner/prepare-config-doors.d.ts +3 -3
  76. package/dist/core/runner/prepare-task.d.ts +21 -21
  77. package/dist/core/runner/prepare-task.js +21 -14
  78. package/dist/core/runner/prepare-workspace-restore.d.ts +2 -2
  79. package/dist/core/runner/runtask.d.ts +11 -11
  80. package/dist/core/runner/session-rule-policy.d.ts +1 -1
  81. package/dist/core/runner/teardown-bounded.d.ts +1 -1
  82. package/dist/core/runner/tool-disclosure.d.ts +2 -2
  83. package/dist/core/runner/turn-attachments.d.ts +11 -11
  84. package/dist/core/scheduler.d.ts +5 -5
  85. package/dist/core/secret-env.d.ts +1 -1
  86. package/dist/core/sensitive-path-policy.d.ts +1 -1
  87. package/dist/core/session-policy-store.d.ts +2 -2
  88. package/dist/core/session-reconcile.d.ts +2 -2
  89. package/dist/core/session-store.d.ts +3 -3
  90. package/dist/core/session.d.ts +1 -1
  91. package/dist/core/shutdown-debug.d.ts +2 -2
  92. package/dist/core/side-query.d.ts +2 -2
  93. package/dist/core/spec-contract.d.ts +1 -1
  94. package/dist/core/store-contracts/contract-harness.d.ts +2 -2
  95. package/dist/core/store-contracts/contract-kit-version.d.ts +2 -2
  96. package/dist/core/store-contracts/mailbox-store-contract.d.ts +1 -1
  97. package/dist/core/store-contracts/mailbox-store-contract.js +1 -1
  98. package/dist/core/task-notification.d.ts +5 -5
  99. package/dist/core/task-registry-agent.d.ts +12 -12
  100. package/dist/core/task-registry-monitor.d.ts +1 -1
  101. package/dist/core/task-registry-shared.d.ts +41 -41
  102. package/dist/core/task-registry.d.ts +12 -12
  103. package/dist/core/tool-detach.d.ts +2 -2
  104. package/dist/core/tool-errors.d.ts +3 -3
  105. package/dist/core/tool-policy.d.ts +55 -28
  106. package/dist/core/tool-result-budget.d.ts +1 -1
  107. package/dist/core/tool-result-store.d.ts +2 -2
  108. package/dist/core/tools.d.ts +1 -1
  109. package/dist/core/trace.d.ts +26 -23
  110. package/dist/core/types.d.ts +123 -70
  111. package/dist/core/untrusted-egress.d.ts +1 -1
  112. package/dist/core/untrusted-text.d.ts +7 -7
  113. package/dist/core/wiring-manifest.d.ts +5 -5
  114. package/dist/core/workflow-journal-store.d.ts +14 -14
  115. package/dist/core/workflow-run-store-contract.d.ts +1 -1
  116. package/dist/core/workflow-run-store-contract.js +1 -1
  117. package/dist/core/workflow-run-store.d.ts +4 -4
  118. package/dist/engine/compaction/compaction.d.ts +3 -3
  119. package/dist/engine/compaction/utils.d.ts +2 -2
  120. package/dist/engine/execution-env/kill-tree.d.ts +1 -1
  121. package/dist/engine/execution-env/node-execution-env.d.ts +8 -8
  122. package/dist/engine/harness/agent-harness.d.ts +6 -6
  123. package/dist/engine/harness/messages.d.ts +1 -1
  124. package/dist/engine/harness/types.d.ts +10 -10
  125. package/dist/engine/llm/types.d.ts +14 -14
  126. package/dist/engine/loop/agent-loop.d.ts +3 -3
  127. package/dist/engine/loop/types.d.ts +4 -4
  128. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  129. package/dist/engine/session/import-validate.d.ts +1 -1
  130. package/dist/engine/session/log-digest.d.ts +1 -1
  131. package/dist/engine/session/memory-repo.d.ts +2 -2
  132. package/dist/engine/session/session.d.ts +4 -4
  133. package/dist/fixtures/index.d.ts +4 -4
  134. package/dist/index.d.ts +5 -4
  135. package/dist/index.js +3 -2
  136. package/dist/orchestration/goal.d.ts +1 -1
  137. package/dist/orchestration/run-spec.d.ts +1 -1
  138. package/dist/orchestration/run-workflow-tool.d.ts +12 -12
  139. package/dist/orchestration/workflow-governance.d.ts +4 -4
  140. package/dist/orchestration/workflow-observe.d.ts +1 -1
  141. package/dist/orchestration/workflow-script-runner.d.ts +1 -1
  142. package/dist/orchestration/workflow-script-store.d.ts +9 -9
  143. package/dist/orchestration/workflow-size-guideline.d.ts +1 -1
  144. package/dist/orchestration/workflow-types.d.ts +5 -5
  145. package/dist/orchestration/workflow.d.ts +10 -10
  146. package/dist/prompt-assembly/artifact-store.d.ts +1 -1
  147. package/dist/prompt-assembly/artifact.d.ts +1 -1
  148. package/dist/prompt-assembly/assemble.d.ts +1 -1
  149. package/dist/prompt-assembly/composer.d.ts +2 -2
  150. package/dist/prompt-assembly/epoch.d.ts +2 -2
  151. package/dist/prompt-assembly/event-registry.d.ts +1 -1
  152. package/dist/prompt-assembly/explain.d.ts +3 -3
  153. package/dist/prompt-assembly/tool-catalog.d.ts +1 -1
  154. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -4
  155. package/dist/prompt-assembly/types.d.ts +12 -12
  156. package/dist/prompts/coordinator.d.ts +1 -1
  157. package/dist/prompts/default.d.ts +8 -8
  158. package/dist/prompts/simple-sections.d.ts +3 -3
  159. package/dist/prompts/supervisor.d.ts +2 -2
  160. package/dist/scenarios/full-body.d.ts +3 -3
  161. package/dist/scenarios/scenario-registry.d.ts +1 -1
  162. package/dist/stores/cc/sidecar-transcript.d.ts +3 -3
  163. package/dist/stores/file/fs-atomic.d.ts +2 -2
  164. package/dist/stores/file/index.d.ts +1 -1
  165. package/dist/stores/file/session-store.d.ts +2 -2
  166. package/dist/stores/file/workflow-journal-store.d.ts +4 -4
  167. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  168. package/dist/tools/fs/encoding.d.ts +4 -4
  169. package/dist/tools/fs/fs-bash.d.ts +3 -3
  170. package/dist/tools/fs/fs-pdf.d.ts +1 -1
  171. package/dist/tools/fs/fs-shared.d.ts +6 -6
  172. package/dist/tools/fs/index.d.ts +2 -2
  173. package/dist/tools/fs/notebook.d.ts +1 -1
  174. package/dist/tools/fs/pdf.d.ts +1 -1
  175. package/dist/tools/fs/read-deny.d.ts +1 -1
  176. package/dist/tools/fs/safety.d.ts +9 -9
  177. package/dist/tools/fs/search.d.ts +2 -2
  178. package/dist/tools/monitor.d.ts +3 -3
  179. package/dist/tools/task-list.d.ts +2 -2
  180. package/dist/tools/web.d.ts +4 -4
  181. package/dist/tools/worktree.d.ts +5 -5
  182. package/package.json +1 -1
  183. package/test/export-surface.snapshot.json +56 -3
@@ -256,7 +256,7 @@ export declare function riskSeverity(axes: {
256
256
  irreversible?: boolean;
257
257
  shell?: boolean;
258
258
  }): 1 | 2 | 3 | 4 | 5;
259
- /** design S1e (service [204]): the char cap for the {@link CheckpointSummary.toolInput} BOUNDED raw preview of a
259
+ /** design S1e: the char cap for the {@link CheckpointSummary.toolInput} BOUNDED raw preview of a
260
260
  * `tool_approval` pendingAction's `args` (`JSON.stringify`-ed). Caps the `listByScope` payload size; over-cap
261
261
  * is truncated with a trailing `…`. Bounded raw (NOT neutralized) — redaction is the consumer's job (echo-only). */
262
262
  export declare const MAX_TOOL_INPUT_PREVIEW_CHARS = 512;
@@ -340,8 +340,8 @@ export interface PendingSteerInput {
340
340
  * NO clock/random, so the SAME call ⇒ an IDENTICAL descriptor (pinned by a test).
341
341
  *
342
342
  * **Determinism contract = plain-DATA args** (the real flow: model-JSON / hook-rewritten plain objects). A
343
- * Proxy whose `ownKeys` trap returns a DIFFERENT key set per call is OUT OF CONTRACT — JS cannot detect a Proxy
344
- * (codex review Item 2), so its (display-only) digest may vary. This NEVER affects a security/budget/mint
343
+ * Proxy whose `ownKeys` trap returns a DIFFERENT key set per call is OUT OF CONTRACT — JS cannot detect a
344
+ * Proxy, so its (display-only) digest may vary. This NEVER affects a security/budget/mint
345
345
  * decision: `riskDescriptor` is INERT (no core path reads it to gate), so an out-of-contract input can at worst
346
346
  * degrade an inbox preview, never a permission outcome.
347
347
  *
@@ -695,22 +695,30 @@ export type PendingAction = {
695
695
  toolName: string;
696
696
  /** Post-hook (design/37-rewritten) args to execute on `allow`. */
697
697
  args: unknown;
698
- /** [1245] (additive) — the tool's approval display projection of `args`, minted alongside the
698
+ /** (additive) — the tool's approval display projection of `args`, minted alongside the
699
699
  * row (see AgentTool.approvalPreview; control-char-sanitized + 16KiB-clamped at mint).
700
700
  * **UNTRUSTED, ADVISORY**: inboxes must escape contextually and surface `args` alongside.
701
701
  * NEVER read by the resume path (args + boundInputHash stay the sole execution contract). */
702
702
  preview?: unknown;
703
- /** design/179 §4 (additive) — the persistable allow-rule forms this parked call could be covered by,
704
- * minted from the SAME post-hook args the row executes. Advisory display metadata for the approval
705
- * inbox's "stop asking me this" option; never read by the resume path, and never a rule by itself
706
- * (minting one goes through the approval-record protocol). Absent when no rule lane is armed, the
707
- * command is one the lane cannot speak for, or the parked ask is one a persisted rule could not
708
- * clear (mandated marks / a real-approval demand / a shadowed matching rule).
709
- * CONTRACT (same as the synchronous `AskRequest.ruleSuggestions`) array order is display order,
710
- * narrowest first: the EXACT form is always index 0, a broader reviewed PREFIX form (at most one)
711
- * follows; basis ≤ 2, and selection/ticket indices are keyed against this order. A row persisted
712
- * before the prefix arm existed carries ≤ 1 entry and stays valid under the same reading. */
713
- ruleSuggestions?: readonly import("./permission-rule-model.js").RuleSuggestion[];
703
+ /** design/179 §4, re-formed by design/375 §3.1/§3.3 (BREAKING replaces the retired
704
+ * `ruleSuggestions` seat; a pre-375 inbox reading a new row simply finds no offers and renders
705
+ * no "don't ask again" option, fail toward asking) the persistable allow-rule OFFERS this
706
+ * parked call could be covered by, minted from the SAME post-hook args the row executes.
707
+ * Advisory display metadata for the approval inbox's "stop asking me this" option; never read
708
+ * by the resume path, and never a rule by itself (minting one goes through the approval-record
709
+ * protocol). Absent when no rule lane is armed, the command is one the lane cannot speak for,
710
+ * or the parked ask is one a persisted rule could not clear (mandated marks / a real-approval
711
+ * demand / a shadowed matching rule).
712
+ * CONTRACT (same as the synchronous `AskRequest.ruleOffers` — see
713
+ * {@link import("./permission-rule-model.js").RuleOffer}): at most 2 offers, the whole-string
714
+ * EXACT single always index 0 when present, the BATCH offer (choosing it is one yes to ALL of
715
+ * its 1..5 per-segment rules at once) always last; selection indices are keyed against this
716
+ * order (redemption TICKETS are keyed on the consent record's flat CANDIDATE list instead —
717
+ * a chosen offer is redeemed via `redeemRuleBatch`), per-element parse with single-row
718
+ * degrade on an unknown `kind` and
719
+ * original-index preservation. The park→resume redemption chain walks the same consent
720
+ * protocol as the synchronous card — there is no second form. */
721
+ ruleOffers?: readonly import("./permission-rule-model.js").RuleOffer[];
714
722
  /**
715
723
  * design/80 D-1 §2 (slice 1a.2): the server-minted **opaque** boundInputHash of {@link args} — a
716
724
  * SHA-256 (hex) via {@link import("./canonical-json.js").boundInputHashOf}, computed ONCE here at
@@ -797,7 +805,7 @@ export interface CheckpointState {
797
805
  pattern: string;
798
806
  caseSensitive: boolean;
799
807
  }>;
800
- /** codex r2 — REDUNDANT governance marker: `true` iff the row's gate was minted WITH a
808
+ /** REDUNDANT governance marker: `true` iff the row's gate was minted WITH a
801
809
  * {@link RealApprovalGateBit}. v8's bit-required invariant was version-keyed and v9 (face)
802
810
  * outranks v8 in the stamp, so without this a v9 GOVERNED row whose `gate.realApproval` member
803
811
  * was dropped in storage would pass pre-CAS and be redeemable on an unwired worker — the exact
@@ -895,7 +903,7 @@ export interface CheckpointState {
895
903
  * :707384-707399 under the `CLAUDE_CODE_RESUME_INTERRUPTED_TURN` gate — the cloud-worker restart
896
904
  * leg, exactly sema's durable-resume shape): the background tasks (pending/running, this run's
897
905
  * owner triple) still ALIVE at suspend. Background processes never survive a suspend (design/103
898
- * §3.7 unconditional dispose + 飞轮 [506]③ killed receipts), so on resume any snapshot entry NOT
906
+ * §3.7 unconditional dispose + killed receipts), so on resume any snapshot entry NOT
899
907
  * alive in the resume leg's registry is an ORPHAN — aggregated into ONE CC-verbatim "The container
900
908
  * was restarted…" reminder appended to the resume continuation (single message: header +
901
909
  * `- description (task id)` list + re-create instruction; never a per-task barrage). A survivor
@@ -910,7 +918,7 @@ export interface CheckpointState {
910
918
  description?: string;
911
919
  }>;
912
920
  /**
913
- * codex 终审 1.255 F2: the hands band's LOGICAL working directory at suspend (`handsCwdRef.current` —
921
+ * the hands band's LOGICAL working directory at suspend (`handsCwdRef.current` —
914
922
  * moved by `cd` and by EnterWorktree). Without it a resume silently reset the task cwd to the task root:
915
923
  * relative Read/Edit/Write paths and Bash commands then operated somewhere else than the model believes.
916
924
  * Absent when the task has no tracked cwd (no real shell / read-only hands). The directory itself is
@@ -918,7 +926,7 @@ export interface CheckpointState {
918
926
  */
919
927
  handsCwd?: string;
920
928
  /**
921
- * codex 终审 1.255 F2: the ACTIVE EnterWorktree session at suspend (worktree.ts keeps it in a shared
929
+ * the ACTIVE EnterWorktree session at suspend (worktree.ts keeps it in a shared
922
930
  * serializable ref, not a closure-only var, precisely so it lands here). Without it a resume LOST the
923
931
  * session: ExitWorktree became a no-op (the unchanged worktree could never be removed), a second
924
932
  * EnterWorktree was wrongly accepted, and `handsCwd` pointed into a worktree the tooling no longer
@@ -1145,7 +1153,7 @@ export declare const TOKEN_CHECKPOINT_VERSION = 5;
1145
1153
  */
1146
1154
  export declare const ORG_ADMISSION_CHECKPOINT_VERSION = 6;
1147
1155
  /**
1148
- * F-012 (2026-08-09 — the ORG_ADMISSION_CHECKPOINT_VERSION precedent replayed a fifth time, codex
1156
+ * F-012 (2026-08-09 — the ORG_ADMISSION_CHECKPOINT_VERSION precedent replayed a fifth time
1149
1157
  * falsification-style finding): the schema version a suspend stamps when its state carries the F-012 durable
1150
1158
  * enforcement fields — `inheritedGate.constraintChain`/`constraintDigest` (the frozen ancestor
1151
1159
  * projection chain the resume-edit re-adjudication executes) or `delegationProvenance` (the monotonic
@@ -1463,7 +1471,7 @@ export interface Checkpoint {
1463
1471
  */
1464
1472
  rev?: number;
1465
1473
  /**
1466
- * design S1d (source-tag persistence, service [198]/[199]): the issuing task's session id, stamped at the
1474
+ * design S1d (source-tag persistence): the issuing task's session id, stamped at the
1467
1475
  * APPROVAL suspend mint so a supervisor inbox can attribute a paused/awaiting checkpoint to the worker that
1468
1476
  * raised it (the durable analog of {@link import("./tool-policy.js").AskRequest}.sourceTaskId — the durable
1469
1477
  * suspend path does NOT invoke `onAsk`, so the synchronous source identity is captured here instead). It is
@@ -1546,14 +1554,14 @@ export interface CheckpointSummary {
1546
1554
  * suspend — projected so the inbox shows WHICH call awaits a decision without an N+1 `getCheckpoint`.
1547
1555
  * `undefined` for a non-`tool_approval` pendingAction (resource_limit / plan_review / task_done).
1548
1556
  *
1549
- * **ABSENCE SHAPE (contract, [1995]②)** — shared by every optional field on this projection: a
1557
+ * **ABSENCE SHAPE (contract)** — shared by every optional field on this projection: a
1550
1558
  * tool-less park (`resource_limit` / `plan_review` / `task_done` — none of which binds a tool call)
1551
1559
  * gets the key **OMITTED**, never `null` and never a present-but-`undefined` property. The
1552
1560
  * `PendingAction` arms for those kinds declare no tool/binding fields at all, so there is nothing to
1553
1561
  * project; `summarizeCheckpoint` spreads them conditionally for exactly this reason. A consumer
1554
1562
  * therefore tests presence (`"toolCallId" in summary`), and a re-projecting service (BFF / SDK wire
1555
1563
  * face) must not materialize the keys as `null` on the way out. Pinned in
1556
- * `test/checkpoint-store.test.ts` ("[1995]②③ tool-less park …"). */
1564
+ * `test/checkpoint-store.test.ts` ("tool-less park …"). */
1557
1565
  toolCallId?: string;
1558
1566
  /** The pending tool's name ({@link PendingAction} `tool_approval.toolName`) when this is an approval suspend.
1559
1567
  * OMITTED (not `null`) for a non-`tool_approval` pendingAction — see {@link toolCallId}'s absence-shape note. */
@@ -1565,13 +1573,13 @@ export interface CheckpointSummary {
1565
1573
  * this lightweight `listByScope` projection). Deliberately NOT a new `content_ask` checkpoint gate kind (that
1566
1574
  * would cross the durable-checkpoint once-only-winner / reaper-deadline / batch invariants — the DoR). */
1567
1575
  contentKind?: "content_ask";
1568
- /** design S1e (service [204]): when the checkpoint was created ({@link Checkpoint.createdAt}, epoch ms) —
1576
+ /** design S1e: when the checkpoint was created ({@link Checkpoint.createdAt}, epoch ms) —
1569
1577
  * projected so a supervisor inbox can sort/age pending entries (oldest-first triage) in ONE `listByScope`
1570
1578
  * call, no N+1 `getCheckpoint`. ECHO-ONLY display/triage; always present (a Checkpoint always has a
1571
1579
  * `createdAt`). */
1572
1580
  createdAt?: number;
1573
1581
  /**
1574
- * design S1e (service [204]): a **BOUNDED, UNREDACTED** raw preview of the pending tool call's input
1582
+ * design S1e: a **BOUNDED, UNREDACTED** raw preview of the pending tool call's input
1575
1583
  * ({@link PendingAction} `tool_approval.args` `JSON.stringify`-ed, truncated to {@link
1576
1584
  * MAX_TOOL_INPUT_PREVIEW_CHARS} chars with a `…` marker when over) — projected so a supervisor inbox shows
1577
1585
  * WHAT a paused tool call will do without an N+1 `getCheckpoint`. `undefined` for a non-`tool_approval`
@@ -1600,7 +1608,7 @@ export interface CheckpointSummary {
1600
1608
  * workspace at all. ECHO-ONLY display/triage — nothing gates on it. Mirrors `TaskResult.workspaceRestoreMode`.
1601
1609
  */
1602
1610
  restoreMode?: "snapshot" | "park_only";
1603
- /** [1245] codex F2 — the tool's approval display projection ({@link PendingAction} `preview`),
1611
+ /** the tool's approval display projection ({@link PendingAction} `preview`),
1604
1612
  * projected so the ONE-CALL inbox (`listByScope`) can render a rich confirmation without an N+1
1605
1613
  * `get`. Same trust posture as `toolInput`: **UNTRUSTED, advisory display metadata** (strings are
1606
1614
  * sanitized of control chars at mint but may still carry model-authored markdown — renderers must
@@ -2180,7 +2188,7 @@ export interface CheckpointStore {
2180
2188
  */
2181
2189
  listByScope?(scope: string): Promise<CheckpointSummary[]>;
2182
2190
  /**
2183
- * server [1800] seam: the DISTINCT scopes that currently have at least one PENDING checkpoint — the
2191
+ * Deployment seam: the DISTINCT scopes that currently have at least one PENDING checkpoint — the
2184
2192
  * enumeration face `listByScope` lacks. A host keeping its own scope registry (e.g. a sidecar file for a
2185
2193
  * cross-scope inbox) can rebuild it from the data itself when the registry is lost/corrupt, instead of the
2186
2194
  * enumeration silently going empty and pending approvals turning invisible. Scoped to PENDING deliberately:
@@ -118,7 +118,7 @@ export interface ContextEditOptions {
118
118
  persist: (toolCallId: string, fullText: string) => string;
119
119
  };
120
120
  /**
121
- * design/123 D3 (codex-B1 = fable-M5) — ANCHORED accounting start: `estimateContextTokens(messages,
121
+ * design/123 D3 (= fable-M5) — ANCHORED accounting start: `estimateContextTokens(messages,
122
122
  * charsPerToken).tokens` for the SAME message array. When set, the trigger gate AND the internal
123
123
  * bookkeeping start from this usage-anchored value instead of the pure structural sum (which
124
124
  * underestimates code by ~25% and CJK by 60–75% — the defense would self-certify and pass
@@ -8,7 +8,7 @@ import type { Model } from "../internal/llm.js";
8
8
  * budget, dropping older regular messages at a safe boundary (never starting on an orphan
9
9
  * toolResult). Returns the original array when already within budget.
10
10
  *
11
- * design/123 D3 (codex-B1 = fable-M5) — anchored accounting: when `anchoredTotalTokens`
11
+ * design/123 D3 (= fable-M5) — anchored accounting: when `anchoredTotalTokens`
12
12
  * (= `estimateContextTokens(messages, charsPerToken).tokens` for the SAME array) is provided, the
13
13
  * trigger gate and the internal bookkeeping start from the usage-anchored value instead of the
14
14
  * structural sum (which underestimates code/CJK and lets over-window requests through). Dropping a
@@ -6,7 +6,7 @@
6
6
  * what the model needs) — dropping the head as it overflows, plus a count of dropped bytes for a visible marker.
7
7
  *
8
8
  * This lives in `src/core/` — NOT `src/vendor/` — on purpose: it is OUR robustness invariant, shared by the
9
- * (currently-vendored) NodeExecutionEnv AND a downstream exec adapter (service host/ssh/adb/docker/k8s, [267]).
9
+ * (currently-vendored) NodeExecutionEnv AND a downstream exec adapter (service host/ssh/adb/docker/k8s).
10
10
  * One implementation + ONE model-facing marker text = zero drift, and the public export points at a STABLE path
11
11
  * that survives the planned de-vendoring (when NodeExecutionEnv is naturalized out of `src/vendor/`, nothing rebinds).
12
12
  */
@@ -35,18 +35,18 @@ export declare class RollingTailBuffer {
35
35
  text: string;
36
36
  droppedBytes: number;
37
37
  };
38
- /** RB-234 ([1937]): the retained window's RAW bytes — cursor slicing must happen in the byte domain
38
+ /** RB-234: the retained window's RAW bytes — cursor slicing must happen in the byte domain
39
39
  * (re-encoding a lossily-decoded string inflates every invalid byte to a 3-byte U+FFFD and lands
40
40
  * byte cursors on the wrong offsets). */
41
41
  bytes(): Buffer;
42
- /** RB-234 ([1937]): head-eviction count ALONE — the retention window is [headDroppedBytes, pushed-total)
42
+ /** RB-234: head-eviction count ALONE — the retention window is [headDroppedBytes, pushed-total)
43
43
  * in the accepted-byte domain; source skips must not shift this origin. */
44
44
  headDroppedBytes(): number;
45
- /** RB-234 ([1937]): source-skip count alone (see {@link recordSkippedBytes}) — poll disclosure reports
45
+ /** RB-234: source-skip count alone (see {@link recordSkippedBytes}) — poll disclosure reports
46
46
  * the per-poll increment of this figure instead of silently absorbing it into the window origin. */
47
47
  sourceSkippedBytes(): number;
48
48
  }
49
- /** RB-234 ([1937]): per-stream cursor state for incremental (poll-style) consumption of a
49
+ /** RB-234: per-stream cursor state for incremental (poll-style) consumption of a
50
50
  * {@link RollingTailBuffer}. All counters live in the ACCEPTED-byte domain (bytes actually pushed);
51
51
  * source skips are tracked separately for disclosure. Module-level export (not on the package
52
52
  * surface) so the slice arithmetic is unit-pinnable without an 8MB integration harness. */
@@ -65,7 +65,7 @@ export interface StreamCursorState {
65
65
  /** Fresh cursor state over a new tail. */
66
66
  export declare function newStreamCursorState(tail?: RollingTailBuffer): StreamCursorState;
67
67
  /**
68
- * RB-234 ([1937]): slice the undelivered increment out of a rolling tail — in the BYTE domain, decoded
68
+ * RB-234: slice the undelivered increment out of a rolling tail — in the BYTE domain, decoded
69
69
  * incrementally. Replaces the former decode→re-encode→byte-offset-subarray shape, which mixed two
70
70
  * domains: byte cursors landed inside a re-encoded string whose length differs from the raw stream as
71
71
  * soon as any invalid-UTF-8 byte sits in the window (each inflates to a 3-byte U+FFFD), making every
@@ -1,5 +1,5 @@
1
1
  /** rel path of `child` under `root` in "/" form (win root) / verbatim form (posix root); null when not under.
2
- * codex 1.237 F7: fold "\" only under a WIN-family root ({@link isWinFormPath}); a POSIX tree may legally
2
+ * fold "\" only under a WIN-family root ({@link isWinFormPath}); a POSIX tree may legally
3
3
  * contain literal backslashes in FILE NAMES, and folding them corrupted both the manifest key and the
4
4
  * restore target. */
5
5
  declare function relUnder(root: string, child: string): string | null;
@@ -41,20 +41,20 @@ export interface FileSnapshotStore {
41
41
  reap(scope: string, keepKeys: string[]): Promise<number>;
42
42
  /** Every snapshot key in `scope` (order unspecified). The enumeration counterpart of {@link reap} (which
43
43
  * already iterates the same set internally) — exposed for a cross-backend session EXPORT (service 2c
44
- * session-sync, [266]): list a session's snapshot keys to move its {entries + file snapshots} to another
44
+ * session-sync): list a session's snapshot keys to move its {entries + file snapshots} to another
45
45
  * backend. A durable backend implements it as a `SELECT key WHERE scope = ?`. */
46
46
  listKeys(scope: string): Promise<string[]>;
47
47
  /**
48
- * 2c session-sync ([271]): the manifest (`relPath → blobHash`) for `(scope, key)`, or `null` if absent — to
48
+ * 2c session-sync: the manifest (`relPath → blobHash`) for `(scope, key)`, or `null` if absent — to
49
49
  * EXPORT a snapshot's content to another backend. Pairs with {@link getBlob} for CONTENT-ADDRESSED (deduped)
50
50
  * blob transfer: the caller fetches each distinct hash ONCE across all of a session's snapshots. Optional — a
51
51
  * backend that supports cross-backend snapshot export implements it.
52
52
  */
53
53
  exportManifest?(scope: string, key: string): Promise<Map<string, string> | null>;
54
- /** 2c session-sync ([271]): the content-addressed bytes for `hash` (undefined if absent). */
54
+ /** 2c session-sync: the content-addressed bytes for `hash` (undefined if absent). */
55
55
  getBlob?(hash: string): Promise<Uint8Array | undefined>;
56
56
  /**
57
- * 2c session-sync ([273]): STORE a snapshot INTO this store from another store's {@link exportManifest} +
57
+ * 2c session-sync: STORE a snapshot INTO this store from another store's {@link exportManifest} +
58
58
  * {@link getBlob} output — the import-side mirror that closes the cross-backend transfer loop. For each DISTINCT
59
59
  * blob hash in `manifest`, fetch its bytes via `srcGetBlob`, VERIFY content-address integrity
60
60
  * (`sha256(bytes) === hash`), and store it (content-addressed dedup); THEN record `(scope, key) → manifest`.
@@ -70,7 +70,7 @@ export interface FileSnapshotStore {
70
70
  */
71
71
  importManifest?(scope: string, key: string, manifest: Map<string, string>, srcGetBlob: (hash: string) => Promise<Uint8Array | undefined>): Promise<FileSnapshotResult>;
72
72
  /**
73
- * 2c session-sync ([277]): STORE a single content-addressed blob — the symmetric WRITE side of {@link getBlob},
73
+ * 2c session-sync: STORE a single content-addressed blob — the symmetric WRITE side of {@link getBlob},
74
74
  * for a two-phase PUSH (upload blobs, THEN import the manifest that references them). VERIFIES content-address
75
75
  * integrity (`sha256(bytes) === hash`) so a corrupt/mismatched upload can never contaminate the store (a later
76
76
  * getBlob/restore would otherwise return wrong content); a mismatch → `read_failed`, nothing stored. IMMUTABLE +
@@ -105,7 +105,7 @@ export declare const DEFAULT_SNAPSHOT_BOUNDS: FileSnapshotBounds;
105
105
  * bugs the dual-review fixed). Fail-CLOSED: an enumerate/read/bound failure returns an error and the caller must
106
106
  * NOT persist a partial manifest. Never throws.
107
107
  *
108
- * [789] vanished-file tolerance: a file that DISAPPEARED between enumerate and read (`not_found`) is OMITTED
108
+ * vanished-file tolerance: a file that DISAPPEARED between enumerate and read (`not_found`) is OMITTED
109
109
  * from the manifest instead of failing the whole capture. This is semantically SAFE — the E19 snapshot runs
110
110
  * concurrently with a live tree (the `done` frame is emitted BEFORE the snapshot, so shell-side per-turn
111
111
  * markers, `.git/index.lock`, editor swap files etc. legitimately vanish mid-walk), and omitting a
@@ -128,7 +128,7 @@ export declare function captureManifest(env: ExecutionEnv, root: string, bounds:
128
128
  }>;
129
129
  /**
130
130
  * CONVERGE the tree under `root` to `manifest`, loading each captured file's bytes via `getBlob`. **The
131
- * env-operating + security-critical half a durable backend MUST reuse.** Order is load-bearing (codex BLOCKER +
131
+ * env-operating + security-critical half a durable backend MUST reuse.** Order is load-bearing (+
132
132
  * Opus M1): PHASE 1 removes every current symlink (neutralizes a `dir -> /outside` ancestor that writeFile would
133
133
  * otherwise follow OUT of root) + every file created since; PHASE 2 writes each captured file, clearing a
134
134
  * directory that now occupies a file's path first. Never throws.
@@ -23,8 +23,8 @@ export interface AddWorktreeOptions {
23
23
  * when its `ctx.isolation === "worktree"` and returns the result (with `destroy`); for a non-isolated task it
24
24
  * returns the SHARED base env (no `destroy`) so the Runner never tears the base down.
25
25
  *
26
- * ISOLATE-ONLY (clay): the runtime never merges — the orchestrator script reads each worktree's result and
27
- * decides verify/merge in userland. Caveats (codex review): `git worktree` isolates the git WORKING COPY, not
26
+ * ISOLATE-ONLY: the runtime never merges — the orchestrator script reads each worktree's result and
27
+ * decides verify/merge in userland. Caveats: `git worktree` isolates the git WORKING COPY, not
28
28
  * arbitrary shell access (bash can still reach the host — sandbox separately); UNCOMMITTED changes in the base
29
29
  * repo are absent in the child (detached HEAD); a worktree orphaned by a process crash is reaped by
30
30
  * {@link pruneWorktrees} (userland — there is no Runner hook for post-kill cleanup).
@@ -41,7 +41,7 @@ export declare function addWorktree(baseEnv: ExecutionEnv, opts: AddWorktreeOpti
41
41
  * HRD-PTL-11: the exec Result used to be discarded, so every caller had to ASSUME the prune landed — and
42
42
  * ExitWorktree's "already gone externally" leg told the model "stale git worktree metadata was pruned"
43
43
  * on a claim it could not have checked. Same fail-loud treatment {@link removeWorktree} already got
44
- * (server [1796]②): report the outcome, let the caller decide what to say. Never throws (a throwing env
44
+ * Report the outcome, let the caller decide what to say. Never throws (a throwing env
45
45
  * lands on the same `{ok:false}`), so a caller that ignores the value behaves exactly as before. */
46
46
  export declare function pruneWorktrees(baseEnv: ExecutionEnv, repoRoot: string): Promise<{
47
47
  ok: true;
@@ -17,11 +17,13 @@ export const NON_GOVERNANCE_MEMORY_CODES = new Set([
17
17
  "memory.session_polluted",
18
18
  "memory.harvest_quarantined",
19
19
  "memory.delegation_static_mark_waived",
20
+ "memory.consolidation_driver_superseded",
20
21
  "memory.challenge_sweep_failed",
21
22
  "memory.lineage_settle_failed",
22
23
  "memory.challenge_ledger_corrupt",
23
24
  "memory.consolidation_recommended",
24
25
  "memory.consolidation_committed",
26
+ "memory.consolidation_incomplete",
25
27
  "memory.consolidation_conflict",
26
28
  "memory.consolidation_refused",
27
29
  "memory.consolidation_disabled",
@@ -161,7 +161,7 @@ export interface Hooks {
161
161
  */
162
162
  stopFailure?(ctx: StopFailureContext): void | Promise<void>;
163
163
  /**
164
- * design/134 R5 (CC PermissionDenied parity, SDK 0.3.202 — service [418]③): runs when the tool gate's
164
+ * design/134 R5 (CC PermissionDenied parity, SDK 0.3.202): runs when the tool gate's
165
165
  * adjudicate chain DENY-SHORT-CIRCUITS a tool call — a ToolPolicy deny, a gate tighten (egress /
166
166
  * irreversibility / coarse shellGate) whose `ask` resolved to deny (headless auto-deny included), or the
167
167
  * plan-mode write-deny. Closes the observation blind spot where a blocked call fires NEITHER postToolUse
@@ -525,7 +525,7 @@ export interface StopHookContext {
525
525
  /** Consecutive blocks so far in this run (resets when a stop() call lets the run proceed). */
526
526
  consecutiveBlocks: number;
527
527
  /**
528
- * RB-177 ([1730], measured downstream) — a view of the conversation this hook is being asked to judge.
528
+ * RB-177 (measured downstream) — a view of the conversation this hook is being asked to judge.
529
529
  *
530
530
  * Until now a Stop hook received two counters and nothing else. That is enough for a hook that asks
531
531
  * "have I blocked too often?", and structurally insufficient for the entire class of hooks that ask
@@ -732,7 +732,7 @@ export interface HookInvocationIdentity {
732
732
  * other absence-signaling face this module mints — "absent member" must be a fact about THIS object,
733
733
  * and a frozen object with an ordinary prototype still answers `insideFork`/`agentName` reads (and
734
734
  * `in` probes) from `Object.prototype`, so a prototype write elsewhere in the process could hand
735
- * every leg a delegation axis the mint never stamped (codex r1). `agentName` is sanitized here — it
735
+ * every leg a delegation axis the mint never stamped. `agentName` is sanitized here — it
736
736
  * is the only member whose value a model influences.
737
737
  */
738
738
  export declare function mintHookInvocationIdentity(facts: HookInvocationIdentity): HookInvocationIdentity;
@@ -986,20 +986,33 @@ export type OrgGateVerdict = {
986
986
  /** The overlay's own disclosure lines (engine/deployment-authored), for the operator channel. */
987
987
  disclosures: readonly string[];
988
988
  };
989
+ /** One member of a {@link PersistedRuleHit} coverage set: a rule's canonical text plus (optionally)
990
+ * its add-dot identity. */
991
+ export interface PersistedRuleHitRule {
992
+ /** The canonical text of one admitting rule. */
993
+ readonly rule: string;
994
+ /** The rule's LIVE add dots (tombstoned adds already filtered by the store's read). Omitted by a
995
+ * lane that has the text but not the dots; the evidence then reports `"not_reported"`. */
996
+ readonly dots?: readonly import("./permission-rule-model.js").RuleDot[];
997
+ }
989
998
  /**
990
- * design/252 G-2 — the richer answer a persisted-rule lane may give instead of the bare rule text (see
991
- * `ToolGateInput.persistedRules.admits`): the same canonical text, plus the matched rule's add dots.
999
+ * design/252 G-2, re-formed by design/375 (BREAKING) — the structured answer a persisted-rule lane
1000
+ * gives: the COVERAGE SET that admits the call. A single rule admitting the whole command is a
1001
+ * one-element set (the historical case); a compound admitted by the conjunction of per-segment rules
1002
+ * (design/375 §5.1) is the set of those rules, in segment order. `rules` is non-empty by contract —
1003
+ * an empty set covers nothing and is not a hit (the normalizer reads it as a clean negative).
992
1004
  *
993
- * Why the dots and not an id: a persisted allow rule HAS no scalar id — it is a (text, scope) group
994
- * whose identity is the set of add dots that redeemed it, and two concurrently approved records for one
995
- * text each carry their own. The set is the identity; a joined string would not be one.
1005
+ * Why dots and not an id: a persisted allow rule HAS no scalar id — it is a (text, scope) group whose
1006
+ * identity is the set of add dots that redeemed it, and two concurrently approved records for one text
1007
+ * each carry their own. The set is the identity; a joined string would not be one.
1008
+ *
1009
+ * The pre-375 single-rule object shape (`{ rule, dots? }`) is NOT accepted: on this loosening seam an
1010
+ * unrecognized answer degrades to a clean negative (more asks), never to a match — the safe failure
1011
+ * shape for a lane that missed the same-window upgrade.
996
1012
  */
997
1013
  export interface PersistedRuleHit {
998
- /** The canonical text of the admitting rule the same value the bare-string shape returns. */
999
- readonly rule: string;
1000
- /** The matched rule's LIVE add dots (tombstoned adds already filtered by the store's read). Omitted
1001
- * by a lane that has the text but not the dots; the evidence then reports `"not_reported"`. */
1002
- readonly dots?: readonly import("./permission-rule-model.js").RuleDot[];
1014
+ /** The coverage set every rule the decision stands on. Non-empty. */
1015
+ readonly rules: readonly PersistedRuleHitRule[];
1003
1016
  }
1004
1017
  /**
1005
1018
  * design/252 G-2 — the answer a lane gives when it could not READ its store.
@@ -1014,8 +1027,20 @@ export interface PersistedRuleHit {
1014
1027
  export interface PersistedRuleUnreadable {
1015
1028
  readonly unreadable: true;
1016
1029
  }
1030
+ /**
1031
+ * design/375 §5.2② — the CLEAN NEGATIVE that still carries the per-segment coverage table: no rule
1032
+ * admits the whole call, and THESE segments are the ones an eligible rule already covers. Minted by
1033
+ * the lane from the SAME store read that adjudicated the call (snapshot = adjudication snapshot, no
1034
+ * second read), and consumed only by the suggestion face — which puts on the batch offer exactly the
1035
+ * segments this table calls uncovered. Its DECISION meaning is identical to "no rule": the seat is
1036
+ * advisory, and a lane that omits it (or an unreadable one) degrades to all-uncovered, which merely
1037
+ * over-offers (every offered rule still passes the validator at redemption).
1038
+ */
1039
+ export interface PersistedRuleCoverage {
1040
+ readonly segmentCoverage: readonly import("./permission-rule-model.js").SegmentCoverage[];
1041
+ }
1017
1042
  /** Every shape a lane may answer with. A bare string stays valid and unchanged. */
1018
- export type PersistedRuleAnswer = string | PersistedRuleHit | PersistedRuleUnreadable | undefined;
1043
+ export type PersistedRuleAnswer = string | PersistedRuleHit | PersistedRuleCoverage | PersistedRuleUnreadable | undefined;
1019
1044
  /**
1020
1045
  * design/252 review r3 — read a foreign {@link OrgGateVerdict} the way the personal-rule answer is read:
1021
1046
  * OWN DATA properties only, never the prototype chain, never an accessor.
@@ -1044,9 +1069,15 @@ export declare function normalizeOrgGateVerdict(answer: unknown, unreadable: str
1044
1069
  * Normalize the accepted {@link ToolGateInput.persistedRules} answers into one reading.
1045
1070
  *
1046
1071
  * `{}` = a clean negative (no rule admits this call). `{ unreadable: true }` = the lane could not read
1047
- * its source. `{ hit }` = a match. An answer outside every accepted shape a number, `null`, an object
1048
- * with no `rule`is read as a clean negative rather than a match: this is a LOOSENING seam, so an
1049
- * answer nobody can name degrades toward asking, never toward an allow built on it.
1072
+ * its source. `{ hit }` = a match, whose `rules` is the non-empty coverage set (design/375). An answer
1073
+ * outside every accepted shape — a number, `null`, an object with neither `rules` nor `unreadable`, an
1074
+ * EMPTY `rules` array, the retired pre-375 `{ rule, dots? }` single-rule object is read as a clean
1075
+ * negative rather than a match: this is a LOOSENING seam, so an answer nobody can name degrades toward
1076
+ * asking, never toward an allow built on it. All-or-nothing across the set's TEXTS for the same
1077
+ * reason: a set with one unreadable member is a different (smaller) claim than the lane made, and a
1078
+ * decision must not stand on a claim nobody made — one bad member drops the whole answer to the clean
1079
+ * negative. Per-member DOTS stay individually optional (identity lost ⇒ `"not_reported"`, exactly the
1080
+ * single-rule contract).
1050
1081
  *
1051
1082
  * The hit's dots are COPIED, not aliased. The array travels onto an ask that may sit in front of a
1052
1083
  * person for a long time; a lane that retains and mutates its own array would otherwise change what the
@@ -1055,6 +1086,7 @@ export declare function normalizeOrgGateVerdict(answer: unknown, unreadable: str
1055
1086
  export declare function normalizePersistedRuleHit(hit: PersistedRuleAnswer): {
1056
1087
  hit?: PersistedRuleHit;
1057
1088
  unreadable?: true;
1089
+ coverage?: readonly import("./permission-rule-model.js").SegmentCoverage[];
1058
1090
  };
1059
1091
  /** Inputs to the two-phase tool gate. `adjudicate`/`resolveAsk` are pre-bound to the task abort signal. */
1060
1092
  export interface ToolGateInput {
@@ -1104,7 +1136,7 @@ export interface ToolGateInput {
1104
1136
  /** The combined tool-policy check (abort-bound), or undefined when no policy is wired (→ allow). */
1105
1137
  adjudicate?: (req: ToolCallRequest) => Promise<PermissionResult>;
1106
1138
  /** Resolve an `ask` to allow/deny via `onAsk` (abort-bound). Required iff a decision can be `ask`.
1107
- * G1 three-value ([871]①): the result may carry `approverUnavailable` — the live approver affirmed no
1139
+ * G1 three-value: the result may carry `approverUnavailable` — the live approver affirmed no
1108
1140
  * operator is reachable for THIS ask; the gate then re-routes onto the durable park leg (below),
1109
1141
  * keeping the carried fail-closed deny when no park is armed. */
1110
1142
  resolveAsk: (decision: PermissionResult, req: ToolCallRequest) => Promise<ResolvedAsk>;
@@ -1163,7 +1195,11 @@ export interface ToolGateInput {
1163
1195
  probeReason?: string,
1164
1196
  /** backlog #239: the STRUCTURED cause (the surviving ask's `probeCause`) — same durable-route errand
1165
1197
  * as `probeReason`, already validated at the gate. */
1166
- probeCause?: import("./checkpoint-store.js").ProbeCause) => Promise<ToolGateResult["suspend"] | ParkAttemptFailed | undefined>;
1198
+ probeCause?: import("./checkpoint-store.js").ProbeCause,
1199
+ /** design/375 §5.2②: the surviving ask's engine-stamped `segmentCoverage` — threaded so the park
1200
+ * mint's offer factory reads the same coverage snapshot on the durable route as the synchronous
1201
+ * mints read off the decision (absent ⇒ all segments uncovered ⇒ over-offer, the safe way). */
1202
+ segmentCoverage?: readonly import("./permission-rule-model.js").SegmentCoverage[]) => Promise<ToolGateResult["suspend"] | ParkAttemptFailed | undefined>;
1167
1203
  /**
1168
1204
  * design/174 — route a policy `ask` on the reserved question tool to this run's CONTENT-ask channel
1169
1205
  * before it can become a park or a refusal. Called in the `ask` branch with the FINAL post-hook,
@@ -1268,7 +1304,7 @@ export interface ToolGateInput {
1268
1304
  */
1269
1305
  writeProtectionCheck?: (toolName: string, args: unknown) => import("./write-protect.js").WriteProtectedHit | null;
1270
1306
  /**
1271
- * design/143 批2 ([672]-A, CC 2.1.207 auto mode): when present, a surviving `ask` is routed to the
1307
+ * design/143 批2 (A, CC 2.1.207 auto mode): when present, a surviving `ask` is routed to the
1272
1308
  * small-model policy CLASSIFIER before any human/durable resolution:
1273
1309
  * - verdict `allow` → the ask resolves to allow (`decisionReason:"classifier"`) — no suspend, no onAsk;
1274
1310
  * - verdict `block` → deny (`decisionReason:"classifier"`, `source:"classifier"`; CC `automode-blocked`);
@@ -1337,22 +1373,26 @@ export interface ToolGateInput {
1337
1373
  * bullets above are what keep integrity/hook/mandated asks out of that set.
1338
1374
  */
1339
1375
  persistedRules?: {
1340
- /** The rule that admits this call, or `undefined`. Must not throw: a store that cannot be read
1341
- * answers "no rule" and discloses on its own channel (fail-closed = more asks).
1376
+ /** The rule COVERAGE that admits this call, or `undefined`. Must not throw: a store that cannot
1377
+ * be read answers "no rule" and discloses on its own channel (fail-closed = more asks).
1342
1378
  *
1343
- * TWO ACCEPTED SHAPES (design/252 G-2, additive a lane returning the bare string is unchanged
1344
- * and stays supported): the canonical rule TEXT, or a {@link PersistedRuleHit} carrying that same
1345
- * text plus the matched rule's add DOTS. The dots are the rule's durable identity, and the text
1346
- * is not one (it reaches a card sanitized and capped); a lane that can name them lets the
1347
- * shadowed-ask evidence say WHICH stored rule matched rather than merely what it looked like.
1348
- * Widening the RETURN is why this is additive for implementers: every existing lane satisfies
1349
- * the union unchanged, and the gate reads both through one normalizer. */
1379
+ * TWO ACCEPTED SHAPES (design/252 G-2 / design/375 BREAKING): the canonical rule TEXT (a
1380
+ * single-rule hit with no identity), or a {@link PersistedRuleHit} carrying the coverage SET —
1381
+ * each member's canonical text plus its add DOTS. A single rule admitting the whole command is a
1382
+ * one-element set; a compound admitted by the per-segment conjunction (design/375 §5.1) is the
1383
+ * set of the covering rules. The dots are a rule's durable identity, and the text is not one (it
1384
+ * reaches a card sanitized and capped); a lane that can name them lets the shadowed-ask evidence
1385
+ * say WHICH stored rules matched rather than merely what they looked like. The retired pre-375
1386
+ * single-rule object shape (`{ rule, dots? }`) is read as a clean negative by the normalizer —
1387
+ * a stale lane degrades toward asking, never toward an allow. */
1350
1388
  admits: (req: ToolCallRequest) => Promise<PersistedRuleAnswer>;
1351
- /** Observation sink for an ask a rule resolved — the allow-side disclosure. Never affects the outcome. */
1389
+ /** Observation sink for an ask a rule coverage resolved — the allow-side disclosure. `rules` is
1390
+ * the coverage set's canonical texts in reporting order (design/375: a conjunction names every
1391
+ * rule the decision stands on). Never affects the outcome. */
1352
1392
  onResolved?: (info: {
1353
1393
  toolName: string;
1354
1394
  toolCallId: string;
1355
- rule: string;
1395
+ rules: readonly string[];
1356
1396
  }) => void;
1357
1397
  };
1358
1398
  /**
@@ -1380,7 +1420,7 @@ export interface ToolGateInput {
1380
1420
  /** True iff the reserved question-tool NAME on this leg resolves to the ENGINE's own content-ask
1381
1421
  * tool. It is the exemption's real predicate: the name alone is not, because a caller may mount
1382
1422
  * its own tool under that name when the first-party one is not mounted, and such a tool has
1383
- * arbitrary side effects (codex review, confirmed MED). Absent ⇒ `false` ⇒ the call is governed
1423
+ * arbitrary side effects (confirmed MED). Absent ⇒ `false` ⇒ the call is governed
1384
1424
  * like any other, which is the fail-closed default. */
1385
1425
  contentAskToolMounted?: boolean;
1386
1426
  /** Disclosure sink for the unavailable arm (trace `permission.org_snapshot_unavailable`). Never
@@ -1398,7 +1438,7 @@ export interface ToolGateInput {
1398
1438
  * checkpoint store that explicitly declares `redecision.reopen`). Absent ⇒ the whole step does not
1399
1439
  * exist and the decision path is byte-identical to a build without it.
1400
1440
  *
1401
- * Semantics (clay's ruling): inside a declared sandbox, an engine-authored "confirm a potentially
1441
+ * Semantics (the ruling): inside a declared sandbox, an engine-authored "confirm a potentially
1402
1442
  * destructive local action" ask is answered by containment itself — auto-allow + durable
1403
1443
  * disclosure (`permission.sandbox_admitted`), never a headless deny that pollutes the model.
1404
1444
  * STRICT dominance governs: the leg admits only when EVERY surviving ask on the call is classified