@sema-agent/core 7.5.1 → 7.5.2

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 (66) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/core/protocol-table.d.ts +5 -0
  3. package/dist/core/protocol-table.js +1 -0
  4. package/dist/core/runner/abort-race.d.ts +41 -0
  5. package/dist/core/runner/abort-race.js +38 -0
  6. package/dist/core/runner/checkpoint-scope.d.ts +15 -3
  7. package/dist/core/runner/checkpoint-scope.js +3 -0
  8. package/dist/core/runner/compaction-call-options.d.ts +1 -1
  9. package/dist/core/runner/content-ask-bindings.d.ts +27 -0
  10. package/dist/core/runner/content-ask-bindings.js +1 -0
  11. package/dist/core/runner/contracts.d.ts +118 -6
  12. package/dist/core/runner/denial-limit-arms.d.ts +23 -0
  13. package/dist/core/runner/denial-limit-arms.js +21 -0
  14. package/dist/core/runner/inherited-ask-grants.d.ts +46 -0
  15. package/dist/core/runner/inherited-ask-grants.js +29 -0
  16. package/dist/core/runner/park-commit.d.ts +108 -0
  17. package/dist/core/runner/park-commit.js +32 -0
  18. package/dist/core/runner/{prepare-permission-rules.d.ts → permission-rule-lanes.d.ts} +109 -3
  19. package/dist/core/runner/{prepare-permission-rules.js → permission-rule-lanes.js} +47 -1
  20. package/dist/core/runner/prepare-ask-lane.d.ts +110 -0
  21. package/dist/core/runner/prepare-ask-lane.js +133 -0
  22. package/dist/core/runner/prepare-boundary-parks.d.ts +105 -0
  23. package/dist/core/runner/prepare-boundary-parks.js +169 -0
  24. package/dist/core/runner/prepare-context-lane.d.ts +119 -0
  25. package/dist/core/runner/prepare-context-lane.js +230 -0
  26. package/dist/core/runner/prepare-gate-stations.d.ts +177 -0
  27. package/dist/core/runner/prepare-gate-stations.js +290 -0
  28. package/dist/core/runner/prepare-hands-readface.d.ts +4 -4
  29. package/dist/core/runner/prepare-inherited-gate.d.ts +4 -4
  30. package/dist/core/runner/prepare-memory-engine-session.d.ts +84 -0
  31. package/dist/core/runner/prepare-memory-engine-session.js +233 -0
  32. package/dist/core/runner/prepare-park-ask.d.ts +164 -0
  33. package/dist/core/runner/prepare-park-ask.js +377 -0
  34. package/dist/core/runner/prepare-policy-chain.d.ts +208 -0
  35. package/dist/core/runner/prepare-policy-chain.js +584 -0
  36. package/dist/core/runner/prepare-project-context.d.ts +1 -13
  37. package/dist/core/runner/prepare-project-context.js +1 -3
  38. package/dist/core/runner/prepare-prompt-assembly.d.ts +95 -0
  39. package/dist/core/runner/prepare-prompt-assembly.js +162 -0
  40. package/dist/core/runner/prepare-prompt-inputs.d.ts +1 -20
  41. package/dist/core/runner/prepare-protocol-tools.d.ts +3 -3
  42. package/dist/core/runner/prepare-protocol-tools.js +0 -3
  43. package/dist/core/runner/prepare-question-face.d.ts +3 -21
  44. package/dist/core/runner/prepare-question-face.js +2 -1
  45. package/dist/core/runner/prepare-safety-scan.d.ts +0 -5
  46. package/dist/core/runner/prepare-safety-scan.js +1 -2
  47. package/dist/core/runner/prepare-suspend-saga.d.ts +170 -0
  48. package/dist/core/runner/prepare-suspend-saga.js +308 -0
  49. package/dist/core/runner/prepare-task.d.ts +9 -136
  50. package/dist/core/runner/prepare-task.js +44 -2741
  51. package/dist/core/runner/prepare-turn-wiring.d.ts +154 -0
  52. package/dist/core/runner/prepare-turn-wiring.js +201 -0
  53. package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -3
  54. package/dist/core/runner/prepare-wiring-manifest.js +9 -2
  55. package/dist/core/runner/prepare-workspace-restore.d.ts +2 -29
  56. package/dist/core/runner/prepare-workspace-restore.js +3 -16
  57. package/dist/core/runner/prompt-hash-salt.d.ts +1 -0
  58. package/dist/core/runner/prompt-hash-salt.js +2 -0
  59. package/dist/core/runner/remote-env-retry.d.ts +29 -0
  60. package/dist/core/runner/remote-env-retry.js +16 -0
  61. package/dist/core/runner/runtask.js +1 -1
  62. package/dist/core/session.d.ts +12 -0
  63. package/dist/core/session.js +3 -0
  64. package/package.json +1 -1
  65. /package/dist/core/runner/{prepare-announce-once.d.ts → announce-once-ledger.d.ts} +0 -0
  66. /package/dist/core/runner/{prepare-announce-once.js → announce-once-ledger.js} +0 -0
