@sema-agent/core 7.15.0 → 7.17.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 (287) hide show
  1. package/CHANGELOG.md +202 -0
  2. package/dist/agents/builtin-agents.d.ts +3 -3
  3. package/dist/agents/cross-session-envelope.d.ts +0 -1
  4. package/dist/agents/cross-session-envelope.js +0 -1
  5. package/dist/agents/peer-notices.d.ts +0 -9
  6. package/dist/agents/peer-notices.js +0 -63
  7. package/dist/agents/subagent.js +7 -15
  8. package/dist/brain/request-params.d.ts +2 -2
  9. package/dist/config/defaults.d.ts +0 -7
  10. package/dist/config/defaults.js +0 -2
  11. package/dist/core/artifact-host.d.ts +218 -0
  12. package/dist/core/artifact-host.js +92 -0
  13. package/dist/core/ask-origin.d.ts +29 -3
  14. package/dist/core/ask-origin.js +17 -9
  15. package/dist/core/ask-question.d.ts +25 -0
  16. package/dist/core/ask-question.js +4 -0
  17. package/dist/core/ask-unresolvable-notice.d.ts +30 -21
  18. package/dist/core/ask-unresolvable-notice.js +16 -8
  19. package/dist/core/auto-compaction.d.ts +10 -10
  20. package/dist/core/auto-mode-arming.d.ts +2 -2
  21. package/dist/core/background-agent-store.d.ts +5 -5
  22. package/dist/core/background-shell.d.ts +1 -1
  23. package/dist/core/checkpoint-execution-record.d.ts +0 -3
  24. package/dist/core/checkpoint-execution-record.js +0 -4
  25. package/dist/core/checkpoint-store.d.ts +71 -99
  26. package/dist/core/checkpoint-store.js +9 -16
  27. package/dist/core/context-edit.d.ts +36 -104
  28. package/dist/core/context-edit.js +37 -60
  29. package/dist/core/effective-path-target.d.ts +68 -8
  30. package/dist/core/effective-path-target.js +42 -30
  31. package/dist/core/engine-notice.d.ts +46 -32
  32. package/dist/core/env-budget.d.ts +31 -0
  33. package/dist/core/env-budget.js +39 -0
  34. package/dist/core/exec-output-tail.d.ts +5 -5
  35. package/dist/core/file-history-store.js +3 -6
  36. package/dist/core/fs-write-gate-policy.d.ts +1 -1
  37. package/dist/core/fs-write-gate-policy.js +3 -3
  38. package/dist/core/gate-lanes.js +9 -15
  39. package/dist/core/governance-codes.d.ts +1 -1
  40. package/dist/core/governance-codes.js +4 -0
  41. package/dist/core/hands-band.d.ts +1 -1
  42. package/dist/core/hooks.d.ts +18 -17
  43. package/dist/core/lsp-session.d.ts +1 -1
  44. package/dist/core/lsp.d.ts +1 -1
  45. package/dist/core/lsp.js +5 -4
  46. package/dist/core/mcp.d.ts +5 -5
  47. package/dist/core/mcp.js +4 -48
  48. package/dist/core/memory-engine/delegation-settlement.d.ts +37 -12
  49. package/dist/core/memory-engine/delegation-settlement.js +128 -39
  50. package/dist/core/memory-engine/engine.d.ts +9 -8
  51. package/dist/core/memory-engine/engine.js +115 -120
  52. package/dist/core/memory-engine/file-backend.d.ts +17 -5
  53. package/dist/core/memory-engine/file-backend.js +78 -34
  54. package/dist/core/memory-engine/index.d.ts +2 -2
  55. package/dist/core/memory-engine/index.js +2 -2
  56. package/dist/core/memory-engine/layout.d.ts +152 -54
  57. package/dist/core/memory-engine/layout.js +441 -104
  58. package/dist/core/memory-engine/types.d.ts +8 -3
  59. package/dist/core/memory-engine/types.js +5 -0
  60. package/dist/core/memory-recall.d.ts +0 -8
  61. package/dist/core/memory.d.ts +1 -1
  62. package/dist/core/oracle-isolation.js +2 -2
  63. package/dist/core/parent-spec-seat.d.ts +66 -0
  64. package/dist/core/parent-spec-seat.js +47 -0
  65. package/dist/core/permission-rule-model.d.ts +11 -6
  66. package/dist/core/permission-rule-model.js +53 -37
  67. package/dist/core/permission-rules.js +8 -3
  68. package/dist/core/protocol-naming.d.ts +2 -2
  69. package/dist/core/remote-env.d.ts +1 -1
  70. package/dist/core/retired-keys.d.ts +19 -0
  71. package/dist/core/retired-keys.js +15 -0
  72. package/dist/core/runner/abort-race.d.ts +3 -3
  73. package/dist/core/runner/active-skill-scope.d.ts +2 -2
  74. package/dist/core/runner/active-skill-scope.js +3 -3
  75. package/dist/core/runner/assemble-result.d.ts +42 -40
  76. package/dist/core/runner/assemble-result.js +5 -4
  77. package/dist/core/runner/checkpoint-scope.d.ts +4 -4
  78. package/dist/core/runner/clock-and-limits.d.ts +3 -3
  79. package/dist/core/runner/compaction-call-options.d.ts +35 -99
  80. package/dist/core/runner/compaction-knobs.d.ts +4 -4
  81. package/dist/core/runner/compaction-seams.d.ts +5 -5
  82. package/dist/core/runner/contracts.d.ts +232 -233
  83. package/dist/core/runner/decide-continuation.d.ts +6 -6
  84. package/dist/core/runner/denial-limit-arms.d.ts +8 -8
  85. package/dist/core/runner/derived-route-fallback.d.ts +2 -2
  86. package/dist/core/runner/gate-exit.d.ts +6 -6
  87. package/dist/core/runner/gate-exit.js +15 -1
  88. package/dist/core/runner/git-status-frame.d.ts +7 -7
  89. package/dist/core/runner/halt-attribution.d.ts +35 -0
  90. package/dist/core/runner/halt-attribution.js +16 -0
  91. package/dist/core/runner/inherited-ask-grants.d.ts +6 -6
  92. package/dist/core/runner/memory-capture-optout.d.ts +1 -1
  93. package/dist/core/runner/memory-consolidation-driver.d.ts +4 -4
  94. package/dist/core/runner/memory-consolidation.d.ts +6 -8
  95. package/dist/core/runner/memory-consolidation.js +0 -1
  96. package/dist/core/runner/park-commit.d.ts +6 -6
  97. package/dist/core/runner/permission-rule-lanes.d.ts +19 -19
  98. package/dist/core/runner/prepare-acquire-reconcile.d.ts +4 -4
  99. package/dist/core/runner/prepare-artifact.d.ts +53 -0
  100. package/dist/core/runner/prepare-artifact.js +77 -0
  101. package/dist/core/runner/prepare-ask-lane.d.ts +3 -3
  102. package/dist/core/runner/prepare-boundary-parks.d.ts +3 -3
  103. package/dist/core/runner/prepare-caps-and-workflow.d.ts +9 -7
  104. package/dist/core/runner/prepare-caps-and-workflow.js +2 -3
  105. package/dist/core/runner/prepare-config-doors.d.ts +24 -24
  106. package/dist/core/runner/prepare-config-doors.js +5 -2
  107. package/dist/core/runner/prepare-context-lane.d.ts +8 -8
  108. package/dist/core/runner/prepare-context-lane.js +2 -13
  109. package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
  110. package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
  111. package/dist/core/runner/prepare-file-history.d.ts +3 -3
  112. package/dist/core/runner/prepare-file-history.js +3 -52
  113. package/dist/core/runner/prepare-gate-stations.d.ts +5 -5
  114. package/dist/core/runner/prepare-hands-readface.d.ts +35 -38
  115. package/dist/core/runner/prepare-hands-readface.js +3 -2
  116. package/dist/core/runner/prepare-inherited-gate.d.ts +9 -6
  117. package/dist/core/runner/prepare-inherited-gate.js +7 -8
  118. package/dist/core/runner/prepare-listings.d.ts +3 -3
  119. package/dist/core/runner/prepare-lsp.d.ts +3 -3
  120. package/dist/core/runner/prepare-memory-engine-session.d.ts +5 -5
  121. package/dist/core/runner/prepare-memory.d.ts +4 -6
  122. package/dist/core/runner/prepare-memory.js +10 -9
  123. package/dist/core/runner/prepare-offload-wrappers.d.ts +2 -2
  124. package/dist/core/runner/prepare-park-ask.d.ts +6 -6
  125. package/dist/core/runner/prepare-policy-chain.d.ts +7 -7
  126. package/dist/core/runner/prepare-policy-chain.js +15 -30
  127. package/dist/core/runner/prepare-prompt-assembly.js +1 -1
  128. package/dist/core/runner/prepare-prompt-inputs.d.ts +5 -5
  129. package/dist/core/runner/prepare-protocol-tools.d.ts +1 -1
  130. package/dist/core/runner/prepare-question-face.d.ts +4 -4
  131. package/dist/core/runner/prepare-run-refs.d.ts +11 -11
  132. package/dist/core/runner/prepare-safety-scan.d.ts +2 -2
  133. package/dist/core/runner/prepare-suspend-saga.d.ts +4 -4
  134. package/dist/core/runner/prepare-suspend-saga.js +0 -2
  135. package/dist/core/runner/prepare-task.d.ts +12 -12
  136. package/dist/core/runner/prepare-task.js +10 -9
  137. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +2 -3
  138. package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -4
  139. package/dist/core/runner/prepare-wiring-manifest.js +9 -7
  140. package/dist/core/runner/prepare-workspace-restore.d.ts +1 -1
  141. package/dist/core/runner/remote-env-retry.d.ts +3 -3
  142. package/dist/core/runner/resume-admission.d.ts +1 -1
  143. package/dist/core/runner/resume-admission.js +2 -1
  144. package/dist/core/runner/resume-claim.d.ts +1 -1
  145. package/dist/core/runner/resume-internals-and-config.d.ts +1 -1
  146. package/dist/core/runner/resume-internals-and-config.js +4 -0
  147. package/dist/core/runner/resume-policy-outcome.d.ts +1 -1
  148. package/dist/core/runner/resume-preflight.d.ts +1 -1
  149. package/dist/core/runner/resume-review-outcome.d.ts +1 -1
  150. package/dist/core/runner/retired-runner-deps.d.ts +3 -0
  151. package/dist/core/runner/retired-runner-deps.js +7 -0
  152. package/dist/core/runner/run-brain-sinks.d.ts +1 -1
  153. package/dist/core/runner/run-clock-and-content.d.ts +4 -4
  154. package/dist/core/runner/run-compaction-machinery.d.ts +3 -3
  155. package/dist/core/runner/run-git-lane.d.ts +1 -1
  156. package/dist/core/runner/run-harness-handlers.d.ts +2 -2
  157. package/dist/core/runner/run-harness-handlers.js +2 -3
  158. package/dist/core/runner/run-identity-wiring.d.ts +4 -4
  159. package/dist/core/runner/run-leg.d.ts +3 -3
  160. package/dist/core/runner/run-notification-lane.d.ts +2 -2
  161. package/dist/core/runner/run-reasoning-seat.d.ts +2 -2
  162. package/dist/core/runner/run-settle-and-teardown.d.ts +5 -5
  163. package/dist/core/runner/run-settle-and-teardown.js +3 -1
  164. package/dist/core/runner/run-telemetry-and-budget-seats.d.ts +2 -2
  165. package/dist/core/runner/run-terminal-adoption.d.ts +5 -5
  166. package/dist/core/runner/runtask.d.ts +14 -14
  167. package/dist/core/runner/session-file-state-replay.d.ts +3 -3
  168. package/dist/core/runner/session-file-state-replay.js +3 -3
  169. package/dist/core/runner/session-rule-policy.d.ts +2 -2
  170. package/dist/core/runner/session-rule-policy.js +3 -4
  171. package/dist/core/runner/steer-admission.d.ts +2 -2
  172. package/dist/core/runner/stream-halt-verbs.d.ts +1 -1
  173. package/dist/core/runner/stream-halt-verbs.js +1 -1
  174. package/dist/core/runner/stream-reap.d.ts +1 -1
  175. package/dist/core/runner/stream-steer-verb.js +1 -4
  176. package/dist/core/runner/synthetic-tools.d.ts +8 -8
  177. package/dist/core/runner/teardown-bounded.d.ts +2 -2
  178. package/dist/core/runner/tool-defer-gate.d.ts +1 -1
  179. package/dist/core/runner/tool-disclosure.d.ts +33 -33
  180. package/dist/core/runner/tool-end-body.d.ts +3 -3
  181. package/dist/core/runner/tool-face-overlay.d.ts +2 -2
  182. package/dist/core/runner/tool-output-projection.d.ts +2 -2
  183. package/dist/core/runner/turn-attachments.d.ts +53 -53
  184. package/dist/core/runner/usage-accounting.d.ts +4 -4
  185. package/dist/core/runner/workspace-path.d.ts +1 -1
  186. package/dist/core/runner/workspace-path.js +3 -0
  187. package/dist/core/runner-deps.d.ts +30 -49
  188. package/dist/core/safe-notify.d.ts +1 -1
  189. package/dist/core/sensitive-path-policy.d.ts +1 -1
  190. package/dist/core/sensitive-path-policy.js +4 -4
  191. package/dist/core/session.d.ts +2 -2
  192. package/dist/core/skill-tool-specifier.d.ts +1 -1
  193. package/dist/core/skills-directory.d.ts +1 -1
  194. package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
  195. package/dist/core/strategy-store.d.ts +8 -11
  196. package/dist/core/task-event.d.ts +20 -17
  197. package/dist/core/task-limits.d.ts +1 -1
  198. package/dist/core/task-notification.d.ts +5 -5
  199. package/dist/core/task-registry-agent.d.ts +5 -5
  200. package/dist/core/task-registry-monitor.d.ts +2 -2
  201. package/dist/core/task-registry-shared.d.ts +27 -27
  202. package/dist/core/task-registry-shared.js +3 -13
  203. package/dist/core/task-registry.d.ts +8 -8
  204. package/dist/core/task-result.d.ts +37 -37
  205. package/dist/core/task-spec.d.ts +5 -5
  206. package/dist/core/task-stream.d.ts +16 -11
  207. package/dist/core/tool-catalog-entries.d.ts +1 -0
  208. package/dist/core/tool-catalog-entries.js +5 -0
  209. package/dist/core/tool-conformance.d.ts +0 -2
  210. package/dist/core/tool-conformance.js +1 -3
  211. package/dist/core/tool-errors.d.ts +5 -0
  212. package/dist/core/tool-errors.js +1 -0
  213. package/dist/core/tool-policy.d.ts +51 -22
  214. package/dist/core/tool-policy.js +28 -5
  215. package/dist/core/tool-result-budget.d.ts +1 -1
  216. package/dist/core/tool-result-store.d.ts +11 -11
  217. package/dist/core/tool-spec.d.ts +34 -38
  218. package/dist/core/tools.d.ts +2 -2
  219. package/dist/core/trace.d.ts +12 -15
  220. package/dist/core/untrusted-text.d.ts +1 -1
  221. package/dist/core/wiring-manifest.d.ts +4 -3
  222. package/dist/core/workflow-journal-store.d.ts +11 -11
  223. package/dist/engine/execution-env/node-execution-env.d.ts +3 -2
  224. package/dist/engine/execution-env/node-execution-env.js +4 -2
  225. package/dist/engine/harness/agent-harness.d.ts +47 -4
  226. package/dist/engine/harness/agent-harness.js +52 -9
  227. package/dist/engine/llm/types.d.ts +1 -1
  228. package/dist/engine/loop/agent-loop.js +15 -8
  229. package/dist/engine/loop/types.d.ts +5 -0
  230. package/dist/index.d.ts +21 -16
  231. package/dist/index.js +17 -12
  232. package/dist/internal/harness.d.ts +1 -0
  233. package/dist/orchestration/run-spec.d.ts +3 -0
  234. package/dist/orchestration/run-spec.js +3 -3
  235. package/dist/orchestration/run-workflow-tool.d.ts +12 -6
  236. package/dist/orchestration/run-workflow-tool.js +23 -5
  237. package/dist/orchestration/workflow-primitives.d.ts +4 -2
  238. package/dist/orchestration/workflow-primitives.js +1 -4
  239. package/dist/orchestration/workflow-types.d.ts +34 -4
  240. package/dist/orchestration/workflow-types.js +2 -0
  241. package/dist/orchestration/workflow.d.ts +39 -7
  242. package/dist/orchestration/workflow.js +234 -113
  243. package/dist/prompt-assembly/assemble.d.ts +2 -2
  244. package/dist/prompt-assembly/assemble.js +9 -9
  245. package/dist/prompt-assembly/composer.d.ts +6 -7
  246. package/dist/prompt-assembly/composer.js +10 -10
  247. package/dist/prompt-assembly/epoch.js +1 -1
  248. package/dist/prompt-assembly/event-registry.d.ts +0 -21
  249. package/dist/prompt-assembly/packs/sema-default.js +30 -30
  250. package/dist/prompt-assembly/types.d.ts +14 -14
  251. package/dist/prompts/coordinator.d.ts +0 -13
  252. package/dist/prompts/coordinator.js +0 -3
  253. package/dist/stores/file/checkpoint-store.js +1 -5
  254. package/dist/stores/file/file-history-store.js +2 -2
  255. package/dist/stores/file/permission-rule-store.d.ts +4 -35
  256. package/dist/stores/file/permission-rule-store.js +4 -148
  257. package/dist/tools/artifact/artifact-text.d.ts +62 -0
  258. package/dist/tools/artifact/artifact-text.js +68 -0
  259. package/dist/tools/artifact/artifact-tool.d.ts +52 -0
  260. package/dist/tools/artifact/artifact-tool.js +351 -0
  261. package/dist/tools/artifact/local-stub.d.ts +26 -0
  262. package/dist/tools/artifact/local-stub.js +296 -0
  263. package/dist/tools/fs/bash-readonly-classifier.d.ts +114 -48
  264. package/dist/tools/fs/bash-readonly-classifier.js +171 -60
  265. package/dist/tools/fs/encoding.d.ts +31 -40
  266. package/dist/tools/fs/fs-bash.d.ts +49 -45
  267. package/dist/tools/fs/fs-bash.js +19 -27
  268. package/dist/tools/fs/fs-pdf.d.ts +8 -8
  269. package/dist/tools/fs/fs-search-tools.d.ts +4 -4
  270. package/dist/tools/fs/fs-search-tools.js +5 -2
  271. package/dist/tools/fs/fs-shared.d.ts +146 -158
  272. package/dist/tools/fs/fs-shared.js +3 -11
  273. package/dist/tools/fs/fs-write.d.ts +8 -8
  274. package/dist/tools/fs/gh-rate-limit.d.ts +13 -14
  275. package/dist/tools/fs/index.d.ts +78 -78
  276. package/dist/tools/fs/index.js +4 -1
  277. package/dist/tools/fs/notebook.d.ts +24 -25
  278. package/dist/tools/fs/pdf.d.ts +3 -3
  279. package/dist/tools/fs/read-deny.d.ts +22 -22
  280. package/dist/tools/fs/read-face.d.ts +21 -24
  281. package/dist/tools/fs/repo-map.d.ts +8 -8
  282. package/dist/tools/fs/safety.d.ts +233 -130
  283. package/dist/tools/fs/safety.js +131 -31
  284. package/dist/tools/fs/search.d.ts +63 -71
  285. package/dist/tools/fs/search.js +8 -6
  286. package/package.json +6 -2
  287. package/test/export-surface.snapshot.json +119 -39
