@sema-agent/core 7.49.4 → 7.50.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 (200) hide show
  1. package/CHANGELOG.md +152 -0
  2. package/dist/agents/observer.js +3 -10
  3. package/dist/agents/peer-directory.d.ts +8 -3
  4. package/dist/agents/peer-directory.js +5 -3
  5. package/dist/agents/subagent-steps.d.ts +6 -14
  6. package/dist/agents/subagent-steps.js +3 -17
  7. package/dist/brain/stream-shared.d.ts +1 -1
  8. package/dist/core/allow-entry.d.ts +1 -1
  9. package/dist/core/allow-entry.js +1 -1
  10. package/dist/core/ask-origin.d.ts +15 -11
  11. package/dist/core/ask-origin.js +6 -14
  12. package/dist/core/auto-mode-prompt.js +6 -2
  13. package/dist/core/checkpoint-store.d.ts +6 -4
  14. package/dist/core/checkpoint-store.js +1 -1
  15. package/dist/core/context-edit.d.ts +2 -2
  16. package/dist/core/decision-receipt.d.ts +2 -2
  17. package/dist/core/decision-receipt.js +30 -11
  18. package/dist/core/delegation-frames.d.ts +66 -18
  19. package/dist/core/delegation-frames.js +22 -0
  20. package/dist/core/engine-notice.d.ts +7 -5
  21. package/dist/core/frame-settlement.d.ts +6 -1
  22. package/dist/core/gate-fold.js +19 -13
  23. package/dist/core/gate-lanes.js +12 -11
  24. package/dist/core/gate-outcome.d.ts +2 -2
  25. package/dist/core/governance-codes.js +2 -0
  26. package/dist/core/hooks.d.ts +28 -20
  27. package/dist/core/human-input-projection.js +2 -0
  28. package/dist/core/lsp-diagnostics.d.ts +3 -0
  29. package/dist/core/lsp-diagnostics.js +6 -0
  30. package/dist/core/lsp-session.d.ts +39 -17
  31. package/dist/core/lsp-session.js +118 -58
  32. package/dist/core/lsp.d.ts +83 -3
  33. package/dist/core/lsp.js +146 -16
  34. package/dist/core/mcp.js +2 -1
  35. package/dist/core/media-byte-cap.d.ts +14 -0
  36. package/dist/core/media-byte-cap.js +15 -3
  37. package/dist/core/memory-engine/consolidation-driver.d.ts +23 -1
  38. package/dist/core/memory-engine/consolidation-driver.js +54 -6
  39. package/dist/core/memory-engine/consolidation-write-gate.d.ts +46 -0
  40. package/dist/core/memory-engine/consolidation-write-gate.js +82 -0
  41. package/dist/core/memory-engine/consolidation.d.ts +17 -0
  42. package/dist/core/memory-engine/consolidation.js +1 -0
  43. package/dist/core/memory-engine/distiller.d.ts +8 -2
  44. package/dist/core/memory-engine/distiller.js +8 -6
  45. package/dist/core/memory-engine/engine.d.ts +37 -4
  46. package/dist/core/memory-engine/engine.js +127 -38
  47. package/dist/core/memory-engine/file-backend.d.ts +8 -3
  48. package/dist/core/memory-engine/file-backend.js +44 -16
  49. package/dist/core/memory-engine/index.d.ts +2 -2
  50. package/dist/core/memory-engine/index.js +1 -1
  51. package/dist/core/memory-engine/landing-admission.d.ts +65 -0
  52. package/dist/core/memory-engine/landing-admission.js +68 -0
  53. package/dist/core/memory-engine/types.d.ts +23 -0
  54. package/dist/core/mode-policy.d.ts +3 -2
  55. package/dist/core/mode-policy.js +2 -0
  56. package/dist/core/permission-rule-model.d.ts +19 -13
  57. package/dist/core/permission-rule-model.js +7 -4
  58. package/dist/core/permission-rule-provider.d.ts +11 -0
  59. package/dist/core/permission-rules.d.ts +1 -1
  60. package/dist/core/permission-rules.js +5 -2
  61. package/dist/core/persisted-rule-arms.d.ts +15 -7
  62. package/dist/core/persisted-rule-arms.js +13 -6
  63. package/dist/core/posix-mode-face.d.ts +10 -0
  64. package/dist/core/posix-mode-face.js +3 -0
  65. package/dist/core/reminder-mint.d.ts +5 -0
  66. package/dist/core/reminder-mint.js +1 -0
  67. package/dist/core/retired-keys.d.ts +8 -0
  68. package/dist/core/retired-keys.js +4 -0
  69. package/dist/core/rule-lane-reads.d.ts +4 -4
  70. package/dist/core/rule-lane-reads.js +10 -1
  71. package/dist/core/runner/construction-doors.d.ts +10 -4
  72. package/dist/core/runner/construction-doors.js +25 -2
  73. package/dist/core/runner/contracts.d.ts +20 -3
  74. package/dist/core/runner/env-capability-census.js +1 -1
  75. package/dist/core/runner/gate-exit.js +2 -1
  76. package/dist/core/runner/memory-consolidation-driver.d.ts +6 -4
  77. package/dist/core/runner/memory-consolidation-driver.js +5 -2
  78. package/dist/core/runner/memory-consolidation-write-judge.d.ts +17 -0
  79. package/dist/core/runner/memory-consolidation-write-judge.js +14 -0
  80. package/dist/core/runner/permission-rule-lanes.d.ts +16 -22
  81. package/dist/core/runner/permission-rule-lanes.js +13 -43
  82. package/dist/core/runner/person-path-rows.d.ts +244 -0
  83. package/dist/core/runner/person-path-rows.js +387 -0
  84. package/dist/core/runner/prepare-acquire-reconcile.js +8 -1
  85. package/dist/core/runner/prepare-artifact.d.ts +5 -3
  86. package/dist/core/runner/prepare-artifact.js +2 -8
  87. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -3
  88. package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
  89. package/dist/core/runner/prepare-context-lane.js +2 -2
  90. package/dist/core/runner/prepare-gate-stations.d.ts +3 -3
  91. package/dist/core/runner/prepare-gate-stations.js +1 -1
  92. package/dist/core/runner/prepare-hands-readface.d.ts +19 -10
  93. package/dist/core/runner/prepare-hands-readface.js +57 -43
  94. package/dist/core/runner/prepare-lsp.d.ts +15 -13
  95. package/dist/core/runner/prepare-lsp.js +11 -11
  96. package/dist/core/runner/prepare-policy-chain.d.ts +8 -4
  97. package/dist/core/runner/prepare-policy-chain.js +6 -7
  98. package/dist/core/runner/prepare-run-refs.js +1 -1
  99. package/dist/core/runner/prepare-task.js +24 -16
  100. package/dist/core/runner/prepare-turn-wiring.d.ts +13 -6
  101. package/dist/core/runner/prepare-turn-wiring.js +19 -8
  102. package/dist/core/runner/read-root-grant.d.ts +1 -25
  103. package/dist/core/runner/read-root-grant.js +1 -17
  104. package/dist/core/runner/retired-runner-deps.d.ts +2 -2
  105. package/dist/core/runner/run-brain-sinks.d.ts +1 -5
  106. package/dist/core/runner/run-brain-sinks.js +2 -4
  107. package/dist/core/runner/run-harness-handlers.js +5 -4
  108. package/dist/core/runner/run-identity-wiring.d.ts +4 -4
  109. package/dist/core/runner/run-identity-wiring.js +10 -1
  110. package/dist/core/runner/run-leg.d.ts +1 -1
  111. package/dist/core/runner/run-leg.js +22 -9
  112. package/dist/core/runner/run-settle-and-teardown.d.ts +0 -4
  113. package/dist/core/runner/run-settle-and-teardown.js +7 -4
  114. package/dist/core/runner/run-terminal-adoption.d.ts +1 -1
  115. package/dist/core/runner/run-terminal-adoption.js +1 -1
  116. package/dist/core/runner/run-turn-boundary.js +2 -2
  117. package/dist/core/runner/runtask.js +8 -8
  118. package/dist/core/runner/session-file-state-replay.d.ts +14 -4
  119. package/dist/core/runner/session-file-state-replay.js +8 -0
  120. package/dist/core/runner/stream-steer-verb.js +3 -0
  121. package/dist/core/runner/tool-end-body.d.ts +5 -4
  122. package/dist/core/runner/tool-end-body.js +4 -4
  123. package/dist/core/runner/tool-output-projection.d.ts +6 -4
  124. package/dist/core/runner/tool-output-projection.js +66 -47
  125. package/dist/core/runner-deps.d.ts +6 -3
  126. package/dist/core/shared-memory/types.d.ts +2 -2
  127. package/dist/core/shell-read-silence.d.ts +23 -0
  128. package/dist/core/shell-read-silence.js +18 -0
  129. package/dist/core/synthetic-read-verdict.d.ts +80 -21
  130. package/dist/core/synthetic-read-verdict.js +89 -18
  131. package/dist/core/task-event.d.ts +113 -25
  132. package/dist/core/task-spec.d.ts +44 -0
  133. package/dist/core/task-tool-shape.d.ts +1 -1
  134. package/dist/core/tool-catalog-entries.js +16 -2
  135. package/dist/core/tool-policy.d.ts +25 -15
  136. package/dist/core/tool-policy.js +9 -13
  137. package/dist/core/trace.d.ts +3 -2
  138. package/dist/core/types.d.ts +3 -3
  139. package/dist/core/types.js +1 -1
  140. package/dist/core/untrusted-text.d.ts +2 -2
  141. package/dist/core/user-attachment.d.ts +164 -0
  142. package/dist/core/user-attachment.js +437 -0
  143. package/dist/engine/compaction/compaction.js +10 -3
  144. package/dist/engine/compaction/utils.js +6 -0
  145. package/dist/engine/execution-env/node-execution-env.d.ts +19 -1
  146. package/dist/engine/execution-env/node-execution-env.js +127 -1
  147. package/dist/engine/harness/agent-harness.d.ts +12 -2
  148. package/dist/engine/harness/agent-harness.js +15 -3
  149. package/dist/engine/harness/types.d.ts +21 -0
  150. package/dist/engine/llm/content-block-render.d.ts +15 -0
  151. package/dist/engine/llm/content-block-render.js +10 -0
  152. package/dist/engine/llm/index.d.ts +1 -0
  153. package/dist/engine/llm/index.js +1 -0
  154. package/dist/engine/llm/types.d.ts +80 -4
  155. package/dist/engine/llm/types.js +43 -1
  156. package/dist/engine/session/import-validate.js +2 -0
  157. package/dist/index.d.ts +6 -4
  158. package/dist/index.js +2 -1
  159. package/dist/internal/harness-types.d.ts +1 -1
  160. package/dist/internal/llm.d.ts +2 -2
  161. package/dist/internal/llm.js +1 -1
  162. package/dist/orchestration/workflow.d.ts +4 -5
  163. package/dist/orchestration/workflow.js +2 -2
  164. package/dist/prompts/default.d.ts +1 -1
  165. package/dist/stores/file/permission-rule-store.d.ts +13 -1
  166. package/dist/stores/file/permission-rule-store.js +40 -21
  167. package/dist/tools/artifact/artifact-tool.js +1 -1
  168. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  169. package/dist/tools/fs/dir-entries.d.ts +4 -10
  170. package/dist/tools/fs/dir-entries.js +4 -11
  171. package/dist/tools/fs/file-read-check.js +3 -3
  172. package/dist/tools/fs/fs-pdf.js +2 -4
  173. package/dist/tools/fs/fs-read.d.ts +47 -4
  174. package/dist/tools/fs/fs-read.js +63 -19
  175. package/dist/tools/fs/fs-search-tools.d.ts +3 -3
  176. package/dist/tools/fs/fs-search-tools.js +7 -2
  177. package/dist/tools/fs/fs-write.d.ts +1 -1
  178. package/dist/tools/fs/fs-write.js +7 -6
  179. package/dist/tools/fs/index.d.ts +7 -1
  180. package/dist/tools/fs/index.js +56 -34
  181. package/dist/tools/fs/read-deny-home.d.ts +19 -1
  182. package/dist/tools/fs/read-deny-home.js +32 -22
  183. package/dist/tools/fs/read-deny.d.ts +14 -0
  184. package/dist/tools/fs/read-deny.js +8 -0
  185. package/dist/tools/fs/repo-map.d.ts +3 -2
  186. package/dist/tools/fs/repo-map.js +11 -3
  187. package/dist/tools/fs/safety.d.ts +41 -2
  188. package/dist/tools/fs/safety.js +12 -3
  189. package/dist/tools/fs/shell-read-check.d.ts +12 -3
  190. package/dist/tools/fs/shell-read-check.js +28 -15
  191. package/dist/tools/fs/shell-read-device.d.ts +1 -1
  192. package/dist/tools/fs/shell-read-judge.d.ts +9 -4
  193. package/dist/tools/fs/shell-read-judge.js +1 -1
  194. package/dist/tools/loop-tick.d.ts +2 -2
  195. package/package.json +3 -1
  196. package/test/export-surface.snapshot.json +39 -1
  197. package/wire-changes/core@7.49.5.json +104 -0
  198. package/wire-changes/core@7.50.0.json +1699 -0
  199. package/dist/core/runner/persisted-path-rows.d.ts +0 -88
  200. package/dist/core/runner/persisted-path-rows.js +0 -108