@@ -0,0 +1,308 @@
1
+ import { defaultTaskRegistry } from "../task-registry.js";
2
+ import { isRemoteExecutionEnv, isSuspendable, RemoteExecutionError } from "../remote-env.js";
3
+ import { constraintChainDigest, constraintChainEntryOfLayer } from "../tool-policy.js";
4
+ import { raceSettlementAgainstSignal } from "./abort-race.js";
5
+ import { placementValueOrAbsent } from "./checkpoint-scope.js";
6
+ import { serializeAnnouncedListings } from "./announce-once-ledger.js";
7
+ import { remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./remote-env-retry.js";
8
+ const PARK_COMPENSATION_TIMEOUT_MS = 30_000;
9
+ export async function compensateUnparkedPause(remoteEnv, snapshotId, io) {
10
+ const boundCtl = new AbortController();
11
+ const boundTimer = setTimeout(() => boundCtl.abort(), io.boundMs);
12
+ const bound = boundCtl.signal;
13
+ let phase = "resumeVM";
14
+ let restoreAttempts = 1;
15
+ let vmRunning = false;
16
+ const work = (async () => {
17
+ const { outcome: back, attempts: backAttempts } = await restoreWorkspaceWithRetry(remoteEnv, snapshotId, { abortSignal: bound }, (attempt) => (restoreAttempts = attempt));
18
+ if (!back.ok) {
19
+ io.noteFailure(remoteEnvFailureNote("resumeVM", back.error, backAttempts));
20
+ io.disclose(back.error);
21
+ return { ok: false, reason: `resumeVM failed (${back.error.code}) while compensating an unparked pause` };
22
+ }
23
+ vmRunning = true;
24
+ if (bound.aborted) {
25
+ return { ok: false, reason: "resumeVM settled only after the decision bound" };
26
+ }
27
+ phase = "postResumeInit";
28
+ const init = await remoteEnv.postResumeInit({ abortSignal: bound });
29
+ if (!init.ok) {
30
+ io.noteFailure(remoteEnvFailureNote("postResumeInit", init.error, 1));
31
+ io.disclose(init.error);
32
+ return { ok: false, reason: `postResumeInit failed (${init.error.code}) while compensating an unparked pause` };
33
+ }
34
+ return { ok: true };
35
+ })();
36
+ const raced = await raceSettlementAgainstSignal(work, bound);
37
+ clearTimeout(boundTimer);
38
+ if (raced.tag === "value")
39
+ return raced.value;
40
+ if (raced.tag === "threw") {
41
+ io.noteFailure(remoteEnvFailureNote(phase, raced.error instanceof RemoteExecutionError
42
+ ? raced.error
43
+ : new RemoteExecutionError("unknown", `the pause compensation's ${phase} call threw: ${raced.error instanceof Error ? raced.error.message : String(raced.error)}`), phase === "resumeVM" ? restoreAttempts : 1));
44
+ io.disclose(raced.error);
45
+ return {
46
+ ok: false,
47
+ reason: "the pause compensation threw (adapter contract violation; the deployment's error face carries the exception)",
48
+ };
49
+ }
50
+ const timedOut = new RemoteExecutionError("timeout", `the pause compensation's ${phase} call did not settle within the ${io.boundMs}ms decision bound`);
51
+ io.noteFailure(remoteEnvFailureNote(phase, timedOut, phase === "resumeVM" ? restoreAttempts : 1));
52
+ io.disclose(timedOut);
53
+ const destroyOwnerlessLate = () => {
54
+ io.disclose(new Error(`park compensation settled after its ${io.boundMs}ms decision bound: the VM is running with no run ` +
55
+ `left to own it — destroying the env (an ownerless running VM must not linger; the run already took ` +
56
+ `the fail-closed arm when the bound fired)`));
57
+ void Promise.resolve()
58
+ .then(() => remoteEnv.destroy())
59
+ .catch((destroyErr) => io.disclose(destroyErr));
60
+ };
61
+ void work.then((late) => {
62
+ if (vmRunning) {
63
+ destroyOwnerlessLate();
64
+ return;
65
+ }
66
+ void late;
67
+ }, (lateErr) => {
68
+ io.disclose(lateErr);
69
+ if (vmRunning)
70
+ destroyOwnerlessLate();
71
+ });
72
+ return {
73
+ ok: false,
74
+ reason: `the pause compensation did not settle within ${io.boundMs}ms — treated as failed (a late-restored VM is destroyed; a late restore failure is disclosed)`,
75
+ };
76
+ }
77
+ function stampPlacementRootSessionId(placementRootResolved) {
78
+ return placementValueOrAbsent(placementRootResolved);
79
+ }
80
+ function autoModeLatchHealthy(d) {
81
+ try {
82
+ return d.breakerOpen() !== true && typeof d.consecutiveFailures === "function" && d.consecutiveFailures() === 0;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ }
88
+ export function prepareSuspendSaga(input) {
89
+ const { gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, inheritedParentConstraints, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, autoModeIntent, autoModeDecider, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter } = input;
90
+ if (!gateMachineryActive)
91
+ return { saga: undefined };
92
+ const inFlightSpendMicroUsd = () => {
93
+ const own = liveSpendRef.get?.().costMicroUsd ?? 0;
94
+ const seededNested = resume?.seed.nestedStats.costMicroUsd;
95
+ const nestedDelta = nestedStats.costMicroUsd - (typeof seededNested === "number" && Number.isFinite(seededNested) ? seededNested : 0);
96
+ return (Number.isFinite(own) ? own : 0) + Math.max(0, Number.isFinite(nestedDelta) ? nestedDelta : 0);
97
+ };
98
+ const repairBundleForCheckpoint = (parkedSpendMicroUsd) => {
99
+ const carried = internals?.repairBundle !== undefined
100
+ ? structuredClone(internals.repairBundle)
101
+ : resume?.seed.repairBundle !== undefined
102
+ ? structuredClone(resume.seed.repairBundle)
103
+ : undefined;
104
+ if (carried === undefined)
105
+ return undefined;
106
+ if (parkedSpendMicroUsd === undefined || !Number.isFinite(parkedSpendMicroUsd) || parkedSpendMicroUsd <= 0)
107
+ return carried;
108
+ const prior = typeof carried.spentMicroUsd === "number" && Number.isFinite(carried.spentMicroUsd) ? Math.max(0, carried.spentMicroUsd) : 0;
109
+ carried.spentMicroUsd = prior + parkedSpendMicroUsd;
110
+ return carried;
111
+ };
112
+ const screeningParkDisclosedRef = { done: false };
113
+ const serializeCheckpointState = (workspaceHandle, parkedSpendMicroUsd) => ({
114
+ activeTools: [...activeTools],
115
+ outputRef: { value: outputRef.value, set: outputRef.set },
116
+ nestedStats: { ...nestedStats },
117
+ consolidationNotes: undefined,
118
+ readFileState: readFileStateForCheckpoint ? [...readFileStateForCheckpoint.entries()] : undefined,
119
+ readFace: faceCheckpointSection(),
120
+ reminderMark,
121
+ repairBundle: repairBundleForCheckpoint(parkedSpendMicroUsd),
122
+ workspaceHandle,
123
+ handsCwd: handsCwdRef?.current,
124
+ activeWorktree: worktreeSessionRef?.current ? { ...worktreeSessionRef.current } : undefined,
125
+ runningBackgroundTasks: (() => {
126
+ const live = defaultTaskRegistry
127
+ .list({ owner: hostTaskId, scope: taskScope, sessionId })
128
+ .filter((t) => t.status === "pending" || t.status === "running")
129
+ .map((t) => ({ id: t.task_id, ...(t.description !== undefined ? { description: t.description } : {}) }));
130
+ return live.length > 0 ? live : undefined;
131
+ })(),
132
+ pendingSteer: undefined,
133
+ pendingSteerQueue: undefined,
134
+ inheritedGate: (() => {
135
+ const requiresParentConstraint = (inheritedParentConstraints?.length ?? 0) > 0 || seedInheritedGate?.requiresParentConstraint === true;
136
+ const parentConstraintCount = (inheritedParentConstraints?.length ?? 0) > 0 ? inheritedParentConstraints.length : seedInheritedGate?.parentConstraintCount;
137
+ const constraintChain = (inheritedParentConstraints?.length ?? 0) > 0
138
+ ? inheritedParentConstraints.map((pc) => constraintChainEntryOfLayer(pc))
139
+ : seedInheritedGate?.constraintChain;
140
+ const constraintDigest = (inheritedParentConstraints?.length ?? 0) > 0
141
+ ? constraintChainDigest(constraintChain)
142
+ : seedInheritedGate?.constraintDigest;
143
+ const autoModeIntentCarried = autoModeIntent && (autoModeDecider === undefined || autoModeLatchHealthy(autoModeDecider));
144
+ return inheritedAncestorRules !== undefined ||
145
+ inheritedShellGate !== undefined ||
146
+ autoModeIntentCarried ||
147
+ inheritedAdmittedOrgScopes !== undefined ||
148
+ ownOrgVerdictRef.current !== undefined ||
149
+ orgGovernedProvenance ||
150
+ requiresParentConstraint
151
+ ? {
152
+ ...(inheritedAncestorRules !== undefined ? { ancestorRules: structuredClone(inheritedAncestorRules) } : {}),
153
+ ...(inheritedShellGate !== undefined ? { shellGate: inheritedShellGate } : {}),
154
+ ...(autoModeIntentCarried ? { autoModeRequested: true } : {}),
155
+ ...(inheritedAdmittedOrgScopes !== undefined ? { admittedOrgScopes: [...inheritedAdmittedOrgScopes] } : {}),
156
+ ...(ownOrgVerdictRef.current !== undefined
157
+ ? { ownAdmittedOrgScopes: [...ownOrgVerdictRef.current.scopes], ownAdmittedOrgWriteScope: ownOrgVerdictRef.current.writeScope }
158
+ : {}),
159
+ ...(orgGovernedProvenance ? { orgAdmissionGoverned: true } : {}),
160
+ requiresParentConstraint,
161
+ ...(requiresParentConstraint && parentConstraintCount !== undefined ? { parentConstraintCount } : {}),
162
+ ...(requiresParentConstraint && constraintChain !== undefined
163
+ ? { constraintChain: structuredClone(constraintChain), ...(constraintDigest !== undefined ? { constraintDigest } : {}) }
164
+ : {}),
165
+ }
166
+ : undefined;
167
+ })(),
168
+ announcedListings: serializeAnnouncedListings(announcedListingsRef),
169
+ gitAnnouncement: gitStatusRef.announced !== undefined ? { ...gitStatusRef.announced } : undefined,
170
+ delegationProvenance: internals?.delegationProvenance !== undefined ? { ...internals.delegationProvenance.ref.current } : undefined,
171
+ isDelegatedChild: hookIdentity.isDelegatedChild ? true : undefined,
172
+ placementRootSessionId: stampPlacementRootSessionId(placementRootResolved),
173
+ externalContentTarget: externalContentTargetActive ? true : undefined,
174
+ });
175
+ const compensatePausedVM = (remoteEnv, snapshotId) => compensateUnparkedPause(remoteEnv, snapshotId, {
176
+ boundMs: PARK_COMPENSATION_TIMEOUT_MS,
177
+ noteFailure: (note) => remoteEnvFailures.push(note),
178
+ disclose: (err) => {
179
+ try {
180
+ deps.onError?.(err, { phase: "config", sessionId });
181
+ }
182
+ catch {
183
+ }
184
+ },
185
+ });
186
+ const commitSuspendSaga = async (token, cp, remoteEnv, remoteHandle, cutSignal) => {
187
+ if (!checkpointStore)
188
+ return { tag: "absent" };
189
+ if (memoryEngineSession)
190
+ await memoryEngineSession.harvest("checkpoint");
191
+ if (cutSignal?.aborted) {
192
+ if (remoteEnv !== undefined && remoteHandle?.snapshotId !== undefined) {
193
+ const back = await compensatePausedVM(remoteEnv, remoteHandle.snapshotId);
194
+ if (!back.ok) {
195
+ abortController.abort();
196
+ void harness.abort();
197
+ return { tag: "compensation_failed", reason: back.reason };
198
+ }
199
+ }
200
+ return { tag: "cut" };
201
+ }
202
+ const announceCommittedScreeningPark = () => {
203
+ const committedCount = cp.state.inheritedGate?.parentConstraintCount;
204
+ if (cp.state.inheritedGate?.requiresParentConstraint === true &&
205
+ !screeningParkDisclosedRef.done &&
206
+ (inheritedParentConstraints ?? []).some((pc) => pc.preToolUse !== undefined)) {
207
+ screeningParkDisclosedRef.done = true;
208
+ try {
209
+ deps.onError?.(new Error(`durable park under an inherited PreToolUse SCREENING constraint: this checkpoint records ` +
210
+ `requiresParentConstraint with parentConstraintCount=${committedCount ?? "(unrecorded)"}, and the live ` +
211
+ `closures cannot be persisted. A resume on THIS Runner re-supplies them automatically; a resume on a fresh ` +
212
+ `Runner (restart / another replica) must hand back the whole chain via resumeStream(..., internals), ` +
213
+ `rebuilding the screening entry with createPreToolUseConstraintPolicy(hook, env) — otherwise the row stays ` +
214
+ `pending. If the face only observes, declare Hooks.preToolUseObservational and it stops entering the chain.`), { phase: "degraded", sessionId, classification: "screening-constraint-in-durable-chain" });
215
+ }
216
+ catch {
217
+ }
218
+ }
219
+ };
220
+ const confirmPutOutcome = async (putErr) => {
221
+ if (putErr?.code === "checkpoint.already_exists")
222
+ return "absent";
223
+ try {
224
+ const row = await checkpointStore.get(token);
225
+ if (row == null)
226
+ return "absent";
227
+ const sameCall = (a, b) => a.kind === b.kind && (a.kind !== "tool_approval" || b.kind !== "tool_approval" || a.toolCallId === b.toolCallId);
228
+ const isOurs = row.scope === cp.scope && row.sessionId === cp.sessionId && row.leafId === cp.leafId && sameCall(row.pendingAction, cp.pendingAction);
229
+ return isOurs ? "committed" : "absent";
230
+ }
231
+ catch (readErr) {
232
+ deps.onError?.(readErr, { phase: "config", sessionId });
233
+ return "unknown";
234
+ }
235
+ };
236
+ try {
237
+ await checkpointStore.put(token, cp);
238
+ announceCommittedScreeningPark();
239
+ return { tag: "committed" };
240
+ }
241
+ catch (putErr) {
242
+ deps.onError?.(putErr, { phase: "config", sessionId });
243
+ const confirmed = await confirmPutOutcome(putErr);
244
+ if (confirmed === "committed") {
245
+ try {
246
+ deps.onError?.(new Error(`durable approval checkpoint: the store's write reported a failure but the row EXISTS — the commit ` +
247
+ `landed and its acknowledgement was lost (a network backend can complete the INSERT and drop the ` +
248
+ `connection before replying). The run suspends on that row rather than continuing, which would leave ` +
249
+ `a redeemable pending checkpoint behind. This backend's acknowledgement path is lossy — the operator ` +
250
+ `face carries the store's own message.`), { phase: "degraded", sessionId, classification: "checkpoint-put-confirmation-lost" });
251
+ }
252
+ catch {
253
+ }
254
+ announceCommittedScreeningPark();
255
+ return { tag: "committed" };
256
+ }
257
+ if (confirmed === "unknown") {
258
+ const unknownReason = "the approval checkpoint's state cannot be established (the store rejected the write and then could not be read back; a committed-but-unacknowledged row may exist) — the run is stopped rather than continued past an approval whose durable record is unknown";
259
+ try {
260
+ deps.onError?.(new Error(`durable approval checkpoint: ${unknownReason}`), {
261
+ phase: "degraded",
262
+ sessionId,
263
+ classification: "checkpoint-put-outcome-unknown",
264
+ });
265
+ }
266
+ catch {
267
+ }
268
+ abortController.abort();
269
+ void harness.abort();
270
+ return { tag: "unknown", reason: unknownReason };
271
+ }
272
+ const reason = "the approval checkpoint could not be persisted (the store rejected the write; the deployment's error face carries the store's own message)";
273
+ if (remoteEnv !== undefined && remoteHandle?.snapshotId !== undefined) {
274
+ const back = await compensatePausedVM(remoteEnv, remoteHandle.snapshotId);
275
+ if (back.ok)
276
+ return { tag: "absent", reason };
277
+ abortController.abort();
278
+ void harness.abort();
279
+ return { tag: "compensation_failed", reason };
280
+ }
281
+ return { tag: "absent", reason };
282
+ }
283
+ };
284
+ const suspendLoopCapHit = (count, cap, detail) => {
285
+ if (cap === undefined)
286
+ return false;
287
+ if (count + 1 <= cap)
288
+ return false;
289
+ suspendLoopRef.hit = true;
290
+ abortController.abort();
291
+ void harness.abort();
292
+ try {
293
+ deps.onError?.(new Error(`suspend loop: task already suspended ${count} time(s) (max ${cap}); refusing to suspend again${detail}`), { phase: "config", sessionId });
294
+ }
295
+ catch {
296
+ }
297
+ return true;
298
+ };
299
+ const suspendableEnv = ownedEnv !== undefined && isSuspendable(ownedEnv) ? ownedEnv : undefined;
300
+ const parkOnlyRemoteEnv = suspendableEnv === undefined && ownedEnv !== undefined && isRemoteExecutionEnv(ownedEnv) && incompleteSuspendAdapter === undefined
301
+ ? ownedEnv
302
+ : undefined;
303
+ const parkOnlyHandle = (env) => {
304
+ const { snapshotId: _lineage, ...identity } = env.workspaceHandle();
305
+ return { ...identity, restoreMode: "park_only" };
306
+ };
307
+ return { saga: { inFlightSpendMicroUsd, serializeCheckpointState, compensatePausedVM, commitSuspendSaga, suspendLoopCapHit, suspendableEnv, parkOnlyRemoteEnv, parkOnlyHandle } };
308
+ }
@@ -1,15 +1,17 @@
1
1
  import type { SessionStore } from "../session.js";
2
- export { DEFAULT_IRREVERSIBLE_SCOPE, checkpointScopeOf } from "./checkpoint-scope.js";
2
+ export { runGuardChain, type GuardChainArgs, type GuardChainOutcome } from "./prepare-context-lane.js";
3
+ export { gatedCallIdOf, USAGE_WINDOW_REAP_MARGIN_MS } from "./park-commit.js";
4
+ export { batchContextAt } from "./prepare-park-ask.js";
5
+ export { compensateUnparkedPause } from "./prepare-suspend-saga.js";
6
+ export { DEFAULT_IRREVERSIBLE_SCOPE, checkpointScopeOf, placementValueOrAbsent } from "./checkpoint-scope.js";
3
7
  export { mcpManifestEntries } from "./prepare-wiring-manifest.js";
4
8
  export { __resetMaterializeEnvAnnouncements } from "./prepare-tool-disclosure-mount.js";
5
9
  export { fileHistoryFilesystemIdentity, resolveFileHistoryScope } from "./prepare-file-history.js";
6
- import { type OccurrenceIndex } from "../context-edit.js";
7
- import type { RemoteExecutionEnv, SnapshotId } from "../remote-env.js";
8
10
  import type { Runner } from "./runtask.js";
9
- import type { Prepared, PreparedMicroCompact, PrepareResume, RunInternals } from "./contracts.js";
11
+ import type { Prepared, PrepareResume, RunInternals } from "./contracts.js";
10
12
  export type { FileHistoryBoundarySeat, InheritedGate, Prepared, PreparedMicroCompact, PrepareResume, ResolvedWorkspace, RunInternals, UsageGovernance } from "./contracts.js";
11
- import type { AgentMessage, ExecutionEnv } from "../../internal/harness.js";
12
- import type { RemoteEnvFailureNote, RunnerDeps, TaskSpec } from "../types.js";
13
+ import type { ExecutionEnv } from "../../internal/harness.js";
14
+ import type { RunnerDeps, TaskSpec } from "../types.js";
13
15
  /** Test seam (mirrors `__resetMaterializeEnvAnnouncements`): never called by production code.
14
16
  * Re-arms BOTH arms (a WeakMap has no clear — it is re-minted). Deliberately UNLIKE the read-face
15
17
  * seam below (console latch only): tests here legitimately reuse ONE sink across prepares to pin
@@ -36,15 +38,6 @@ export { __resetReadFaceClampAnnouncement } from "./prepare-hands-readface.js";
36
38
  * checkpoint-cost calibration in one place.
37
39
  */
38
40
  export declare const ENV_LIFETIME_SUSPEND_MARGIN_MS = 60000;
39
- /**
40
- * design/164 件五 — how long AFTER a governance window frees a `usage_window` checkpoint stays reapable-free.
41
- * The retention TTL answers "was this abandoned?"; a usage-window suspend is not abandoned while the window
42
- * it waits on is still full, so its deadline is pushed to `retryAfterMs + this`. One hour gives a host's
43
- * scheduler a realistic chance to pick the resume up (a cron tick, a queue drain) before the row is
44
- * treated as garbage — small next to the 30-day retention it is compared against, and large next to any
45
- * polling interval a driver would sanely use.
46
- */
47
- export declare const USAGE_WINDOW_REAP_MARGIN_MS: number;
48
41
  /**
49
42
  * design/164 件四 — resolve the moment an env's lifetime EXPIRES (epoch ms), or `undefined` when the env
50
43
  * declares none / cannot be aged. Split out as a pure function so the anchor rules are testable and
@@ -71,71 +64,7 @@ export declare function resolveEnvLifetimeExpiry(env: ExecutionEnv, observedAt:
71
64
  export { resolveCheckpointStore } from "../checkpoint-store.js";
72
65
  export { isFableFamilyModelId, resolveAttachmentsConfig, resolveModelPromptTraits, resolveTaskLimits } from "./prepare-config-doors.js";
73
66
  export { rebaseWorkspacePath, rebaseWorkspacePathAcross } from "./workspace-path.js";
74
- /** See {@link runGuardChain}. */
75
- export interface GuardChainArgs {
76
- /** The post-frontier view the chain starts from. */
77
- edited: AgentMessage[];
78
- /** The pre-cap counterpart view (arm A's clearSource — RB-212 durable composition seat). */
79
- replayed: AgentMessage[];
80
- index: OccurrenceIndex;
81
- microCompact: PreparedMicroCompact;
82
- guardAt: number;
83
- charsPerToken: number;
84
- offloadStore: import("../tool-result-store.js").ToolResultStore | undefined;
85
- sessionId: string;
86
- taskId: string;
87
- deps: RunnerDeps;
88
- trimPressureRef: {
89
- droppedMessages: boolean;
90
- };
91
- recheck: boolean | undefined;
92
- signal: AbortSignal | undefined;
93
- /** The r7 per-request observation buffer — the chain DROPS it on its early returns (a discarded
94
- * provisional projection must not narrate itself). */
95
- pendingProjectionObservations: Array<() => void>;
96
- }
97
- export type GuardChainOutcome = {
98
- earlyReturn: {
99
- messages: AgentMessage[];
100
- adoptSessionRebuild?: boolean;
101
- };
102
- } | {
103
- working: AgentMessage[];
104
- trimmed: AgentMessage[];
105
- trimDroppedMessages: boolean;
106
- };
107
- /**
108
- * design/374 slice 3 — the GUARD CHAIN over one request build (D-7 case-ii transfer table),
109
- * module-level per the design/238 body-span bank. design/123 D3: the chain reads the anchored
110
- * coordinate re-estimated on the EDITED array (pre-anchor clears don't lower it — deliberately;
111
- * trimToBudget doc). The opt-out machine = the pre-374 backstop order byte-identical
112
- * (trim as the ordinary second line); otherwise arm A (blocking machine run, only when the
113
- * frontier pass is off) → arm B (in-turn forced compaction behind the adopt seam) → arm C (trim,
114
- * the disaster-only last resort and this chain's sole `context.trim` emitter). Returns either the
115
- * post-chain view for the pipeline tail, or an EARLY hook result the context handler must return
116
- * verbatim (arm-B adoption / the r8 dead-turn stand-down).
117
- */
118
- export declare function runGuardChain(args: GuardChainArgs): Promise<GuardChainOutcome>;
119
- /**
120
- * WHICH tool call a committed durable park is holding this run — `undefined` when nothing parked, or
121
- * when the park that did commit holds no call (a resource slice, a plan review).
122
- *
123
- * SINGLE derivation on purpose. Two consumers need this answer: the abort-classification seam, which
124
- * stamps it into the `details` of the results the loop mints for the contaminated siblings, and the
125
- * `tool_end` projection, which puts it on the wire. Reading it from one function keeps the two from
126
- * disagreeing about WHICH HOLDER WINS or about what a holder with no call means. They are not otherwise
127
- * interchangeable: the frame face applies strictly narrower conditions on top of this answer (see
128
- * `tool_end.gatedCallId`), so a frame may omit an id this function returns — never the reverse.
129
- *
130
- * The frame side must not read the id back out of a tool RESULT even though the marker is there: a
131
- * result's `details` is written by the tool (and replaceable by post-tool hooks), so lifting a
132
- * cross-call attribution from it would let any failing tool name an arbitrary call and put a phantom
133
- * approval wait on someone else's frame. Same rule, same reason, as `settledBy`.
134
- *
135
- * The two holders are never both set (the commit-side discriminant writes exactly one); they are read
136
- * here in assemble-result's slot order so the winner is the same one the terminal status is built from.
137
- */
138
- export declare function gatedCallIdOf(p: Pick<Prepared, "suspendRef" | "reviewRef">): string | undefined;
67
+ /** Everything the run loop needs, built once by {@link prepareTask} (task setup, isolated from the loop). */
139
68
  /**
140
69
  * RB-330 + 5.38 r2 件2 — the SINGLE effective-delegation derivation for a leg, minted once per prepare
141
70
  * and read by EVERY consumer face; two facets, one source:
@@ -165,62 +94,6 @@ export declare function effectiveDelegationFacts(internals: Pick<RunInternals, "
165
94
  isDelegatedChild: boolean;
166
95
  isNonForkChild: boolean;
167
96
  };
168
- /**
169
- * From the resumed/active transcript, the batch position of `currentId` (design/45 §4.ter): the tool-call
170
- * ids of the assistant message that issued it (the batch), and the subset already resolved (executed
171
- * before the suspend — #1..k-1). ID-based, not positional (council Question #1): immune to reordering.
172
- */
173
- export declare function batchContextAt(messages: AgentMessage[], currentId: string): {
174
- batchToolCallIds: string[];
175
- completedCallIds: string[];
176
- };
177
- /**
178
- * design/384 slice 2 — the ONE compensation for a paused-but-unparked VM, shared by the fence's
179
- * post-pause checkpoints (③ in the park closure, ④ in the saga) and the saga's put-failure absent
180
- * arm (previously inline there: same two hops, one implementation now, so the three sites cannot
181
- * drift). Restores the workspace (bounded transient retry) then re-establishes consistency
182
- * (`postResumeInit`), both hops under one INDEPENDENT `AbortSignal.timeout(io.boundMs)` —
183
- * deliberately NOT the run/cut signal: the remote contract answers an already-aborted signal
184
- * `{ok:false,"aborted"}`, so gating the restore on the very signal whose firing caused the
185
- * compensation made it die instantly and strand the paused VM on exactly the run-abort arm that
186
- * needs it most. The adapter signal is best-effort (a deaf adapter ignores it), so the caller's
187
- * await is ALSO raced against the same bound — bounded decision, three outcomes:
188
- * · settled ok ⇒ the VM is running again ({ok:true});
189
- * · settled not-ok / threw ⇒ recorded + disclosed, {ok:false} — the caller takes its fatal
190
- * fail-closed arm (abort the run; never continue on a paused VM);
191
- * · bound fires with the adapter still in flight ⇒ {ok:false} NOW, and the in-flight call
192
- * continues DETACHED + swallow-guarded with the late-settlement split:
193
- * – late SUCCESS: a running VM now exists with no run and no committed row to own it — the
194
- * detached continuation compensates the compensation with `destroy()` (the adapter's own
195
- * best-effort contract, swallow-guarded, disclosed);
196
- * – late FAILURE: disclosed; the VM is most likely still paused — provider-side TTL/GC
197
- * territory, and the disclosure is the end of this engine's obligation (a deaf adapter's
198
- * stranded VM is that adapter's own defect surface).
199
- * Decide-then-disclose throughout: `io.disclose`/`io.noteFailure` must be swallow-guarded by the
200
- * caller's binding, and nothing they do can change the returned verdict. Never throws. Exported for
201
- * direct unit pinning (the bounded/deaf/late arms need a small bound; production binds the
202
- * `PARK_COMPENSATION_TIMEOUT_MS` constant at the one call-site closure).
203
- */
204
- export declare function compensateUnparkedPause(remoteEnv: RemoteExecutionEnv, snapshotId: SnapshotId, io: {
205
- boundMs: number;
206
- noteFailure: (note: RemoteEnvFailureNote) => void;
207
- disclose: (err: unknown) => void;
208
- }): Promise<{
209
- ok: true;
210
- } | {
211
- ok: false;
212
- reason: string;
213
- }>;
214
- /**
215
- * rescan C5 — the ONE spelling of the placement fields' empty-string discipline: `""` is absence
216
- * wearing clothes (the resume entry's principal-rung posture), and every placement read that must
217
- * treat it so — the resume rung's two sides (runtask), the restore fold's seed and the suspend
218
- * stamp — goes through THIS helper, so three sites cannot drift into three readings. Deliberately
219
- * NOT applied to the live `internals.placementRoot`/`rootSessionId` reads of the RESOLUTION fold:
220
- * an empty supplied claim there is an assembly error the execution-env phase's `mintPlacementRootSessionId` refuses
221
- * loudly on the factory path, and normalizing it away would silently repair what should be loud.
222
- */
223
- export declare function placementValueOrAbsent(value: string | undefined): string | undefined;
224
97
  /**
225
98
  * Build everything a task run needs (council design/34 ②: a free function with EXPLICIT deps, not a
226
99
  * Runner method — testable and decoupled). Resolves the model/role/thinking, acquires + reconciles the