@@ -2,14 +2,14 @@ import { createHash } from "node:crypto";
2
2
  import { homedir } from "node:os";
3
3
  import { brandPolicyAskClass } from "./ask-class.js";
4
4
  import { sanitizeAutoModeArmingRecipe } from "./auto-mode-arming.js";
5
- import { join, normalize as normalizePath, posix as posixPath, sep, win32 as winPath } from "node:path";
5
+ import { join, normalize as normalizePath, sep } from "node:path";
6
6
  import { BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName } from "../tools/fs/index.js";
7
7
  import { protectivePathTargetOf } from "./tool-registry.js";
8
8
  import { boundInputHashOf } from "./canonical-json.js";
9
9
  import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY } from "./untrusted-text.js";
10
10
  import { isNamespacedCoveringRuleName, namespacedRuleNameCovers, parsePermissionRule } from "./permission-rules.js";
11
11
  import { protocolOf } from "./protocol-table.js";
12
- import { isAbsolutePathForm, isWinFormPath, writeTargetPath } from "../tools/fs/safety.js";
12
+ import { isAbsoluteForFamily, isAbsolutePathForm, joinForFamily, normalizeAbsPathLexically, pathFamilyOf, writeTargetPath } from "../tools/fs/safety.js";
13
13
  const DECISION_REASONS = ["rule", "mode", "hook", "safety", "classifier", "persisted_rule", "sandbox", "org_rule", "org_unavailable", "read_only"];