@@ -1,8 +1,9 @@
1
1
  import type { AgentTool } from "../../internal/harness-types.js";
2
2
  import type { ExecutionEnv } from "../../internal/harness-types.js";
3
3
  import { type RootsSeat } from "./safety.js";
4
- import type { ReadDenyMatcher } from "./read-deny.js";
4
+ import { type ReadDenyMatcher } from "./read-deny.js";
5
5
  import type { ContainmentFace } from "./containment-face.js";
6
+ import type { CwdRef } from "./fs-shared.js";
6
7
  /** Extract top-level symbol names (deduped, in first-seen order) from source text. A lightweight
7
8
  * comment/docstring state machine skips column-0 declaration-like lines that are really inside a
8
9
  * `/* … *​/` block comment or a Python `"""`/`'''` docstring — otherwise e.g. a module docstring
@@ -14,4 +15,4 @@ import type { ContainmentFace } from "./containment-face.js";
14
15
  * (src/core/auto-promote.ts) consumes it in ESCALATE-ONLY mode — a clean scan contributes nothing;
15
16
  * it can only ever raise an escalation, never clear one. */
16
17
  export declare function extractSymbols(text: string): string[];
17
- export declare function createRepoMapTool(env: ExecutionEnv, rootCanonical: string, additionalRoots?: RootsSeat, readDeny?: ReadDenyMatcher, readFace?: ContainmentFace): AgentTool;
18
+ export declare function createRepoMapTool(env: ExecutionEnv, rootCanonical: string, rootsSeat?: RootsSeat, denySeat?: ReadDenyMatcher, readFace?: ContainmentFace, cwdRef?: CwdRef, readAdmission?: (toolCallId: string | undefined, canonicalKey: string) => boolean): AgentTool;
@@ -2,7 +2,10 @@ import { Type } from "typebox";
2
2
  import { defineTool, errorResult } from "../../core/tools.js";
3
3
  import { resolveKey, violationText, violationDetails } from "./safety.js";