14
14
  const DECISION_REASON_SET = new Set(DECISION_REASONS);
15
15
  function settledByNobody(kind) {
@@ -32,6 +32,9 @@ function transferEngineSettlement(from, to) {
32
32
  const c = CLASSIFIER_DENY_CAUSES_SEAT.get(from);
33
33
  if (c !== undefined)
34
34
  CLASSIFIER_DENY_CAUSES_SEAT.set(to, c);
35
+ const u = ASK_UNRESOLVABLE_CAUSES_SEAT.get(from);
36
+ if (u !== undefined)
37
+ ASK_UNRESOLVABLE_CAUSES_SEAT.set(to, u);
35
38
  }
36
39
  export function carryEngineAttestations(from, to) {
37
40
  transferEngineSettlement(from, to);
@@ -56,6 +59,19 @@ export function classifierDenyCauseOf(d, call) {
56
59
  return undefined;
57
60
  return v.cause;
58
61
  }
62
+ const ASK_UNRESOLVABLE_CAUSES_SEAT = new WeakMap();
63
+ export function attestAskUnresolvableCause(d, cause, call) {
64
+ ASK_UNRESOLVABLE_CAUSES_SEAT.set(d, { cause, toolCallId: call.toolCallId, toolName: call.toolName });
65
+ return d;
66
+ }
67
+ export function askUnresolvableCauseOf(d, call) {
68
+ if (typeof d !== "object" || d === null)
69
+ return undefined;
70
+ const v = ASK_UNRESOLVABLE_CAUSES_SEAT.get(d);
71
+ if (v === undefined || v.toolCallId !== call.toolCallId || v.toolName !== call.toolName)
72
+ return undefined;
73
+ return v.cause;
74
+ }
59
75
  export function engineSettlementOf(d, call) {
60
76
  if (typeof d !== "object" || d === null)
61
77
  return undefined;
@@ -807,9 +823,8 @@ export function createTranscriptIntegrityPolicy(opts) {
807
823
  const shellTools = canonicalToolNameSet(opts?.tools);
808
824
  const dirSegs = dirs.map((d) => pathSegments(d).map(foldPathCase));
809
825
  const inProtectedDir = (p, liveCwd) => {
810
- const rawRelative = !isAbsolutePathForm(p);
811
- const joinInFamily = (base, rel) => isWinFormPath(base) ? winPath.join(base, rel) : posixPath.join(base, rel);
812
- const abs = liveCwd !== undefined && rawRelative ? lexicalPath(joinInFamily(liveCwd, p), home) : lexicalPath(p, home);
826
+ const rawRelative = liveCwd === undefined ? !isAbsolutePathForm(p) : !isAbsoluteForFamily(pathFamilyOf({ root: liveCwd }), p);
827
+ const abs = liveCwd !== undefined && rawRelative ? lexicalPath(normalizeAbsPathLexically(joinForFamily(pathFamilyOf({ root: liveCwd }), liveCwd, p)), home) : lexicalPath(p, home);
813
828
  const segs = pathSegments(abs).map(foldPathCase);
814
829
  if (isAbsolutePathForm(abs) && dirSegs.some((d) => d.length <= segs.length && d.every((s, i) => s === segs[i])))
815
830
  return true;
@@ -891,6 +906,14 @@ export function askApproverIdentity(onAsk) {
891
906
  export function isLiveApproverSeat(onAsk) {
892
907
  return typeof onAsk === "function";
893
908
  }
909
+ export const DURABLE_MANDATE_SOURCES = ["force_durable_gate", "durable_approval"];
910
+ export function durableMandateSourceOf(args) {
911
+ if (args.forceDurableGate)
912
+ return "force_durable_gate";
913
+ if (args.durableApprovalDeclared && !isLiveApproverSeat(args.onAsk))
914
+ return "durable_approval";
915
+ return undefined;
916
+ }
894
917
  export function tryCloneArgs(v) {
895
918
  try {
896
919
  const value = structuredClone(v);
@@ -35,7 +35,7 @@ export interface AggregateBudgetOptions {
35
35
  sizeChars: number;
36
36
  storeFallback: boolean;
37
37
  }) => void;
38
- /** RB-142: fired once per batch that is STILL over budget after both passes — i.e. the cap did what it
38
+ /** Fired once per batch that is STILL over budget after both passes — i.e. the cap did what it
39
39
  * could and the request is going out oversized anyway. Reachable when a batch holds more results than
40
40
  * the budget can hold even at the minimum preview size (a compact preview has a floor, and N of them
41
41
  * cannot be smaller than N × that floor). Before this existed the shortfall was entirely silent, so a
@@ -25,7 +25,7 @@ export interface ToolResultStore {
25
25
  * deterministic ref, so `put` for an already-stored ref MUST be a no-op — re-writing would risk a
26
26
  * non-identical preview and break the prompt cache). A durable backend treats `ref` as the primary key
27
27
  * and should validate/sanitize it (it is composed from sessionId+toolCallId, not raw model input, but a
28
- * durable store still owns key hygiene for its storage layer). RB-266: the floor of that hygiene is
28
+ * durable store still owns key hygiene for its storage layer). The floor of that hygiene is
29
29
  * NOT per-backend — every implementation rejects the unsafe ref set via {@link assertSafeToolResultRef}
30
30
  * (a volatile backend silently accepting what a durable one rejects is the drift this closes).
31
31
  *
@@ -139,7 +139,7 @@ export interface ToolResultDeletionReport {
139
139
  * the read face authorizes by COMPARING fields it already knows; `taskId` is present when the write site
140
140
  * has one (it is a narrowing of the session, never a substitute for it).
141
141
  *
142
- * #167 (namespace rule): a stamped `taskId` must name a coordinate the read face's CALLER presents —
142
+ * A stamped `taskId` must name a coordinate the read face's CALLER presents —
143
143
  * the host's own task/run id — never an engine-internal registry handle id. A handle id lives in a
144
144
  * namespace only the engine's in-memory registry can resolve, so an owner stamped with one compares
145
145
  * unequal to every caller coordinate forever: the entry becomes readable by NOBODY across the wire
@@ -181,7 +181,7 @@ export declare function assertToolResultProvenanceMatch(ref: string, stored: Too
181
181
  * round-tripping through a durable backend (NULL column, missing JSON key) compares equal. */
182
182
  export declare function normalizeToolResultProvenance(p: ToolResultProvenance): ToolResultProvenance;
183
183
  /**
184
- * RB-266 — the ref-safety half of the {@link ToolResultStore} contract, shared by every backend.
184
+ * The ref-safety half of the {@link ToolResultStore} contract, shared by every backend.
185
185
  *
186
186
  * Why it is central and not per-backend: the file backend has always rejected these refs (its path
187
187
  * component guard, `stores/file/fs-atomic.ts:48`), while the in-memory backend accepted them
@@ -207,7 +207,7 @@ export declare function normalizeToolResultProvenance(p: ToolResultProvenance):
207
207
  */
208
208
  export declare function assertSafeToolResultRef(ref: string): void;
209
209
  /**
210
- * RB-273 — the SINGLE mint point for a tool-result `ref`. Three call sites compose the same
210
+ * The SINGLE mint point for a tool-result `ref`. Three call sites compose the same
211
211
  * `tr_<sessionId>~<toolCallId>` string (`withToolResultOffload` here, the aggregate budget's preview
212
212
  * pass, and the runner's clear-with-offload persist); this is that string's one definition.
213
213
  *
@@ -320,7 +320,7 @@ export declare class InMemoryToolResultStore implements ToolResultStore {
320
320
  private readonly opts?;
321
321
  /** put/get only — no scheduled deletion contract: honestly `"none"` (retention.ts). */
322
322
  readonly retention: "none";
323
- /** #119: the entry is content AND owner as ONE value — the write-once election that decides the
323
+ /** The entry is content AND owner as ONE value — the write-once election that decides the
324
324
  * content decides the owner in the same step (no window where an entry exists ownerless). */
325
325
  private readonly map;
326
326
  private totalChars;
@@ -328,7 +328,7 @@ export declare class InMemoryToolResultStore implements ToolResultStore {
328
328
  maxTotalChars?: number;
329
329
  } | undefined);
330
330
  put(ref: string, content: string, provenance?: ToolResultProvenance): void;
331
- /** #119 — the owner recorded at the winning write; `undefined` for unknown AND for unowned entries,
331
+ /** The owner recorded at the winning write; `undefined` for unknown AND for unowned entries,
332
332
  * which a read face treats identically (fail-closed). */
333
333
  ownerOf(ref: string): ToolResultProvenance | undefined;
334
334
  /** Erase this session's entries, selected on the owner recorded at the winning write (the interface
@@ -370,7 +370,7 @@ export declare class ScopedToolResultStore implements ToolResultStore {
370
370
  readonly volatileBacking: boolean;
371
371
  constructor(inner: ToolResultStore, scope: string);
372
372
  /** Length-prefixed namespace — unambiguous for any scope string (no delimiter-injection ambiguity).
373
- * RB-266: the scope segment is ENCODED (injective, and its output charset carries no path separator
373
+ * The scope segment is ENCODED (injective, and its output charset carries no path separator
374
374
  * or control character), so a deployment whose trust scope contains one cannot compose a key the
375
375
  * inner store must reject — the ref-safety rule then applies to the caller's ref alone. */
376
376
  private key;
@@ -379,7 +379,7 @@ export declare class ScopedToolResultStore implements ToolResultStore {
379
379
  offset?: number;
380
380
  limit?: number;
381
381
  }): Promise<ToolResultSlice | undefined> | ToolResultSlice | undefined;
382
- /** #119 — same namespacing as {@link get}. `undefined` when the inner store predates the operation
382
+ /** Same namespacing as {@link get}. `undefined` when the inner store predates the operation
383
383
  * (an unowned answer, which the read face reads fail-closed — never a fabricated owner). */
384
384
  ownerOf(ref: string): Promise<ToolResultProvenance | undefined> | ToolResultProvenance | undefined;
385
385
  /** THIS task's offload count only — the D-2 gate's per-task semantics (see class doc). */
@@ -390,10 +390,10 @@ export declare function isVolatileOffloadStore(store: ToolResultStore): boolean;
390
390
  /** Reserved name of the injected large-result reader (design/108 PascalCase: `read_tool_result`→`ReadToolResult`). */
391
391
  export declare const OFFLOAD_TOOL_NAME = "ReadToolResult";
392
392
  /**
393
- * RB-469-d — the runner's clear-with-offload persist, as ONE construction point (the closure used to
393
+ * The runner's clear-with-offload persist, as ONE construction point (the closure used to
394
394
  * live inline in prepare-task). Fire-and-forget by design (the caller returns the ref synchronously).
395
395
  *
396
- * #167 (A-025.17) — a failed put REPORTS the loss, it never writes under the ref. The previous arm
396
+ * A failed put REPORTS the loss, it never writes under the ref. The previous arm
397
397
  * wrote a lost-marker row under the SAME ref "so the page-back face reports the true cause", and that
398
398
  * one write carried two defects:
399
399
  * - **revival**: the put and a session purge can race. When the put loses, the marker write lands
@@ -450,7 +450,7 @@ export declare const DEFAULT_TOOL_RESULT_THRESHOLD_CHARS = 20000;
450
450
  * the per-message aggregate budget (design/64 §17.2) produces the SAME preview format (deterministic →
451
451
  * byte-identical across queries → prompt-cache safe).
452
452
  *
453
- * #115 (2026-08-09) — the truncation line states WHERE the rest is, not what anyone can do with it.
453
+ * The truncation line states WHERE the rest is, not what anyone can do with it.
454
454
  * "read more" alone reads as a promise that the full output is retrievable, and the model relays that
455
455
  * promise to the person it is talking to; what is actually guaranteed is narrower and exactly two
456
456
  * things: the text is retained in this run's tool-result store, and THIS chain can page it back. A
@@ -48,7 +48,7 @@ export interface ReversibilityVerdict {
48
48
  * a malformed value costs the DISCLOSURE only, never the ask. */
49
49
  cause?: import("./checkpoint-store.js").ProbeCause;
50
50
  /**
51
- * #502 (additive) — this demotion is STRUCTURAL, not the probe hesitating: the call crosses a
51
+ * This demotion is STRUCTURAL, not the probe hesitating: the call crosses a
52
52
  * boundary the deployment declared, so a persisted allow rule must not retire the resulting ask.
53
53
  * The gate folds it into the #144 mandate family ("allow rules silence the CLASSIFIER's questions,
54
54
  * never a MANDATED one") beside an operator `shellGate:"always"` and the tool's own
@@ -385,7 +385,7 @@ export interface ToolSpec<TParams extends TSchema = TSchema> {
385
385
  */
386
386
  defer?: boolean;
387
387
  /**
388
- * RB-400-a — inline-keep override, judged FIRST in the deferral chain (CC 220 counterpart:
388
+ * Inline-keep override, judged FIRST in the deferral chain (CC 220 counterpart:
389
389
  * `alwaysLoad`, declared per MCP tool via `_meta["anthropic/alwaysLoad"]`, whose `isDeferredTool`
390
390
  * checks it before every deferral arm): `true` pins this tool's full schema inline in every
391
391
  * request — it is never deferred, regardless of its own {@link defer}, {@link TaskSpec.deferTools},
@@ -493,7 +493,7 @@ export type ToolReturn = string | {
493
493
  /** Hint the agent to stop after this tool batch. */
494
494
  terminate?: boolean;
495
495
  /**
496
- * RB-211 (root-cause widening): a `ToolSpec.execute` can RETURN a failure
496
+ * A `ToolSpec.execute` can RETURN a failure
497
497
  * receipt instead of throwing (teaching errors that carry structured `details`, e.g. an
498
498
  * unrecoverable-but-informative rejection). Before this field existed, `ToolReturn` had NO
499
499
  * isError channel at all — `defineTool`'s wrapper builds a fresh `{content,details,terminate}`
@@ -872,21 +872,15 @@ export interface ToolExecuteContext {
872
872
  */
873
873
  interactiveTools?: false;
874
874
  /**
875
- * RB-220 — read-only mirror of {@link "./types.js".TaskSpec.oneShot} (same trust tier/seat as
875
+ * Read-only mirror of {@link "./types.js".TaskSpec.oneShot} (same trust tier/seat as
876
876
  * `principal`): this RUN has no later turn for an async background notification to land in (a
877
877
  * headless `-p` process exits once the turn ends). A delegation tool (`createSubagentTool`) reads
878
878
  * it to branch its background-launch RECEIPT toward an active block-wait instruction instead of
879
- * "end your turn and wait" — mirrors {@link import("../orchestration/run-workflow-tool.js").RunWorkflowToolDeps.oneShot}'s
880
- * guidance-text branch for `run_workflow`. Undefined when the tool runs outside a Runner task.
879
+ * "end your turn and wait" — the Workflow tool branches its launch receipt the same way off the seat it is
880
+ * mounted with (`RunWorkflowToolDeps.parentSpecSeat.oneShot`). The CHILDREN's copy rides {@link parentSpecSeat}
881
+ * (only `true` travels there). Undefined when the tool runs outside a Runner task.
881
882
  */
882
883
  oneShot?: boolean;
883
- /**
884
- * design/112 C1/C5 — read-only SNAPSHOT of the parent task's client-supplied USER facts (timeZone/userEmail),
885
- * inherited verbatim down the delegation tree like `principal`, so a subagent/fork child's
886
- * `# Environment` block localizes "today" to the SAME user zone (not the container's UTC) and names the same
887
- * user. Runner-filled (NOT a tool argument). Undefined when the task carries no clientContext.
888
- */
889
- clientContext?: TaskSpec["clientContext"];
890
884
  /** — the parent's tool-face controls ({@link TaskSpec.excludeTools} /
891
885
  * {@link TaskSpec.deferTools}), inherited down the delegation tree like `principal` (Runner-filled,
892
886
  * read-only): a scenario-wide roster must not be escapable by delegating to a child that remounts
@@ -911,30 +905,32 @@ export interface ToolExecuteContext {
911
905
  * tool-face controls (Runner-filled): a classic-profile parent's children speak classic too
912
906
  * unless the child spec says otherwise (child spec wins — profile is presentation, not policy). */
913
907
  promptProfile?: "simple" | "classic";
914
- /** the parent's declared extra file-tool roots ({@link TaskSpec.additionalDirectories}),
915
- * inherited down the delegation tree (Runner-filled, copy-at-spawn): a deployment that widened the
916
- * fs fence (e.g. the scratchpad host lane) widened it for the TASK, and a delegated child doing the
917
- * same work hit `path_not_in_root` on the very directory the parent could write. Same trust tier as
918
- * the spec field (deployment declaration, never a model argument). */
919
- additionalDirectories?: readonly string[];
920
- /** The read-only half of the same seat ({@link TaskSpec.additionalReadDirectories}), inherited by
921
- * the same rule (Runner-filled, copy-at-spawn): a child doing the parent's work needs the same
922
- * read whitelist, and MUST NOT have it silently widened into a write grant in transit. */
923
- additionalReadDirectories?: readonly string[];
924
- /** the parent's environment facts ({@link TaskSpec.envFacts}), inherited down the
925
- * delegation tree (Runner-filled, copy-at-spawn): the sandbox binding (profile/egress/scratchpad)
926
- * is a DEPLOYMENT property, not a per-task one a child in the same sandbox needs the same facts
927
- * (its env block renders the scratchpad section; its root fence admits the scratchpad dir). */
928
- envFacts?: TaskSpec["envFacts"];
929
- /**
930
- * The parent task's DECLARED {@link TaskSpec.memoryPersistenceCapable} — present ONLY when the spec
931
- * set it (an inferred run's ctx gains no key), Runner-filled on the same trusted seat as
932
- * {@link principal}: never a model/tool argument. A delegation tool (`createSubagentTool`) forwards
933
- * it into every child spec it builds so the deployment's persistence statement survives delegation:
934
- * `false` is a floor a chosen agent definition cannot loosen (the read-only-memory disclosure must
935
- * hold tree-wide when the deployment says nothing durable is reachable), `true` is a default a
936
- * definition may narrow back to `false`. Absent nothing is forwarded and each child's own roster
937
- * inference decides, exactly as before the seat existed.
908
+ /**
909
+ * The parent SPEC seat this run hands its children ({@link import("./parent-spec-seat.js").ParentSpecSeat}):
910
+ * `principal`, `oneShot` (only `true`), `clientContext` (the user's TZ/email facts), `onQuestion` (the FROZEN
911
+ * question face `AskUserQuestion` mounts on it), `additionalDirectories` / `additionalReadDirectories` (the
912
+ * fs-fence widening; the read-only half stays read-only in transit), `envFacts` (the sandbox facts), and the
913
+ * DECLARED `memoryPersistenceCapable`. Runner-filled, read-only, NEVER a model/tool argument; minted ONCE per
914
+ * prepare from the run's rebound spec + frozen question face (arrays and the facts object frozen copies). ABSENT
915
+ * when the tool runs outside a Runner task.
916
+ *
917
+ * A delegation tool applies it onto every child spec it builds with `applyParentSpecSeat` — the ONE law both
918
+ * delegation lanes (Task and Workflow) share: a value the child spec already carries WINS (an agent definition's
919
+ * own declaration, a deployment baseline, a trusted script), the seat FILLS an unset one, and the two REMOVAL
920
+ * values (`oneShot: true`, `memoryPersistenceCapable: false`) land unconditionally. A deployment that widened the
921
+ * fs fence widened it for the TASK, a per-request question face is the child's face too, a one-shot process is
922
+ * one-shot for the whole tree — none of that stops at one level.
923
+ */
924
+ parentSpecSeat?: import("./parent-spec-seat.js").ParentSpecSeat;
925
+ /** This run's per-request question face was STRIPPED by the engine (`RunInternals.questionFaceStripped` the leg outlives
926
+ * the request that spawned it), Runner-filled read-only. A delegation tool forwards it onto every descendant's internals:
927
+ * the descendants are faceless by the same engine act, so the posture door's exemption travels with them. */
928
+ questionFaceStripped?: true;
929
+ /**
930
+ * The parent task's DECLARED {@link TaskSpec.memoryPersistenceCapable} as THIS run's own fact present ONLY when
931
+ * the spec set it (an inferred run's ctx gains no key), Runner-filled on the same trusted seat as {@link principal}:
932
+ * never a model/tool argument. Read by the revival spawner as the waking run's own clamp (a declared `false` forces
933
+ * the read-only-memory disclosure onto the cycle it wakes). The CHILDREN's copy rides {@link parentSpecSeat}.
938
934
  */
939
935
  memoryPersistenceCapable?: boolean;
940
936
  /**
@@ -954,7 +950,7 @@ export interface ToolExecuteContext {
954
950
  */
955
951
  memoryCaptureOptedOut?: boolean | Promise<boolean>;
956
952
  /**
957
- * design/383 §2.5 (rescan post-6.0.0-RC) — the floor seat's THIRD state: TRUE ⇔ the spawning
953
+ * design/383 §2.5 — the floor seat's THIRD state: TRUE ⇔ the spawning
958
954
  * session's capture opt-out state is INDETERMINATE at the moment a delegation tool reads this
959
955
  * seat (its capture record store is faulting, and no genuine record is known in-process). The
960
956
  * delegation lanes forward it into the child's trusted internals as the floor's indeterminate
@@ -44,7 +44,7 @@ export declare function stampDefineToolBrand<T extends object>(tool: T, rebind:
44
44
  */
45
45
  export declare function rebindDefineToolCtx(product: AgentTool, enrich: ToolCtxEnricher): AgentTool;
46
46
  /**
47
- * RB-409 — a per-call ctx builder a MOUNT hands to {@link defineTool}.
47
+ * A per-call ctx builder a MOUNT hands to {@link defineTool}.
48
48
  *
49
49
  * Why the seat exists: the adapter below feeds the inner `ToolSpec.execute` a `{toolCallId, signal}`
50
50
  * ctx, because `AgentTool.execute(toolCallId, rawParams, signal, onUpdate)` — the contract every
@@ -72,7 +72,7 @@ export type ToolCtxEnricher = (base: ToolExecuteContext) => ToolExecuteContext;
72
72
  * typing accepts without needing the name.
73
73
  */
74
74
  export interface DefineToolOptions {
75
- /** RB-409 — see {@link ToolCtxEnricher}. Absent ⇒ the inner spec sees exactly the pre-RB-409
75
+ /** See {@link ToolCtxEnricher}. Absent ⇒ the inner spec sees exactly the pre-RB-409
76
76
  * `{toolCallId, signal}` ctx, so every mount that does not opt in stays byte-identical. */
77
77
  enrichCtx?: ToolCtxEnricher;
78
78
  }
@@ -58,7 +58,7 @@ export type TraceEvent = {
58
58
  kind: "task.start";
59
59
  version: 1;
60
60
  taskId: string;
61
- /** #499 (additive) — the ENGINE-minted identity of THIS run (`TaskResult.runId`). `taskId` is
61
+ /** The ENGINE-minted identity of THIS run (`TaskResult.runId`). `taskId` is
62
62
  * `spec.taskId ?? sessionId`, so two runs of one session that declare no host task id emit two
63
63
  * task.start frames under ONE id and a consumer pairing start↔end has no way to say which end
64
64
  * closes which start. Present on every `task.start` (the frame is emitted after prepare, which
@@ -264,7 +264,7 @@ export type TraceEvent = {
264
264
  kind: "task.end";
265
265
  version: 1;
266
266
  taskId: string;
267
- /** #499 (additive) — the run this terminal closes; pairs with the `task.start` frame's `runId`
267
+ /** The run this terminal closes; pairs with the `task.start` frame's `runId`
268
268
  * (see that field for why `taskId` cannot carry the pairing, and for the ASYMMETRY: this frame
269
269
  * is also emitted on the prepare-throw backstop, where no `task.start` exists — it still names
270
270
  * its run, because the id is minted at prepare's first statement and prepare-time disclosures
@@ -290,7 +290,7 @@ export type TraceEvent = {
290
290
  * loop breathes, so lateness this size means the environment starved the process (run89: an
291
291
  * abandoned compile group froze the loop 646s; the 1200s hard abort landed 683s late). */
292
292
  timerLatenessMs?: number;
293
- /** RB-20 (TB b-form): the run was stopped by the SYNCHRONOUS turn-boundary walltime
293
+ /** The run was stopped by the SYNCHRONOUS turn-boundary walltime
294
294
  * backstop, not the hard-abort timer — i.e. the deadline had passed but the setTimeout leg
295
295
  * had not fired yet (starved event loop). Pairs with `timerLatenessMs` for attribution. */
296
296
  walltimeSyncBackstop?: boolean;
@@ -308,7 +308,7 @@ export type TraceEvent = {
308
308
  model: string;
309
309
  provider?: string;
310
310
  /**
311
- * RB-410 — 1-based index of the turn this provider call served, same numbering as `turn.end` and as
311
+ * 1-based index of the turn this provider call served, same numbering as `turn.end` and as
312
312
  * `tool.call.turn`. Lets a bridge put a `chat` span and the `execute_tool` spans of the tools that
313
313
  * call requested under one parent without re-deriving turn boundaries from event order.
314
314
  *
@@ -316,10 +316,10 @@ export type TraceEvent = {
316
316
  * is not a loop turn, so any number here would be a different measurement wearing the same name.
317
317
  */
318
318
  turn?: number;
319
- /** RB-457-a: normalized prompt tokens that MISSED the cache (Anthropic-protocol `input_tokens`
319
+ /** Normalized prompt tokens that MISSED the cache (Anthropic-protocol `input_tokens`
320
320
  * shape) — disjoint from `cacheRead`/`cacheWrite`. Carried the cache-inclusive total up to 2.13.x. */
321
321
  promptTokens: number;
322
- /** RB-457-a: the cache-INCLUSIVE prompt total for this call (`promptTokens + cacheRead +
322
+ /** The cache-INCLUSIVE prompt total for this call (`promptTokens + cacheRead +
323
323
  * cacheWrite`) — the figure `costMicroUsd` is computed from. */
324
324
  totalInputTokens: number;
325
325
  completionTokens: number;
@@ -349,7 +349,7 @@ export type TraceEvent = {
349
349
  taskId: string;
350
350
  name: string;
351
351
  /**
352
- * RB-410 — the resolved call's id: the SAME value the wire's `tool_start`/`tool_end` `TaskEvent`
352
+ * The resolved call's id: the SAME value the wire's `tool_start`/`tool_end` `TaskEvent`
353
353
  * carries for this call. OTel GenAI names it `gen_ai.tool.call.id` on the `execute_tool` span.
354
354
  *
355
355
  * Why it matters: without it the trace face and the event face could only be paired by tool NAME
@@ -358,7 +358,7 @@ export type TraceEvent = {
358
358
  */
359
359
  toolCallId?: string;
360
360
  /**
361
- * RB-410 — 1-based index of the turn this call ran in, on the same numbering `turn.end` reports
361
+ * 1-based index of the turn this call ran in, on the same numbering `turn.end` reports
362
362
  * (a `tool.call` is emitted BEFORE the `turn.end` that closes its turn, so the two agree without
363
363
  * look-ahead). No GenAI attribute corresponds; it is the PARENT-span correlation key a bridge
364
364
  * needs to nest an `execute_tool` span under the `chat` call that requested the tool.
@@ -427,7 +427,7 @@ export type TraceEvent = {
427
427
  ts: number;
428
428
  } | {
429
429
  /**
430
- * #619 — the READ-ONLY reader cleared a shell call, so no person and no classifier was asked: the
430
+ * The READ-ONLY reader cleared a shell call, so no person and no classifier was asked: the
431
431
  * allow layer's second attribution channel beside `permission.persisted_rule_allowed`. `command` is
432
432
  * the FINAL command the gate judged (a policy rewrite included) — model-authored text, carried
433
433
  * verbatim as the audit fact this frame exists for (a consumer rendering it applies its own
@@ -802,12 +802,9 @@ export type TraceEvent = {
802
802
  * = the proactive request-build pass (anchored estimate crossed the edit budget),
803
803
  * `"refusal"` = the MC-R rejection-recovery arm (provider said input-too-long), `"blocking"`
804
804
  * = the slice-3 guard-chain arm A (the machine's one pre-guard shot when the frontier pass
805
- * is off, `microCompact.machine: "off"`). SCOPE (X1): emitted only by the cc machine — the
806
- * `"frontier"` arm requires `microCompact.machine: "cc"` (the default since the slice-3
807
- * flip), the `"refusal"` arm requires `microCompact.clearOnRejection` (also default-on);
808
- * the legacy OPT-OUT machine clears silently exactly as pre-374 (its clears are ledger-less
809
- * and re-fire per request, so a frame there would re-count the same occurrences and break
810
- * this frame's cardinality clause). Cardinality: exactly ONE frame per firing pass — a retry
805
+ * is off, `microCompact.machine: "off"`). The `"frontier"` arm requires
806
+ * `microCompact.machine: "cc"` (the default), the `"refusal"` arm requires
807
+ * `microCompact.clearOnRejection` (also default-on). Cardinality: exactly ONE frame per firing pass — a retry
811
808
  * chain re-sending an already-cleared view emits none. A `"refusal"` frame also marks one
812
809
  * attempt of the shared prompt-too-long recovery budget spent (the MC-R arm's retry rides
813
810
  * the same per-chain account the forced-compaction arm draws on — the knob doc on
@@ -394,7 +394,7 @@ export declare function defuseControlChars(text: string): string;
394
394
  * Defense-in-depth, NOT a guarantee (same posture as the rest of this module).
395
395
  */
396
396
  export declare function inlineUntrusted(text: string, maxLen?: number): string;
397
- /** backlog #239: the per-ENTRY ceiling inside a `ProbeCause` operand family (checkpoint-store's
397
+ /** The per-ENTRY ceiling inside a `ProbeCause` operand family (checkpoint-store's
398
398
  * structured probe account), sized like the descriptor's own `touchedPaths` entries (the same thing
399
399
  * on the same card). Per entry, not per cause: that is the whole point of the structured shape —
400
400
  * one pathological path costs only itself, where a single joined string let it consume every other
@@ -46,7 +46,8 @@ export type AskEffective = "human_reachable" | "auto_allow" | "auto_deny" | "par
46
46
  * The content-question channel, three-valued (design/173 §8.2 — a derived enum, not a bare
47
47
  * boolean): `"wired"` (a resolved `onQuestion` face exists), `"absent"` (none), or
48
48
  * `"stripped_bg_lane"` — the ENGINE deliberately stripped the spawn turn's per-request face from a
49
- * long-lived background/retained leg (correct design, not a configuration lie; the flag is minted
49
+ * leg that outlives the request: a session-scoped background/retained leg, or an agent the Workflow tool
50
+ * spawned (submit-and-return) — correct design, not a configuration lie; the flag is minted
50
51
  * ONLY by the engine's strip sites, pair-produced with the strip itself — never inferred from spec
51
52
  * shape).
52
53
  */
@@ -58,7 +59,7 @@ export type SeamProvenance = "spec" | "deps";
58
59
  /** Machine-readable reason codes for a park lane that is not (or not provably) effective. */
59
60
  export type ParkLaneReason = "no_checkpoint_store" | "no_durable_approval_opt_in" | "no_force_durable_gate" | "no_armed_safety_vocabulary" | "await_runtime_caps" | "await_tool_vocabulary";
60
61
  /**
61
- * #529 — the closed set of auto-mode ARMING outcomes a leg's manifest reports
62
+ * The closed set of auto-mode ARMING outcomes a leg's manifest reports
62
63
  * ({@link WiringManifest.autoMode}). Minted from the arming predicate's own three-arm read, as the
63
64
  * FIRST failing arm in predicate order:
64
65
  * - `no_intent` — no `TaskSpec.autoModeRequested` seat and no intent inherited on the chain /
@@ -244,7 +245,7 @@ export interface WiringManifest {
244
245
  restore: string;
245
246
  };
246
247
  /**
247
- * #529 — EFFECTIVE half only, and ALWAYS present on an engine-minted effective manifest (unlike
248
+ * EFFECTIVE half only, and ALWAYS present on an engine-minted effective manifest (unlike
248
249
  * `modelGate`, which is present only when a trim happened: auto mode has an answer on every leg,
249
250
  * so absence here means an older mint or an external derivation, never "not applicable"). The
250
251
  * per-leg READ face of the auto-mode arming decision: `armed` ⇔ `reason === "armed"` (the
@@ -15,7 +15,7 @@ export type WorkflowJournalEntry = {
15
15
  callKey: string;
16
16
  result?: never;
17
17
  /**
18
- * #642 — the ordinal's leg is PARKED at a durable approval gate: the child's own paused `TaskResult`
18
+ * The ordinal's leg is PARKED at a durable approval gate: the child's own paused `TaskResult`
19
19
  * (its `terminal` carries the checkpoint token + gate, its `sessionId` the pinned session). A resume
20
20
  * reaching this ordinal with a matching call key does NOT run the call live (the parked child's
21
21
  * session is pinned under a pending checkpoint; a fresh spawn would duplicate it) — it drives the
@@ -73,7 +73,7 @@ export interface WorkflowJournalStore {
73
73
  * line teaches only the TaskOutput route (which is always live). Engine-facing string, never parsed. */
74
74
  locator?(runId: string, scope: string): string | undefined;
75
75
  /**
76
- * RB-242 (ruled 2026-07-30) — ADMISSION for a resume, so two concurrent
76
+ * ADMISSION for a resume, so two concurrent
77
77
  * `resumeFromRunId` legs off ONE source run cannot fork its execution.
78
78
  *
79
79
  * Why a store seam at all: the engine's own mutex is in-process only (`startWorkflow` refuses a duplicate
@@ -84,7 +84,7 @@ export interface WorkflowJournalStore {
84
84
  * shared durable layer, i.e. here.
85
85
  *
86
86
  * OPTIONAL, and absence is a first-class state: a store that does NOT implement this has NO STORE-LEVEL lease
87
- * semantics. RB-367 (dual-process probe): a store without the hook is no longer completely
87
+ * semantics. A store without the hook is no longer completely
88
88
  * unguarded, though — `runWorkflow`'s engine falls back to a process-local admission table for exactly this
89
89
  * shape, so a same-process double `resumeFromRunId` off one source is still refused even against a store
90
90
  * that never implements this member. That fallback cannot see a SECOND process, which is the one thing a
@@ -132,7 +132,7 @@ export interface WorkflowJournalStore {
132
132
  holder?: string;
133
133
  }>;
134
134
  /**
135
- * RB-242 — release the claim {@link resumeClaim} granted to `newRunId` on `(sourceRunId, scope)`.
135
+ * Release the claim {@link resumeClaim} granted to `newRunId` on `(sourceRunId, scope)`.
136
136
  * Called by the engine at the resuming run's TERMINAL boundary (in a `finally`, so abort/error/abandon are
137
137
  * covered), and ONLY when the matching claim was actually granted.
138
138
  *
@@ -143,7 +143,7 @@ export interface WorkflowJournalStore {
143
143
  * A throw here is swallowed by the engine — a release failure must never replace the run's real outcome, and
144
144
  * the store's TTL is the standing backstop for the row it left behind.
145
145
  *
146
- * RB-355: the engine's terminal boundary now BOUNDS this call (and its wait on
146
+ * The engine's terminal boundary now BOUNDS this call (and its wait on
147
147
  * the {@link resumeClaim} verdict) by a timeout — a store that hangs would otherwise keep the run's `done`
148
148
  * promise pending forever, after the outcome is already decided. A release that outlives that bound is
149
149
  * treated exactly like one that throws: swallowed, with the TTL as the backstop. Implementations should not
@@ -158,7 +158,7 @@ export declare const MAX_JOURNAL_RESULT_BYTES: number;
158
158
  /** True when a serialized journal result is too large to store (UTF-8 byte length over {@link MAX_JOURNAL_RESULT_BYTES}). */
159
159
  export declare function oversizeJournalResult(serialized: string): boolean;
160
160
  export declare function callKeyOrdinal(callKey: string): number;
161
- /** RB-243: the errorCode a journal OVERSIZE TOMBSTONE carries — the resume path recognizes it to
161
+ /** The errorCode a journal OVERSIZE TOMBSTONE carries — the resume path recognizes it to
162
162
  * say WHY an ordinal never replays. `failed` + this code lands on the T2A-4 no-replay arm, so replay
163
163
  * behavior is identical to the entry simply being absent (the pre-tombstone shape). */
164
164
  export declare const JOURNAL_OVERSIZE_ERROR_CODE = "workflow.journal_oversize";
@@ -192,7 +192,7 @@ export declare class WorkflowJournalOversizeError extends Error {
192
192
  * answer is the rule, the engine's tombstone the one place that pre-empts it.
193
193
  */
194
194
  export declare function assertJournalEntryFits(entry: WorkflowJournalEntry): void;
195
- /** RB-243: mint the tiny FAILED entry the ENGINE journals in place of an oversize result. The
195
+ /** Mint the tiny FAILED entry the ENGINE journals in place of an oversize result. The
196
196
  * tombstone is minted in the engine, NOT in a store — a store REFUSES an oversize entry
197
197
  * ({@link assertJournalEntryFits}) and never invents one; the engine measures the durable copy first, so
198
198
  * the store sees the tombstone, not the payload. Never copies `result.result`/`structuredOutput` (the
@@ -200,7 +200,7 @@ export declare function assertJournalEntryFits(entry: WorkflowJournalEntry): voi
200
200
  * and the paid spend. Its own serialization is a few hundred bytes — always under the cap (pinned). */
201
201
  export declare function journalOversizeTombstone(result: TaskResult, bytes: number): TaskResult;
202
202
  /**
203
- * RB-367 (dual-process probe, core-side judgment) — the TTL a resume claim {@link
203
+ * The TTL a resume claim {@link
204
204
  * InMemoryWorkflowJournalStore} grants survives WITHOUT an engine release: the backstop for an engine that
205
205
  * abandoned a granted claim without ever reaching the terminal `finally` that releases it (a bug, not the
206
206
  * normal path — the normal path releases promptly). Same VALUE as the file store's `RESUME_CLAIM_TTL_MS`
@@ -214,7 +214,7 @@ export declare const IN_MEMORY_RESUME_CLAIM_TTL_MS: number;
214
214
  * service's Postgres store (SVC-2). Records each run's `scope` and enforces it on load (CORE-9 audit BLOCKER:
215
215
  * a cross-scope resumeFromRunId resolves to an empty journal — no cross-tenant disclosure).
216
216
  *
217
- * RB-367: also carries a REAL {@link WorkflowJournalStore.resumeClaim}/{@link
217
+ * Also carries a REAL {@link WorkflowJournalStore.resumeClaim}/{@link
218
218
  * WorkflowJournalStore.releaseResumeClaim} implementation (this store used to be the canonical example of a
219
219
  * store WITHOUT the seam — its own header said so). Left unimplemented, the DEFAULT deployment (no
220
220
  * `journalStore` supplied, or this store supplied explicitly) had NO protection against two same-process
@@ -231,7 +231,7 @@ export declare class InMemoryWorkflowJournalStore implements WorkflowJournalStor
231
231
  * collide across the boundary between the two fields. */
232
232
  private readonly resumeClaims;
233
233
  private claimsForScope;
234
- /** RB-367 — contract parity with the file store: keyed by `(sourceRunId, scope)`; idempotent re-grant to the
234
+ /** Contract parity with the file store: keyed by `(sourceRunId, scope)`; idempotent re-grant to the
235
235
  * SAME holder; an unexpired claim held by someone else refuses (naming the holder); an expired or absent
236
236
  * claim is free to take. Acquisition is a single synchronous Map read-then-write with no `await` between
237
237
  * the check and the publish — there is no window (matching the atomicity RB-354 requires of a durable
@@ -240,7 +240,7 @@ export declare class InMemoryWorkflowJournalStore implements WorkflowJournalStor
240
240
  granted: boolean;
241
241
  holder?: string;
242
242
  }>;
243
- /** RB-367 — release ONLY a claim `newRunId` still holds (a missing/foreign/already-taken-over claim is a
243
+ /** Release ONLY a claim `newRunId` still holds (a missing/foreign/already-taken-over claim is a
244
244
  * no-op, never an error — matches the file store's contract). */
245
245
  releaseResumeClaim(input: ResumeClaimArgs): Promise<void>;
246
246
  load(runId: string, scope: string): Promise<WorkflowJournalEntry[]>;
@@ -79,8 +79,9 @@ export declare function openSpoolPair(base: string): {
79
79
  };
80
80
  export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCapability, SchedulerCapability {
81
81
  cwd: string;
82
- /** #644 this adapter runs on the engine host, so the host's home IS the environment's (`ExecutionEnv.homeDir`). */
83
- readonly homeDir: string;
82
+ /** `ExecutionEnv.homeDir` = the `HOME` the shell child receives (its `~`/`$HOME`/`${HOME}` all expand to it), read LIVE off the same `shellEnv`-over-`inheritEnv` merge each exec gets; ABSENT when the
83
+ * child gets none (an allowlist that withholds it: `~` then falls back to passwd while `$HOME` is empty — two values, no single home, home-relative operands stay fail-closed). Residual: a per-exec `env.HOME` override. */
84
+ get homeDir(): string | undefined;
84
85
  private shellPath?;
85
86
  private shellEnv?;
86
87
  private inheritEnv;
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { closeSync, constants, createReadStream, mkdtempSync, openSync, readSync, statSync, truncateSync, unlinkSync } from "node:fs";
4
4
  import { access, appendFile, lstat, mkdir, mkdtemp, open, readdir, readFile, readlink, realpath, rename, rm, unlink, writeFile, } from "node:fs/promises";
5
- import { homedir, tmpdir } from "node:os";
5
+ import { tmpdir } from "node:os";
6
6
  import { isAbsolute, join, resolve } from "node:path";
7
7
  import { createInterface } from "node:readline";
8
8
  import { ExecutionError, err, FileError, ok, toError, } from "../harness/types.js";
@@ -284,7 +284,9 @@ export function openSpoolPair(base) {
284
284
  }
285
285
  export class NodeExecutionEnv {
286
286
  cwd;
287
- homeDir = homedir();
287
+ get homeDir() {
288
+ return getShellEnv(this.inheritEnv, this.shellEnv, undefined, () => { }).HOME;
289
+ }
288
290
  shellPath;
289
291
  shellEnv;
290
292
  inheritEnv;