4
4
  import { buildIgnore, denyWithheldNote, walk, walkIsPartial } from "./search.js";
5
+ import { seatForCall } from "./read-deny.js";
5
6
  import { toolFace } from "../../core/tool-catalog-entries.js";
7
+ import { pathTargetBaseOf } from "../../core/effective-path-target.js";
8
+ import { pathTargetValue } from "../../core/tool-registry.js";
6
9
  const DEFAULT_MAX_CHARS = 16_000;
7
10
  const DEFAULT_MAX_FILES = 400;
8
11
  const FILE_SCAN_MAX_BYTES = 256 * 1024;
@@ -80,7 +83,8 @@ function rankEntries(a, b) {
80
83
  return b.symbols.length - a.symbols.length;
81
84
  return a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0;
82
85
  }
83
- export function createRepoMapTool(env, rootCanonical, additionalRoots, readDeny, readFace) {
86
+ export function createRepoMapTool(env, rootCanonical, rootsSeat, denySeat, readFace, cwdRef, readAdmission) {
87
+ const declaredTarget = toolFace("repo-map").pathTarget;
84
88
  return defineTool({
85
89
  name: "RepoMap",
86
90
  ...toolFace("repo-map"),
@@ -94,12 +98,16 @@ export function createRepoMapTool(env, rootCanonical, additionalRoots, readDeny,
94
98
  max_files: Type.Optional(Type.Number({ description: `Max files to scan (default ${DEFAULT_MAX_FILES}).` })),
95
99
  }),
96
100
  execute: async (args, ctx) => {
101
+ const readDeny = seatForCall(denySeat, ctx.toolCallId);
102
+ const additionalRoots = seatForCall(rootsSeat, ctx.toolCallId);
97
103
  const a = args;
98
104
  const signal = ctx.signal;
99
105
  const rootPrefix = rootCanonical.replace(/[\\/]+$/, "") + (rootCanonical.includes("\\") ? "\\" : "/");
100
106
  let start = rootCanonical;
101
- if (a.path !== undefined) {
102
- const r = await resolveKey(env, rootCanonical, a.path, signal, rootCanonical, additionalRoots, undefined, readDeny, readFace);
107
+ const scopeSpelling = declaredTarget === undefined ? undefined : pathTargetValue(a, declaredTarget);
108
+ if (scopeSpelling !== undefined) {
109
+ const baseCwd = pathTargetBaseOf(declaredTarget, { root: rootCanonical, cwd: cwdRef?.current });
110
+ const r = await resolveKey(env, rootCanonical, scopeSpelling, signal, baseCwd, additionalRoots, readAdmission && ((key) => readAdmission(ctx.toolCallId, key)), readDeny, readFace);
103
111
  if (!r.ok)
104
112
  return errorResult(violationText("RepoMap", r.violation), violationDetails(r.violation));
105
113
  start = r.key;
@@ -1,3 +1,4 @@
1
+ import { type DenyFace } from "./read-deny.js";
1
2
  import { type HomeViewSource } from "./read-deny-home.js";
2
3
  import type { AssertAllKeysHandled } from "../../core/ask-origin.js";
3
4
  import type { ExecutionEnv } from "../../internal/harness-types.js";
@@ -520,12 +521,36 @@ export declare function violationDetails(v: FsViolation): {
520
521
  code: "path_not_in_root";
521
522
  target: string;
522
523
  roots: readonly string[];
523
- } | {
524
+ } | ReadPathDeniedCard | undefined;
525
+ /** The read face's refusal card: which target, which deny pattern. */
526
+ export type ReadPathDeniedCard = {
524
527
  type: "read_path_denied";
525
528
  code: "read_path_denied";
526
529
  target: string;
527
530
  pattern: string;
528
- } | undefined;
531
+ };
532
+ /**
533
+ * The ONE mint of the `read_path_denied` card. `type` is the CC_DETAIL_TYPES discriminator, so the refusal's
534
+ * coordinates reach `tool_end.structured`, not just prose; `code` carries the same value for in-process readers.
535
+ * Every site that refuses a read on a deny row — the tools' own resolution, the shell station, the gate's rule lanes —
536
+ * mints it here.
537
+ */
538
+ export declare function readPathDeniedCard(target: string, pattern: string): ReadPathDeniedCard;
539
+ /**
540
+ * Where one deny row refused a call: the row's text, the view of the target it met, and the face the call is on.
541
+ * Minted once, by the judge that found the row; every exit of the gate reads it and judges nothing again.
542
+ */
543
+ export interface PathDenialEvidence {
544
+ readonly rule: string;
545
+ readonly view: string;
546
+ readonly face: DenyFace;
547
+ }
548
+ /**
549
+ * The card a gate-side path refusal carries: the read face's own ({@link readPathDeniedCard}); the write face has none
550
+ * (as in the tools' own resolution, where a write refusal's `write_path_denied` code carries no card). The card's
551
+ * presence follows the FACE, never the station that refused.
552
+ */
553
+ export declare function pathDenialCardOf(evidence: PathDenialEvidence | undefined): ReadPathDeniedCard | undefined;
529
554
  /**
530
555
  * Does `p` sit inside ANY of the canonical containment roots? Exposed for the Bash
531
556
  * tool's post-`cd` disclosure note (fs-bash.ts): the note reuses the SAME segment-aware `within`
@@ -534,6 +559,20 @@ export declare function violationDetails(v: FsViolation): {
534
559
  * design; fs-bash canonical-confirms before claiming "outside").
535
560
  */
536
561
  export declare function withinAnyRoot(rootsCanonical: readonly string[], p: string): boolean;
562
+ /**
563
+ * THE store-isolation rule, one judgment for every root admission point (the Artifact mount over the prepare-time
564
+ * roots, an in-flight read-root grant over the granted root, a person's read directory where a run's read roots are
565
+ * read): a root that CONTAINS the local artifact store, lies INSIDE it, or IS it hands the file tools the store's ledger
566
+ * and stored files. Returns the first such root, or undefined.
567
+ *
568
+ * `storePhysical` is the store's physical path on THIS process's filesystem (`physicalPathOfExisting`, resolved
569
+ * once per run by the Artifact phase); a root is the execution env's canonical key. The judgment touches no
570
+ * filesystem — the grant runs after the approver's wait under the call's cut, and a synchronous lookup on a stalled
571
+ * store mount would block the event loop past that cut. The two are compared as identities only when both spell the
572
+ * same family (`within` reads both under the root's family); a root of the other family names a filesystem the store
573
+ * cannot be on, and no claim is made against it.
574
+ */
575
+ export declare function rootAdmittingArtifactStore(storePhysical: string, rootsCanonical: readonly string[]): string | undefined;
537
576
  /**
538
577
  * The escape-hatch tail for the `path_not_in_root` refusal: like its three sibling hints below, it
539
578
  * names a sanctioned next step, so the model does not oscillate between "the boundary is hard" and
@@ -659,16 +659,25 @@ export function violationText(toolName, v) {
659
659
  return `Error (${toolName}): ${v.message}`;
660
660
  }
661
661
  export function violationDetails(v) {
662
- if (v.code === "read_path_denied" && v.target !== undefined && v.pattern !== undefined) {
663
- return { type: "read_path_denied", code: "read_path_denied", target: v.target, pattern: v.pattern };
664
- }
662
+ if (v.code === "read_path_denied" && v.target !== undefined && v.pattern !== undefined)
663
+ return readPathDeniedCard(v.target, v.pattern);
665
664
  return v.code === "path_not_in_root" && v.target !== undefined
666
665
  ? { type: "path_not_in_root", code: "path_not_in_root", target: v.target, roots: v.roots ?? [] }
667
666
  : undefined;
668
667
  }
668
+ export function readPathDeniedCard(target, pattern) {
669
+ return { type: "read_path_denied", code: "read_path_denied", target, pattern };
670
+ }
671
+ export function pathDenialCardOf(evidence) {
672
+ return evidence?.face === "read" ? readPathDeniedCard(evidence.view, evidence.rule) : undefined;
673
+ }
669
674
  export function withinAnyRoot(rootsCanonical, p) {
670
675
  return rootsCanonical.some((r) => within(r, p));
671
676
  }
677
+ export function rootAdmittingArtifactStore(storePhysical, rootsCanonical) {
678
+ const storeFamily = pathFamilyOf({ root: storePhysical });
679
+ return rootsCanonical.find((root) => pathFamilyOf({ root }) === storeFamily && (withinAnyRoot([root], storePhysical) || withinAnyRoot([storePhysical], root)));
680
+ }
672
681
  export const PATH_NOT_IN_ROOT_ESCAPE_HINT = "(This boundary applies to the structured file tools. If you genuinely need content outside the allowed root(s), ask for the directory to be added to the deployment's additionalDirectories — or additionalReadDirectories for read-only access; a deployment that wants reads or writes open everywhere can declare readFace / writeFace: \"open\" instead of listing directories.)";
673
682
  export function requireRead(state, key) {
674
683
  const entry = state.get(key);
@@ -44,6 +44,14 @@ export type ShellReadRefusalDetails = NonNullable<ReturnType<typeof violationDet
44
44
  export interface ShellReadVerdict {
45
45
  readonly disposition: ShellReadDisposition;
46
46
  readonly finding: ShellReadFinding;
47
+ /** The environment did not answer the judgment — a resolver, a listing or an identity lookup gave no answer, a bound was
48
+ * reached, the judge itself did not answer: present on the `unanswered` finding the fold or the fallback gives. The gate
49
+ * classes the question as shell text the engine cannot read. */
50
+ readonly environmentSilent?: true;
51
+ /** Rows the station's boundary stands on could not be read (`ShellReadBoundary.unreadPartitions`, or a boundary the seat
52
+ * could not hand over): present on ANY verdict judged beside them, whatever its finding. The gate classes the question as
53
+ * a rule that could not be read. */
54
+ readonly rowsUnread?: true;
47
55
  /** `write` ⇔ the finding is about where the command WRITES — its witness is a write target (a redirection's, or a word
48
56
  * the program's row writes), judged against the write roots. Absent ⇒ a read's finding (or `vouch`). */
49
57
  readonly face?: "write";
@@ -146,9 +154,10 @@ export interface ShellReadStationOptions {
146
154
  readonly tools: ReadonlySet<string>;
147
155
  /** The trust-policy seat a tool is judged on. */
148
156
  readonly seatOf: (toolName: string) => ShellReadStationSeat;
149
- /** The boundary for a call, read per call (the tracked working directory moves). `undefined` ⇒ no
150
- * boundary declared, nothing to be outside of — the station vouches. */
151
- readonly boundaryOf: (toolName: string, cwd: string | undefined) => ShellReadBoundary | undefined;
157
+ /** The boundary for a call, read per call (the tracked working directory moves; the call's own tables, by its id —
158
+ * `undefined` where no call is judged). `undefined` ⇒ no boundary declared, nothing to be outside of — the station
159
+ * vouches. */
160
+ readonly boundaryOf: (toolName: string, cwd: string | undefined, toolCallId: string | undefined) => ShellReadBoundary | undefined;
152
161
  /** The listed read verbs (decides whether a segment is read by verb slots or word by word). */
153
162
  readonly readers?: ReadonlySet<string>;
154
163
  /** `true` ⇔ every root `boundaryOf` returns is already a canonical identity (the Runner's): the station never
@@ -286,15 +286,17 @@ function verdictOf(tool, seat, fold, judged, boundary) {
286
286
  const paths = outsidePathsOf(judged);
287
287
  const unestablished = fold.unestablished === true ? { unestablished: true } : {};
288
288
  const writes = fold.witness?.read.candidate.face === "write" ? { face: "write" } : {};
289
+ const by = fold.finding === "unanswered" ? { environmentSilent: true } : {};
289
290
  if (disposition === "refuse") {
290
291
  const r = refusalOf(tool, fold, boundary, paths);
291
- return { disposition, finding: fold.finding, ...writes, sentence: r.sentence, ...(r.details !== undefined ? { details: r.details } : {}) };
292
+ return { disposition, finding: fold.finding, ...by, ...writes, sentence: r.sentence, ...(r.details !== undefined ? { details: r.details } : {}) };
292
293
  }
293
294
  const grant = fold.finding === "outside_roots" ? readRootGrantCandidateOf(judged, boundary) : undefined;
294
295
  const containment = fold.finding === "outside_roots" || fold.finding === "unestablishable" || fold.finding === "unanswered";
295
296
  return {
296
297
  disposition,
297
298
  finding: fold.finding,
299
+ ...by,
298
300
  ...writes,
299
301
  ...unestablished,
300
302
  sentence: findingAccount(fold, boundary),
@@ -404,6 +406,16 @@ export function createShellReadStation(opts) {
404
406
  admissions.set(toolCallId, a);
405
407
  };
406
408
  const memberOf = (call) => readStationMemberOf(call, opts.tools)?.name;
409
+ const unansweredOver = (toolName, seat, cause, boundary, silence) => {
410
+ if (boundary === undefined || (boundary !== "unread" && !(anyFaceGuards(boundary) || boundary.writeTargetJudge !== undefined)))
411
+ return { disposition: "vouch", finding: "none" };
412
+ const disposition = decideShellRead("unanswered", seat);
413
+ const account = `${cause}, so where this command reads could not be established ${NOT_AUTO_ALLOWED}`;
414
+ const details = unestablishedDetails();
415
+ if (disposition === "refuse")
416
+ return { disposition, finding: "unanswered", ...silence, sentence: `Error (${toolName}): ${account}. ${BASH_READONLY_CONFINEMENT_NOTE}`, details };
417
+ return { disposition, finding: "unanswered", ...silence, sentence: account, details };
418
+ };
407
419
  const check = {
408
420
  judge(call, args, cwd, signal, callOpts) {
409
421
  const member = memberOf(call);
@@ -412,7 +424,7 @@ export function createShellReadStation(opts) {
412
424
  const command = shellCommandOf(args);
413
425
  if (command === undefined)
414
426
  return null;
415
- const boundary = opts.boundaryOf(member, cwd);
427
+ const boundary = opts.boundaryOf(member, cwd, callOpts.toolCallId);
416
428
  if (boundary === undefined)
417
429
  return null;
418
430
  const seat = callOpts.seat ?? opts.seatOf(member);
@@ -420,22 +432,23 @@ export function createShellReadStation(opts) {
420
432
  const run = await runShellReadStation(call.toolName, command, boundary, seat, readers, establisherFor(boundary.roots), opts.env, signal);
421
433
  if (run.verdict.disposition !== "refuse" && callOpts.toolCallId !== undefined)
422
434
  remember(callOpts.toolCallId, { toolName: member, boundary: run.boundary, established: run.established, command });
423
- return run.verdict;
435
+ if (boundary.unreadPartitions !== true)
436
+ return run.verdict;
437
+ return run.verdict.disposition === "vouch" ? unansweredOver(call.toolName, seat, "the rules this check stands on could not all be read", boundary, { rowsUnread: true }) : { ...run.verdict, rowsUnread: true };
424
438
  })();
425
439
  },
426
440
  unanswered(call, cause) {
427
- const toolName = call.toolName;
428
- const member = memberOf(call) ?? toolName;
429
- const seat = opts.seatOf(member);
430
- const boundary = opts.boundaryOf(member, undefined);
431
- if (boundary === undefined || !(anyFaceGuards(boundary) || boundary.writeTargetJudge !== undefined))
432
- return { disposition: "vouch", finding: "none" };
433
- const disposition = decideShellRead("unanswered", seat);
434
- const account = `${cause}, so where this command reads could not be established ${NOT_AUTO_ALLOWED}`;
435
- const details = unestablishedDetails();
436
- if (disposition === "refuse")
437
- return { disposition, finding: "unanswered", sentence: `Error (${toolName}): ${account}. ${BASH_READONLY_CONFINEMENT_NOTE}`, details };
438
- return { disposition, finding: "unanswered", sentence: account, details };
441
+ const member = memberOf(call) ?? call.toolName;
442
+ const boundary = (() => {
443
+ try {
444
+ return opts.boundaryOf(member, undefined, undefined);
445
+ }
446
+ catch {
447
+ return "unread";
448
+ }
449
+ })();
450
+ const rowsUnread = boundary === "unread" || boundary?.unreadPartitions === true ? { rowsUnread: true } : {};
451
+ return unansweredOver(call.toolName, opts.seatOf(member), cause, boundary, { environmentSilent: true, ...rowsUnread });
439
452
  },
440
453
  };
441
454
  const admit = async (toolName, toolCallId, command, signal) => {
@@ -5,7 +5,7 @@
5
5
  * operand, the content a program writes through an operand, a `git diff` operand) and the shape tier's two readings of "does
6
6
  * this redirection write" (the read-only reader, the classify faces' data-free redirections).
7
7
  *
8
- * The table is the reference implementation's own device predicate (CC 2.1.296 `wwe`, cli296.js @18511591): the null
8
+ * The table is the reference implementation's own device predicate (CC 2.1.296 `wwe` (cli296.js:249645) @18511591): the null
9
9
  * device, the three standard streams, the terminal, any `/dev/fd/<digits>`, and `/proc/self/fd/{0,1,2}`. A word is such a
10
10
  * spelling AS WRITTEN (quotes removed, nothing folded: `/dev/./null` is a path, not the null device).
11
11
  *
@@ -74,7 +74,7 @@ export declare function dispositionOfCell(cell: ShellReadCell, narrowedReadFace:
74
74
  * ask is MANDATED and no automatic lane answers; on the OPEN face (where the station asks only because a deny list has
75
75
  * rows), and for a written target alone (a narrowed WRITE face fences what is written; it is no request to be asked about
76
76
  * every word the floor cannot place), it is the ORDINARY ask — the reference implementation's plain permission ask (CC
77
- * 2.1.296 `sR`, cli296.js @13116941, reason `other`), which a whole-tool allow (`$pn` @18717070), bypass (`$pn` @18716980)
77
+ * 2.1.296 `sR` (cli296.js:242691) @13116941, reason `other`), which a whole-tool allow (`N9` (cli296.js:249675) @18717070), bypass (`$pn` (cli296.js:249675) @18716980)
78
78
  * and the auto-mode classifier release and a prefix allow does not.
79
79
  * · `declined` — the one deliberate fail-open of this table: the scan could not read the program bash
80
80
  * will run, or the operands arrive on a stream. On the full shell it is an ORDINARY ask — an answerer
@@ -159,6 +159,10 @@ export interface ShellReadCellContext {
159
159
  */
160
160
  export interface ShellReadBoundary extends BashReadonlyRootBoundary {
161
161
  readonly alsoInside?: (canonicalTarget: string) => Promise<boolean>;
162
+ /** A partition of the rules the deny seats are compiled from could not be read: a guard of unknown reach. The station
163
+ * guards ({@link stationGuards}) and vouches for nothing against this boundary — what it would vouch for is answered as
164
+ * a judgment it could not make. */
165
+ readonly unreadPartitions?: true;
162
166
  /** The deny table's WRITE face (`compileWriteDeny`, read-deny.ts): judges a command's write targets (candidates marked
163
167
  * `face: "write"`) and returns the matched row's rule, or null. PRESENT-IFF there is something to judge. */
164
168
  readonly writeDenyMatch?: (resolvedPath: string) => string | null;
@@ -303,12 +307,13 @@ export interface JudgedPlan {
303
307
  }
304
308
  /**
305
309
  * Does the station GUARD anything for this boundary — a closed face (roots: containment is what it guards; an absent
306
- * face reads as roots, as {@link containmentOf} does), or a deny table with rows (`denyMatch` is present exactly then)?
310
+ * face reads as roots, as {@link containmentOf} does), or a deny table with rows (`denyMatch` is present exactly then),
311
+ * or rows it could not read (`unreadPartitions`: a guard of unknown reach)?
307
312
  * Where it guards nothing (an open face, no deny row), a read it could not establish has nothing to be confirmed
308
313
  * against: no finding. The deny judgment itself is untouched (with no row there is nothing to hit). The READ face's
309
314
  * question only: a write target folds by {@link writeFaceGuards}.
310
315
  */
311
- export declare function stationGuards(boundary: Pick<ShellReadBoundary, "face" | "denyMatch">): boolean;
316
+ export declare function stationGuards(boundary: Pick<ShellReadBoundary, "face" | "denyMatch" | "unreadPartitions">): boolean;
312
317
  /**
313
318
  * Does the station guard anything on the WRITE face — the same shape for the write seats: the write face in force runs
314
319
  * the roots-containment step ({@link skipsRootsContainment}, the structured write tools' reading; absent ⇒ roots), or
@@ -319,7 +324,7 @@ export declare function writeFaceGuards(boundary: Pick<ShellReadBoundary, "write
319
324
  /** Does the station guard anything on EITHER face? What a finding about the text's own structure folds by — a text the
320
325
  * lexer could not read, a program it cannot name, program text it does not read, a working directory it lost, a text the
321
326
  * shell re-enters — since what such a text reads AND what it writes are both unknown. */
322
- export declare function anyFaceGuards(boundary: Pick<ShellReadBoundary, "face" | "denyMatch" | "writeFace" | "writeDenyMatch">): boolean;
327
+ export declare function anyFaceGuards(boundary: Pick<ShellReadBoundary, "face" | "denyMatch" | "unreadPartitions" | "writeFace" | "writeDenyMatch">): boolean;
323
328
  /** The command-level fold and the finding that produced it. `witness` is absent for `none`; for `declined`
324
329
  * the segment that declined stands in for a candidate. */
325
330
  export interface ShellReadFold {
@@ -104,7 +104,7 @@ function judgeWrite(read, boundary) {
104
104
  return { read, kind: containment === "outside" && !skipsRootsContainment(boundary.writeFace) ? "outside_roots" : "none", containment };
105
105
  }
106
106
  export function stationGuards(boundary) {
107
- return boundary.face !== "open" || boundary.denyMatch !== undefined;
107
+ return boundary.face !== "open" || boundary.denyMatch !== undefined || boundary.unreadPartitions === true;
108
108
  }
109
109
  export function writeFaceGuards(boundary) {
110
110
  return !skipsRootsContainment(boundary.writeFace) || boundary.writeDenyMatch !== undefined;
@@ -19,9 +19,9 @@ export interface AutonomousLoopPromptOptions {
19
19
  */
20
20
  pushNotification?: boolean;
21
21
  }
22
- /** CC `FFi` (:205310) — first-tick preamble, DEFAULT variant (steward framing). Verbatim. */
22
+ /** CC 2.1.209 `FFi` (:205310) — first-tick preamble, DEFAULT variant (steward framing). Verbatim through 2.1.259; the reference dropped this preamble from 2.1.278 on. */
23
23
  export declare const AUTONOMOUS_LOOP_PREAMBLE = "# Autonomous loop check\n\nYou're being invoked on a timer while the user is away or occupied. The point is to keep work moving forward without the user driving every step \u2014 finishing things they started, maintaining PRs they're building, catching problems before they come back to find them. You're a steward, not an initiator. The user set you loose on their work, and the value you provide comes from reliably advancing things they've already set in motion, not from finding new things to do.\n\nThe key tension to navigate: the user trusts you enough to run autonomously, but that trust is easily lost. Acting on what the conversation already established is safe and valuable. Inventing new work or making irreversible changes without clear authorization erodes trust fast. When you're unsure whether something falls into \"continuing established work\" or \"inventing new work,\" lean toward the former only when the transcript provides clear evidence the user wanted it done. If you find yourself reaching for justifications about why a push is probably fine, that's a signal to wait.\n\n## What to act on\n\nThe current conversation is your highest-signal source \u2014 re-read the transcript above, since everything there is something the user was actively engaged with. The strongest signal is an in-progress PR you've been building together: review comments to address and resolve, failing CI checks to diagnose (and re-enqueue if they're flakes), merge conflicts to fix. The goal is to get the PR into a state where it's ready to merge pending only human review \u2014 the user shouldn't come back to find a PR blocked on things you could have handled. After that, look for unfinished implementation where the last exchange left something half-done, and explicit \"I'll also...\" or \"next I'll...\" commitments the conversation made and didn't honor. Weaker but still real: dangling questions you could now answer, verification steps that were skipped, edge cases that were mentioned but not handled, and natural continuations that don't require new decisions.\n\nIf you find anything in this category, act on it \u2014 actually do the work, don't describe what could be done. Run the tests, don't say \"you could run the tests.\" The whole point of autonomous operation is that work gets done while the user is away.\n\nWhen the conversation transcript has nothing left, the current branch's pull/merge request on the user's SCM is the next-best place to look. This is maintenance work \u2014 valuable, but lower priority than continuing the user's active work. Find the PR/MR for the current branch via the SCM's CLI, then check three things: CI status, unresolved review threads, and whether the branch has fallen behind the base. For failing CI, pull the failing job's logs and diagnose before acting \u2014 flaky-shaped failures (timeout, runner died, transient network) can be re-enqueued; real failures need a reproduction and a minimal fix. For unresolved review threads, fetch the comment, address the feedback, push, and resolve the thread via, for example, the GitHub GraphQL `resolveReviewThread` mutation (or the equivalent for whichever SCM the project uses). Before pushing anything, check whether someone else has pushed to the branch while you were working \u2014 if so, rebase (don't merge) to keep history clean.\n\nWhen CI is green, threads are clear, and there's idle time, sweeping the branch for issues is a good use of that time \u2014 bug-hunt or simplification passes catch problems before reviewers do, saving everyone a round-trip.\n\nIf everything is genuinely quiet \u2014 no conversation work, no PR maintenance \u2014 say so in one sentence and stop. No summary of what you checked, no list of what you might do later. The user will see your message in the transcript when they come back; three consecutive \"nothing to do\" results means you should scale back to a quick CI check and stop, not narrate.\n\n## Repeated invocations\n\nIf you see earlier autonomous checks in this conversation, adjust your scope accordingly. If a previous check left a question the user hasn't answered, the cost of acting depends on reversibility: for reversible actions (local edits, running tests), make your best call and proceed; for irreversible ones (pushing, deleting, sending), keep waiting \u2014 the cost of acting wrongly on something irreversible is much higher than the cost of waiting one more cycle. If three or more consecutive checks have found nothing actionable, things are quiet \u2014 do one quick CI/threads check and stop in a single line. Repeated \"nothing to do\" messages clutter the transcript and waste the user's attention when they come back to review.\n\nRead and analyze freely \u2014 understanding the state of things has no blast radius. Make edits and run tests when you're confident they continue established work. Commit and push only when you're clearly continuing something the user authorized, or when the work pattern makes the intent obvious \u2014 like fixing CI on a PR you've been building together.\n";
24
- /** CC `w6c` (:205335) — first-tick preamble, PERSISTENT variant. Verbatim. */
24
+ /** CC 2.1.209 `w6c` (:205335) — first-tick preamble, PERSISTENT variant. Verbatim through 2.1.259; dropped from 2.1.278 on. */
25
25
  export declare const AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT = "# Autonomous loop check\n\nYou're being invoked on a timer while the user is away or occupied. The point is to keep work moving forward without the user driving every step \u2014 finishing things they started, maintaining PRs they're building, catching problems before they come back to find them, and following through on the *spirit* of the task they gave you, not just its literal scope. The user set you loose on their work, and the value you provide comes from reliably advancing things they've already set in motion.\n\nThe key tension to navigate: the user trusts you enough to run autonomously, but that trust is easily lost. Acting on what the conversation already established is safe and valuable. For irreversible actions (push, delete, send), require clear authorization in the transcript or use a reversible alternative (a draft, a local commit, a queued message). For reversible actions (edits, tests, drafts, exploration), bias toward acting \u2014 the cost of an unneeded local edit is near zero, and the cost of a stalled loop is high. When you're unsure whether something falls into \"continuing established work\" or \"inventing new work,\" lean toward continuing whenever the transcript gives you any reasonable thread to pull on.\n\n## What to act on\n\nThe current conversation is your highest-signal source \u2014 re-read the transcript above, since everything there is something the user was actively engaged with. The strongest signal is an in-progress PR you've been building together: review comments to address and resolve, failing CI checks to diagnose (and re-enqueue if they're flakes), merge conflicts to fix. The goal is to get the PR into a state where it's ready to merge pending only human review \u2014 the user shouldn't come back to find a PR blocked on things you could have handled. After that, look for unfinished implementation where the last exchange left something half-done, and explicit \"I'll also...\" or \"next I'll...\" commitments the conversation made and didn't honor. Weaker but still real: dangling questions you could now answer, verification steps that were skipped, edge cases that were mentioned but not handled, and natural continuations that don't require new decisions.\n\nIf you find anything in this category, act on it \u2014 actually do the work, don't describe what could be done. Run the tests, don't say \"you could run the tests.\" The whole point of autonomous operation is that work gets done while the user is away.\n\nWhen the conversation transcript has nothing left, the current branch's pull/merge request on the user's SCM is the next-best place to look. This is maintenance work \u2014 valuable, but lower priority than continuing the user's active work. Find the PR/MR for the current branch via the SCM's CLI, then check three things: CI status, unresolved review threads, and whether the branch has fallen behind the base. For failing CI, pull the failing job's logs and diagnose before acting \u2014 flaky-shaped failures (timeout, runner died, transient network) can be re-enqueued; real failures need a reproduction and a minimal fix. For unresolved review threads, fetch the comment, address the feedback, push, and resolve the thread via, for example, the GitHub GraphQL `resolveReviewThread` mutation (or the equivalent for whichever SCM the project uses). Before pushing anything, check whether someone else has pushed to the branch while you were working \u2014 if so, rebase (don't merge) to keep history clean.\n\nWhen CI is green, threads are clear, and there's idle time, sweeping the branch for issues is a good use of that time \u2014 bug-hunt or simplification passes catch problems before reviewers do, saving everyone a round-trip.\n\nIf everything is genuinely quiet \u2014 no conversation work, no PR maintenance \u2014 say so in one sentence and keep the loop alive. Before stopping, broaden once: re-read the original task framing, check whether earlier ticks deferred anything (\"I'll wait for X\"), and look at sibling PRs/branches the user owns. Persistence is the point of autonomous mode. Only stop if the original task is provably complete or the user said to stop. (Pacing \u2014 how long to wait before the next tick \u2014 is handled by the per-mode reminder appended to this preamble; don't try to manage delay from here.)\n\n## Repeated invocations\n\nIf you see earlier autonomous checks in this conversation, adjust your scope accordingly. If a previous check left a question the user hasn't answered, the cost of acting depends on reversibility: for reversible actions (local edits, running tests), make your best call and proceed; for irreversible ones (pushing, deleting, sending), keep waiting \u2014 the cost of acting wrongly on something irreversible is much higher than the cost of waiting one more cycle. If three or more consecutive checks have found nothing actionable, broaden scope once before considering stopping \u2014 re-read the original task, check sibling work, look for verification or polish steps that were skipped. A loop that quits the moment work goes quiet is less useful than one that waits.\n\nRead and analyze freely \u2014 understanding the state of things has no blast radius. Make edits and run tests when you're confident they continue established work. Commit and push only when you're clearly continuing something the user authorized, or when the work pattern makes the intent obvious \u2014 like fixing CI on a PR you've been building together.\n";
26
26
  /**
27
27
  * Resolve a fire-time prompt: if it is one of the two autonomous-loop sentinels, return the tick
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.49.4",
3
+ "version": "7.50.0",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -72,6 +72,8 @@
72
72
  "handoff:diff": "node scripts/dist-handoff-diff.mjs",
73
73
  "post-ship": "node scripts/post-ship.mjs",
74
74
  "gate:debts:rc": "node scripts/verify-debts.mjs --rc-gate",
75
+ "gate:anchor-claims": "node scripts/verify-anchor-claims.mjs",
76
+ "gate:anchor-claims:rc": "node scripts/verify-anchor-claims.mjs --require-corpus",
75
77
  "gate:rulings": "node scripts/rulings-gate.mjs --require-comms",
76
78
  "gate:error-surface": "node scripts/verify-error-surface.mjs",
77
79
  "gate:criteria": "node scripts/criteria-lint.mjs",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_comment": "design/87 L3 — frozen public export surface of src/index.ts (name -> kind). DO NOT edit by hand to silence a red test. A removed/changed entry = a BREAKING change: name every removed entry in the CHANGELOG's BREAKING lines (what was removed / who is hurt / what to read instead) and update this fixture in the SAME commit. Regenerate via REGEN in test/export-surface.test.ts.",
3
3
  "_tierComment": "#435 v1 — machine-readable layering of the public surface: stable = demonstrated by README.md / src/examples; internal = an `Internal`-marked name or a runner/engine deep-subtree declaration (the model seam src/engine/llm is excluded — it is the BYOM contract, not an engine internal); advanced = a supported export the front door does not walk you through. THIS IS AN INITIAL HEURISTIC, derived mechanically and expected to be refined ticket by ticket: no human reviewed these 1700+ entries one by one, and nothing here claims otherwise. Known bias: a short or English-word export name (ok, err, Result, Usage) can match ordinary prose in README.md and land `stable` on a coincidence. Every export MUST carry a tier — a new export with no row fails the gate in export-surface.test.ts.",
4
- "count": 2609,
4
+ "count": 2628,
5
5
  "exports": {
6
6
  "A2ATaskState": "type",
7
7
  "A2ATaskStateReversal": "type",
@@ -216,6 +216,7 @@
216
216
  "BeforeWriteHook": "type",
217
217
  "BeforeWriteRequest": "interface",
218
218
  "BeforeWriteResult": "type",
219
+ "BoundFileObject": "interface",
219
220
  "BoundPathRule": "interface",
220
221
  "BoundSkillGrants": "interface",
221
222
  "Brain": "interface",
@@ -252,6 +253,7 @@
252
253
  "CONSOLIDATION_DRIVER_RUNS_FILE": "variable",
253
254
  "CONSOLIDATION_RUN_STOP_REASONS": "variable",
254
255
  "CONSOLIDATION_SYSTEM_PROMPT": "variable",
256
+ "CONSOLIDATION_WRITE_REFUSED_CODE": "variable",
255
257
  "CONTRACT_KIT_ENGINE_VERSION": "variable",
256
258
  "COORDINATOR_ROLE_PROMPT": "variable",
257
259
  "CORRUPT_BODY_FORMS": "variable",
@@ -358,6 +360,9 @@
358
360
  "ConsolidationRunReceipt": "interface",
359
361
  "ConsolidationRunStopReason": "type",
360
362
  "ConsolidationStats": "interface",
363
+ "ConsolidationWriteGate": "type",
364
+ "ConsolidationWriteJudge": "type",
365
+ "ConsolidationWriteTarget": "interface",
361
366
  "ConstraintChainEntry": "type",
362
367
  "ContainmentFace": "type",
363
368
  "ContainmentFaceInputs": "interface",
@@ -591,6 +596,7 @@
591
596
  "Hooks": "interface",
592
597
  "HostDecider": "type",
593
598
  "HostDecisionFacts": "interface",
599
+ "HumanInputAttachment": "interface",
594
600
  "HumanInputDelivery": "type",
595
601
  "HumanInputEvent": "type",
596
602
  "HumanInputFrame": "interface",
@@ -1660,6 +1666,12 @@
1660
1666
  "UNCOVERED_SEGMENT_REASON_BASELINE": "variable",
1661
1667
  "URL_SAFETY": "variable",
1662
1668
  "USAGE_WINDOW_REAP_MARGIN_MS": "variable",
1669
+ "USER_ATTACHMENTS_MAX": "variable",
1670
+ "USER_ATTACHMENT_KINDS": "variable",
1671
+ "USER_ATTACHMENT_LABEL_MAX": "variable",
1672
+ "USER_ATTACHMENT_OUTCOMES": "variable",
1673
+ "USER_ATTACHMENT_SEAT": "variable",
1674
+ "USER_ATTACHMENT_SUPPLIES": "variable",
1663
1675
  "USER_INPUT_UNDRAINED_CAUSES": "variable",
1664
1676
  "USER_INPUT_UNDRAINED_FAMILIES": "variable",
1665
1677
  "UnarmedDenialLimitFallback": "interface",
@@ -1674,9 +1686,16 @@
1674
1686
  "UsageWindowReading": "interface",
1675
1687
  "UsageWindowRecord": "interface",
1676
1688
  "UsageWindowStore": "interface",
1689
+ "UserAttachment": "type",
1690
+ "UserAttachmentDeclaration": "interface",
1691
+ "UserAttachmentKind": "type",
1692
+ "UserAttachmentObservation": "interface",
1693
+ "UserAttachmentOutcome": "type",
1694
+ "UserAttachmentSupply": "type",
1677
1695
  "UserInputLane": "type",
1678
1696
  "UserInputUndrainedCause": "type",
1679
1697
  "UserMessage": "interface",
1698
+ "UserMessageAttachment": "interface",
1680
1699
  "UserPromptSubmitContext": "interface",
1681
1700
  "UserPromptSubmitResult": "interface",
1682
1701
  "UtilityGate": "type",
@@ -2827,6 +2846,7 @@
2827
2846
  "BeforeWriteHook": "stable",
2828
2847
  "BeforeWriteRequest": "advanced",
2829
2848
  "BeforeWriteResult": "advanced",
2849
+ "BoundFileObject": "internal",
2830
2850
  "BoundPathRule": "advanced",
2831
2851
  "BoundSkillGrants": "advanced",
2832
2852
  "Brain": "stable",
@@ -2863,6 +2883,7 @@
2863
2883
  "CONSOLIDATION_DRIVER_RUNS_FILE": "advanced",
2864
2884
  "CONSOLIDATION_RUN_STOP_REASONS": "advanced",
2865
2885
  "CONSOLIDATION_SYSTEM_PROMPT": "internal",
2886
+ "CONSOLIDATION_WRITE_REFUSED_CODE": "advanced",
2866
2887
  "CONTRACT_KIT_ENGINE_VERSION": "advanced",
2867
2888
  "COORDINATOR_ROLE_PROMPT": "advanced",
2868
2889
  "CORRUPT_BODY_FORMS": "advanced",
@@ -2969,6 +2990,9 @@
2969
2990
  "ConsolidationRunReceipt": "advanced",
2970
2991
  "ConsolidationRunStopReason": "advanced",
2971
2992
  "ConsolidationStats": "internal",
2993
+ "ConsolidationWriteGate": "advanced",
2994
+ "ConsolidationWriteJudge": "advanced",
2995
+ "ConsolidationWriteTarget": "advanced",
2972
2996
  "ConstraintChainEntry": "advanced",
2973
2997
  "ContainmentFace": "stable",
2974
2998
  "ContainmentFaceInputs": "advanced",
@@ -3202,6 +3226,7 @@
3202
3226
  "Hooks": "advanced",
3203
3227
  "HostDecider": "advanced",
3204
3228
  "HostDecisionFacts": "advanced",
3229
+ "HumanInputAttachment": "advanced",
3205
3230
  "HumanInputDelivery": "advanced",
3206
3231
  "HumanInputEvent": "advanced",
3207
3232
  "HumanInputFrame": "advanced",
@@ -4271,6 +4296,12 @@
4271
4296
  "UNCOVERED_SEGMENT_REASON_BASELINE": "advanced",
4272
4297
  "URL_SAFETY": "advanced",
4273
4298
  "USAGE_WINDOW_REAP_MARGIN_MS": "internal",
4299
+ "USER_ATTACHMENTS_MAX": "advanced",
4300
+ "USER_ATTACHMENT_KINDS": "advanced",
4301
+ "USER_ATTACHMENT_LABEL_MAX": "advanced",
4302
+ "USER_ATTACHMENT_OUTCOMES": "advanced",
4303
+ "USER_ATTACHMENT_SEAT": "advanced",
4304
+ "USER_ATTACHMENT_SUPPLIES": "advanced",
4274
4305
  "USER_INPUT_UNDRAINED_CAUSES": "advanced",
4275
4306
  "USER_INPUT_UNDRAINED_FAMILIES": "advanced",
4276
4307
  "UnarmedDenialLimitFallback": "advanced",
@@ -4285,9 +4316,16 @@
4285
4316
  "UsageWindowReading": "advanced",
4286
4317
  "UsageWindowRecord": "advanced",
4287
4318
  "UsageWindowStore": "advanced",
4319
+ "UserAttachment": "advanced",
4320
+ "UserAttachmentDeclaration": "advanced",
4321
+ "UserAttachmentKind": "advanced",
4322
+ "UserAttachmentObservation": "advanced",
4323
+ "UserAttachmentOutcome": "advanced",
4324
+ "UserAttachmentSupply": "advanced",
4288
4325
  "UserInputLane": "advanced",
4289
4326
  "UserInputUndrainedCause": "advanced",
4290
4327
  "UserMessage": "advanced",
4328
+ "UserMessageAttachment": "advanced",
4291
4329
  "UserPromptSubmitContext": "advanced",
4292
4330
  "UserPromptSubmitResult": "advanced",
4293
4331
  "UtilityGate": "advanced",
@@ -0,0 +1,104 @@
1
+ {
2
+ "repo": "core",
3
+ "version": "7.49.5",
4
+ "from": "40a79ac3341fc6750aae1664c64840a44abaa205",
5
+ "to": "9ba02c33f3eea253894b0132dca7ed98c390fb08",
6
+ "added": [],
7
+ "removed": [],
8
+ "changed": [],
9
+ "narrowed": [],
10
+ "closedSetMembers": [],
11
+ "closedSetsUnreadable": [],
12
+ "typeKeys": [],
13
+ "typeKeysUnreadableArms": [],
14
+ "typeKeysFlattenedCount": 223,
15
+ "signatures": [
16
+ {
17
+ "name": "FileDurableRulePartitionProvider.constructor",
18
+ "at": [
19
+ "src/stores/file/permission-rule-store.ts:671"
20
+ ],
21
+ "from": [
22
+ "(dir: string, onError?: (message: string) => void, opts?: { dataRoot?: string; })"
23
+ ],
24
+ "to": [
25
+ "(dir: string, onError?: (message: string) => void, opts?: { dataRoot?: string; platform?: NodeJS.Platform; })"
26
+ ],
27
+ "changes": [
28
+ {
29
+ "aspect": "param",
30
+ "detail": "param 3 `opts` type widened: { dataRoot?: string; [ -> platform?: NodeJS.Platform; ]}",
31
+ "breaking": false
32
+ }
33
+ ],
34
+ "breaking": false,
35
+ "criteriaCovered": false
36
+ },
37
+ {
38
+ "name": "judgePeerRecordFile",
39
+ "at": [
40
+ "src/agents/peer-directory.ts:484"
41
+ ],
42
+ "from": [
43
+ "(stat: { uid?: number; mode: number; isFile: boolean; size: number; }, selfUid: number | undefined): { ok: false; code: \"not_regular\" | \"foreign_owner\" | \"group_or_world_writable\" | \"too_large\"; } | { ok: true; }"
44
+ ],
45
+ "to": [
46
+ "(stat: { uid?: number; mode: number; isFile: boolean; size: number; }, selfUid: number | undefined, platform?: NodeJS.Platform): { ok: false; code: \"not_regular\" | \"foreign_owner\" | \"group_or_world_writable\" | \"too_large\"; } | { ok: true; }"
47
+ ],
48
+ "changes": [
49
+ {
50
+ "aspect": "param",
51
+ "detail": "+optional param `platform?: NodeJS.Platform`",
52
+ "breaking": false
53
+ }
54
+ ],
55
+ "breaking": false,
56
+ "criteriaCovered": false
57
+ },
58
+ {
59
+ "name": "vetPeerRegistryDirectory",
60
+ "at": [
61
+ "src/agents/peer-directory.ts:452"
62
+ ],
63
+ "from": [
64
+ "(dir: string, opts?: { uid?: number; stopAt?: string; }): Promise<PeerRegistryDirectoryVerdict>"
65
+ ],
66
+ "to": [
67
+ "(dir: string, opts?: { uid?: number; stopAt?: string; platform?: NodeJS.Platform; }): Promise<PeerRegistryDirectoryVerdict>"
68
+ ],
69
+ "changes": [
70
+ {
71
+ "aspect": "param",
72
+ "detail": "param 2 `opts` type widened: …umber; stopAt?: string; [ -> platform?: NodeJS.Platform; ]}",
73
+ "breaking": false
74
+ }
75
+ ],
76
+ "breaking": false,
77
+ "criteriaCovered": false
78
+ }
79
+ ],
80
+ "declarationMoves": [],
81
+ "mintMoves": [],
82
+ "criteriaObserves": [
83
+ {
84
+ "kind": "typeMember",
85
+ "name": "AskRequest.classes",
86
+ "assertions": [
87
+ "G1.a",
88
+ "G2.a"
89
+ ]
90
+ }
91
+ ],
92
+ "consumersHint": {
93
+ "cli": [
94
+ "FileDurableRulePartitionProvider"
95
+ ],
96
+ "server": [
97
+ "FileDurableRulePartitionProvider"
98
+ ],
99
+ "sdk": [],
100
+ "note": "scanned cli@7006be65 server@72f3abe9 sdk@f1b30d4 — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it. Ledger files (**/docs/core-consumption/**, **/docs/wire-consumption/**, **/*LEDGER*.json) are not evidence of use — server: 2 name(s) matched ONLY in bookkeeping files and were set aside (judgePeerRecordFile, vetPeerRegistryDirectory)"
101
+ },
102
+ "breakingCount": 0,
103
+ "breakingItems": []
104
+ }