You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by zh...@apache.org on 2026/09/24 13:04:38 UTC

(maka) 01/01: feat(runtime): project unknown outcomes on explicit turns

This is an automated email from the ASF dual-hosted git repository.

me2seeks pushed a commit to branch feat/ts-manual-turn-after-unknown
in repository https://gitbox.apache.org/repos/asf/maka.git

commit b2f88b60d985b3aaf028d167c6f489c54ef27a05
Author: me2seeks <me...@gmail.com>
AuthorDate: Thu Sep 24 20:24:08 2026 +0800

    feat(runtime): project unknown outcomes on explicit turns
---
 docs/architecture/runtime-resume-architecture.md   |  34 ++-
 .../runtime-resume-architecture.zh-CN.md           |  23 +-
 .../cli/src/__tests__/activation-command.test.ts   |   5 +-
 packages/cli/src/__tests__/pi-tui-runner.test.ts   |  29 +++
 .../src/__tests__/runtime-host-run-command.test.ts |  72 ++++++
 .../__tests__/runtime-host-session-driver.test.ts  |  51 ++++
 packages/cli/src/activation-command.ts             |   6 +-
 packages/cli/src/runtime-host-run-command.ts       |  28 ++-
 packages/cli/src/runtime-host-session-driver.ts    |  24 +-
 packages/core/src/__tests__/runtime-event.test.ts  |   1 +
 packages/core/src/backend-types.ts                 |   7 +
 packages/core/src/turn-origin.ts                   |  18 ++
 .../runtime/src/__tests__/ai-sdk-backend.test.ts   | 277 ++++++++++++++++++++-
 .../src/__tests__/recovery-resolver.test.ts        | 241 +++---------------
 .../runtime/src/__tests__/session-manager.test.ts  |  87 +++----
 packages/runtime/src/ai-sdk-turn.ts                | 131 +++++++---
 packages/runtime/src/model-history.ts              | 168 +++++++++++++
 packages/runtime/src/recovery-resolver.ts          | 103 --------
 packages/runtime/src/runtime-kernel.ts             |  16 ++
 packages/runtime/src/session-manager.ts            | 104 +++-----
 20 files changed, 935 insertions(+), 490 deletions(-)

diff --git a/docs/architecture/runtime-resume-architecture.md b/docs/architecture/runtime-resume-architecture.md
index bd8ed98415..678a93efe9 100644
--- a/docs/architecture/runtime-resume-architecture.md
+++ b/docs/architecture/runtime-resume-architecture.md
@@ -493,6 +493,31 @@ CLI/TUI `/resume` uses the same `SessionManager` plan/execute seam. Startup
 recovery can reconstruct an already admitted continuation through that seam,
 but it does not automatically select an ordinary failed or cancelled Run.
 
+### A missing tool result is projected only for a fresh user turn
+
+An uncertain tool side effect is not a resumable boundary. If recovery finds a
+durable T1 dispatch without a committed T2 result, it seals the old invocation
+as `outcome_unknown`; it does not invent a durable tool response and does not
+retry the tool. The old Run remains stopped.
+
+When the user later sends a new explicit message, that message starts a new
+Turn. Only provider requests in that fresh Turn receive a temporary history
+projection: the old tool call is paired with an `outcome_unknown` response and
+a system notice, then the new user message follows. The temporary response and
+notice are not written to the RuntimeEvent ledger or transcript. For example, after
+`Bash("touch marker.txt")` was dispatched but its result was not committed, a
+new request such as “check whether `marker.txt` exists” lets the model inspect
+the current state before deciding what to do; Maka does not decide whether the
+write happened and does not retry it automatically.
+
+This projection must not lose the T1 call. If an existing checkpoint or the
+current context budget would hide it, Runtime falls back to the full effective
+history for that request. This is a deliberate fail-closed trade-off: a very
+large unresolved history may exceed the provider's context limit, in which case
+the provider's real error is surfaced rather than dropping the uncertainty or
+claiming success. Compaction that preserves this uncertainty while reducing
+the rest of that history is not implemented here.
+
 ### Current parked-reason boundary
 
 Runtime Host projects Runtime planner rejection reasons into the closed
@@ -833,14 +858,19 @@ Start with production-shaped red tests, then land core contract, storage constra
 
 | Setting | Purpose | Rollback meaning |
 |---|---|---|
-| unset | Enable explicit Desktop and CLI/TUI resume; keep model-driven WorkHub resume disabled | Default product behavior |
-| `MAKA_RUNTIME_SAFE_BOUNDARY_RESUME=1` | Also enable model-driven WorkHub resume | Preserves the previous full opt-in behavior |
+| unset | Enable explicit Desktop and CLI/TUI resume; keep automated WorkHub and `maka activate` resume disabled | Default product behavior |
+| `MAKA_RUNTIME_SAFE_BOUNDARY_RESUME=1` | Also enable automated WorkHub and `maka activate` resume | Preserves the previous full opt-in behavior |
 | `MAKA_RUNTIME_SAFE_BOUNDARY_RESUME=0` | Disable explicit and model-driven resume planning | May park reconstruction; does not delete durable facts |
 
 Unknown non-empty values fail closed like `0`. Every enabled entry point still
 uses the same authoritative planner; the policy only controls whether a new
 resume attempt may reach it.
 
+With automated `maka activate` resume enabled, a ready continuation is used
+instead of submitting that activation's new stimulus. If no continuation is
+ready, the stimulus is submitted normally. Callers that need every activation
+stimulus processed should not opt into this legacy resume behavior.
+
 RuntimeEvent migration is unconditional on the first write. Downgrading to a
 reader that does not understand the new schema requires explicit, verified
 export. Migration failure must preserve legacy JSONL. A newer database schema
diff --git a/docs/architecture/runtime-resume-architecture.zh-CN.md b/docs/architecture/runtime-resume-architecture.zh-CN.md
index 6044cf3bbf..c9df002fab 100644
--- a/docs/architecture/runtime-resume-architecture.zh-CN.md
+++ b/docs/architecture/runtime-resume-architecture.zh-CN.md
@@ -500,6 +500,23 @@ sequenceDiagram
 CLI/TUI 的 `/resume` 走同一个 `SessionManager` plan/execute seam。启动恢复也会通过这条
 seam 重建已经 admission 的 continuation,但不会自动选择普通的 failed 或 cancelled Run。
 
+### 工具已派发但没有已提交结果:只在新用户 Turn 中临时投影
+
+工具副作用结果未知时,旧 Run 不能安全续跑。如果恢复时发现 T1 派发事实已经写入,但没有已提交的
+T2 结果,Runtime 会把旧 invocation 封存为 `outcome_unknown`;它不会伪造一条 durable tool response,
+也不会重试该工具。旧 Run 仍然是停止状态。
+
+之后用户显式发送新消息时,Runtime 会开启一个新的 Turn。只有这个新 Turn 中发给模型的请求会看到临时的
+历史投影:旧工具调用后面暂时附上一条 `outcome_unknown` 响应和 system 提醒,再接上新用户消息。这条临时响应
+和提醒不会写入 RuntimeEvent ledger 或 transcript。例如,`Bash("touch marker.txt")` 已派发、但结果来不及提交;
+用户新消息可以说“检查 `marker.txt` 是否存在”。模型可以先检查当前状态,再决定下一步;Maka 不会替模型
+判断文件是否写入,也不会自动重试命令。
+
+这个投影不能丢掉 T1 调用。如果已有 checkpoint 或当前 context budget 会把它隐藏,Runtime 会为这次请求
+退回完整的 effective history。这是有意的 fail-closed 取舍:未解决的历史很大时,可能超过 provider 的上下文
+限制;此时返回 provider 的真实错误,而不是删掉不确定事实或谎称工具成功。当前实现还不能在压缩其余历史的同时
+保留这份不确定性。
+
 ### 当前的 parked 原因边界
 
 Runtime Host 负责把 Runtime planner 的 rejection reasons 投影成封闭的
@@ -864,13 +881,15 @@ RuntimeEvent 迁移不再由开关控制;首次写入必然迁移。当前恢
 
 | 设置 | 作用 | 回滚含义 |
 |---|---|---|
-| 未设置 | 开启 Desktop 与 CLI/TUI 的显式 resume;保持 WorkHub 模型驱动 resume 关闭 | 默认产品行为 |
-| `MAKA_RUNTIME_SAFE_BOUNDARY_RESUME=1` | 额外开启 WorkHub 模型驱动 resume | 保留此前完整 opt-in 行为 |
+| 未设置 | 开启 Desktop 与 CLI/TUI 的显式 resume;保持 WorkHub 和 `maka activate` 自动 resume 关闭 | 默认产品行为 |
+| `MAKA_RUNTIME_SAFE_BOUNDARY_RESUME=1` | 额外开启 WorkHub 和 `maka activate` 自动 resume | 保留此前完整 opt-in 行为 |
 | `MAKA_RUNTIME_SAFE_BOUNDARY_RESUME=0` | 关闭显式和模型驱动 resume planning | 可能 park reconstruction,但不会删除 durable facts |
 
 未知的非空值与 `0` 一样 fail closed。所有已开启的入口仍使用同一个权威 planner;策略只决定
 新的 resume 尝试能否到达 planner。
 
+启用 `maka activate` 自动 resume 后,若有可续跑的 continuation,会续跑旧 Turn,而不提交本次 activation 的新 stimulus;若没有可续跑项,则正常提交 stimulus。需要确保每次 activation 的新内容都被处理时,不应启用这项旧式自动续跑行为。
+
 真正降级到不理解新 schema 的旧版本前,必须显式 export 并验证。Migration 失败不能删除 legacy JSONL;数据库版本比当前程序新时必须 fail closed。
 
 未来 checkpoint 和 recovery capability 也应遵守同一原则:一旦在 T1 或 accepted boundary 前选定 durable mode,不能在执行中静默 fallback 到较弱协议。降级必须产生明确、可审计的 mode mismatch 或 park reason。
diff --git a/packages/cli/src/__tests__/activation-command.test.ts b/packages/cli/src/__tests__/activation-command.test.ts
index 7de4efd1ab..97908e98d7 100644
--- a/packages/cli/src/__tests__/activation-command.test.ts
+++ b/packages/cli/src/__tests__/activation-command.test.ts
@@ -553,9 +553,10 @@ describe('maka activate JSONL protocol', () => {
     }
   });
 
-  test('keeps a fresh activation stimulus instead of implicitly resuming an existing session', async () => {
+  test('preserves a new activation stimulus and origin instead of implicitly resuming an existing session', async () => {
     let created = false;
     let resumed = false;
+    let sentOrigin: unknown;
     let sentText: string | undefined;
     let requestedConnection: string | undefined;
     const lines: string[] = [];
@@ -583,6 +584,7 @@ describe('maka activate JSONL protocol', () => {
             resumed = true;
           },
           sendMessage: async function* (_runtime, _sessionId, input) {
+            sentOrigin = input.origin;
             sentText = input.text;
             yield* completedEvents();
           },
@@ -594,6 +596,7 @@ describe('maka activate JSONL protocol', () => {
     assert.equal(result, 0);
     assert.equal(created, false);
     assert.equal(resumed, false);
+    assert.deepEqual(sentOrigin, { kind: 'cloud_activation', activationId: 'activation-1' });
     assert.equal(sentText, 'Inspect the workspace');
     assert.equal(requestedConnection, 'local');
     assert.equal(JSON.parse(lines.at(-1)!).makaSessionId, 'maka-session-1');
diff --git a/packages/cli/src/__tests__/pi-tui-runner.test.ts b/packages/cli/src/__tests__/pi-tui-runner.test.ts
index a0030a58c5..c6c553e3f0 100644
--- a/packages/cli/src/__tests__/pi-tui-runner.test.ts
+++ b/packages/cli/src/__tests__/pi-tui-runner.test.ts
@@ -9095,6 +9095,35 @@ Slug openai-work<cursor>
       await run;
     });
 
+    test('/resume starts the latest safe-boundary continuation for the selected session', async () => {
+      const terminal = new FakeTerminal();
+      const driver = new SlashCommandDriver();
+      const run = runMakaPiTui({
+        title: 'Maka',
+        driver,
+        cwd: '/repo',
+        model: 'm',
+        connectionSlug: 'c',
+        permissionMode: 'bypass',
+        terminal,
+      });
+
+      terminal.input('/session');
+      terminal.input('\r');
+      await waitFor(() => plainTerminalOutput(terminal.output()).includes('Resume Session'));
+      terminal.input('\r');
+      await waitFor(() => driver.sessionIds.length === 1);
+
+      terminal.input('/resume');
+      terminal.input('\r');
+      await waitFor(() => plainTerminalOutput(terminal.output()).includes('resumed safely'));
+
+      assert.equal(driver.resumeCalls, 1);
+      terminal.input('/exit');
+      terminal.input('\r');
+      await run;
+    });
+
     test('/resume with no interrupted run explains there is nothing to resume', async () => {
       const terminal = new FakeTerminal();
       const driver = new SlashCommandDriver();
diff --git a/packages/cli/src/__tests__/runtime-host-run-command.test.ts b/packages/cli/src/__tests__/runtime-host-run-command.test.ts
index 7e69be8465..5fd9180acb 100644
--- a/packages/cli/src/__tests__/runtime-host-run-command.test.ts
+++ b/packages/cli/src/__tests__/runtime-host-run-command.test.ts
@@ -622,6 +622,56 @@ describe('Runtime Host maka run adapter', () => {
     assert.equal(durable.failure?.class, 'aborted');
   });
 
+  test('observes a resumed Host Turn through the same outcome path as a fresh Turn', async () => {
+    const observed: MakaRunOutcome[] = [];
+    const fixture = runFixture({ observed, resumeReady: true });
+    const session = await fixture.context.runtime.createSession({
+      cwd: '/workspace',
+      llmConnectionSlug: 'openai-main',
+      model: 'gpt-5',
+      permissionMode: 'ask',
+    });
+
+    assert.ok(fixture.context.runtime.resumeLatest);
+    const resumed = await fixture.context.runtime.resumeLatest(session.id);
+    assert.ok(resumed);
+    await collect(resumed);
+
+    assert.equal(observed.length, 1);
+    assert.equal(observed[0]?.outcomeId, 'run-resumed');
+    assert.equal(observed[0]?.status, 'completed');
+    assert.equal(observed[0]?.finalOutput, 'Resumed answer');
+  });
+
+  test('stops a resumed Host Turn if cancellation races its start', async () => {
+    const resumeStarted = deferred<void>();
+    const resumeGate = deferred<void>();
+    const fixture = runFixture({
+      resumeReady: true,
+      resumeGate: resumeGate.promise,
+      onResumeStarted: () => resumeStarted.resolve(),
+    });
+    const session = await fixture.context.runtime.createSession({
+      cwd: '/workspace',
+      llmConnectionSlug: 'openai-main',
+      model: 'gpt-5',
+      permissionMode: 'ask',
+    });
+    assert.ok(fixture.context.runtime.resumeLatest);
+    const resumed = await fixture.context.runtime.resumeLatest(session.id);
+    assert.ok(resumed);
+    const draining = collect(resumed);
+    await resumeStarted.promise;
+
+    await fixture.context.runtime.stopSession(session.id);
+    resumeGate.resolve();
+    await draining;
+
+    assert.deepEqual(fixture.exactTurnStops, [
+      { sessionId: 'session-created', turnId: 'turn-resumed', runId: 'run-resumed' },
+    ]);
+  });
+
   test('classifies live and durable step-cap failures equally', async () => {
     const live = await observeFixtureOutcome({
       turnEvents: completionEvents('turn-1', 'step_limit'),
@@ -1012,6 +1062,9 @@ function runFixture(input: {
   prepareGate?: Promise<void>;
   onPrepareStarted?: () => void;
   turnEvents?: AsyncIterable<SessionEvent>;
+  resumeReady?: boolean;
+  resumeGate?: Promise<void>;
+  onResumeStarted?: () => void;
   pendingInteractions?: InteractionPendingSnapshot[];
   pendingAfterTurnStarts?: boolean;
   graphProjectionRace?: boolean;
@@ -1130,6 +1183,16 @@ function runFixture(input: {
           : events,
       };
     },
+    resumeLatestTurn: async () => {
+      input.onResumeStarted?.();
+      await input.resumeGate;
+      return {
+        sessionId: switches.at(-1) ?? 'session-created',
+        turnId: 'turn-resumed',
+        runId: 'run-resumed',
+        events: eventsFor('turn-resumed', 'Resumed answer'),
+      };
+    },
     respondToSandboxBoundary: async (response: { requestId: string; decision: 'deny' }) => {
       sandboxResponses.push(response);
     },
@@ -1153,6 +1216,15 @@ function runFixture(input: {
   const connection = {
     hostEpoch: 'host-1',
     request: async (operation: string, requestInput: Record<string, unknown>) => {
+      if (operation === 'turn.resume.query' && input.resumeReady) {
+        return {
+          sessionId: requestInput.sessionId,
+          disposition: 'ready',
+          sourceRunId: 'run-source',
+          sourceTurnId: 'turn-source',
+          sourceRuntimeEventHighWater: 3,
+        };
+      }
       if (operation === 'session.execution_boundary.query') {
         return { kind: 'managed', access: 'writable', revision: 0 };
       }
diff --git a/packages/cli/src/__tests__/runtime-host-session-driver.test.ts b/packages/cli/src/__tests__/runtime-host-session-driver.test.ts
index 937e4b66be..a5e9f9d095 100644
--- a/packages/cli/src/__tests__/runtime-host-session-driver.test.ts
+++ b/packages/cli/src/__tests__/runtime-host-session-driver.test.ts
@@ -2493,6 +2493,45 @@ describe('Runtime Host Maka Session driver', () => {
     assert.equal((await nextEvent(turn.events)).text, 'Recovered');
   });
 
+  test('returns the admitted Turn identity when starting a safe-boundary resume', async () => {
+    const subscription = new FakeSubscription(
+      continuitySnapshot({ rootTurn: null }),
+      Promise.resolve([]),
+    );
+    const connection = new FakeConnection([subscription]);
+    const driver = createRuntimeHostMakaSessionDriver({
+      connection: connection.value,
+      cwd: '/tmp',
+      llmConnectionId: 'connection-1',
+      llmConnectionSlug: 'openai-main',
+      model: 'gpt-5',
+      newId: () => 'turn-resume',
+    });
+    await driver.switchSession('session-1');
+
+    const turn = await driver.resumeLatestTurn({
+      sessionId: 'session-1',
+      disposition: 'ready',
+      sourceRunId: 'run-source',
+      sourceTurnId: 'turn-source',
+      sourceRuntimeEventHighWater: 3,
+    });
+
+    assert.deepEqual(
+      { sessionId: turn.sessionId, turnId: turn.turnId, runId: turn.runId },
+      { sessionId: 'session-1', turnId: 'turn-resume', runId: 'run-resumed' },
+    );
+    assert.deepEqual(connection.requests.at(-1), {
+      operation: 'turn.resume.start',
+      input: {
+        sessionId: 'session-1',
+        turnId: 'turn-resume',
+        sourceRunId: 'run-source',
+        sourceRuntimeEventHighWater: 3,
+      },
+    });
+  });
+
   test('starts explicit Skills through the Host command and preserves its typed feedback', async () => {
     const subscription = new FakeSubscription(
       continuitySnapshot({ rootTurn: null }),
@@ -2988,6 +3027,18 @@ class FakeConnection {
     if (operation === 'turn.stop') {
       return {} as OperationOutput<K>;
     }
+    if (operation === 'turn.resume.start') {
+      const resumeInput = input as OperationInput<'turn.resume.start'>;
+      return {
+        kind: 'started',
+        turn: {
+          sessionId: resumeInput.sessionId,
+          turnId: resumeInput.turnId,
+          runId: 'run-resumed',
+          status: 'running',
+        },
+      } as OperationOutput<K>;
+    }
     const turnInput = input as {
       sessionId?: string;
       turnId?: string;
diff --git a/packages/cli/src/activation-command.ts b/packages/cli/src/activation-command.ts
index 689f9ad2e5..97fc28091d 100644
--- a/packages/cli/src/activation-command.ts
+++ b/packages/cli/src/activation-command.ts
@@ -511,7 +511,11 @@ export async function runMakaActivationCli(
       const stream = await activationStream(
         context.runtime,
         session.id,
-        { turnId: deps.newId(), text },
+        {
+          turnId: deps.newId(),
+          text,
+          origin: { kind: 'cloud_activation', activationId: request.activationId },
+        },
         existing !== undefined && deps.automatedResumeEnabled(),
       );
       const drain = (async () => {
diff --git a/packages/cli/src/runtime-host-run-command.ts b/packages/cli/src/runtime-host-run-command.ts
index 7277411455..412120fd88 100644
--- a/packages/cli/src/runtime-host-run-command.ts
+++ b/packages/cli/src/runtime-host-run-command.ts
@@ -32,7 +32,11 @@ import {
   type RuntimeHostProfile,
 } from '@maka/runtime-host/client';
 import { runtimeHostProfileUsesHostWorkspace } from '@maka/runtime-host/profile-kind';
-import type { InteractionPendingSnapshot, SessionCatalogItem } from '@maka/runtime-host/protocol';
+import type {
+  InteractionPendingSnapshot,
+  SessionCatalogItem,
+  TurnResumePlan,
+} from '@maka/runtime-host/protocol';
 import {
   runMakaTextCliCore,
   type MakaRunContext,
@@ -348,7 +352,27 @@ class RuntimeHostRunRuntime implements MakaRunRuntime {
   async resumeLatest(sessionId: string): Promise<AsyncIterable<SessionEvent> | null> {
     await this.#attach(sessionId);
     const plan = await this.#connection.request('turn.resume.query', { sessionId });
-    return plan.disposition === 'ready' ? this.#driver.resumeLatest() : null;
+    return plan.disposition === 'ready' ? this.#resumeAndObserve(plan) : null;
+  }
+
+  async *#resumeAndObserve(
+    plan: Extract<TurnResumePlan, { disposition: 'ready' }>,
+  ): AsyncIterable<SessionEvent> {
+    const turn = await this.#driver.resumeLatestTurn(plan);
+    if (!turn.runId) throw new Error('Runtime Host did not return a Run identity');
+    const activeTurn: ActiveRuntimeHostTurn = {
+      sessionId: turn.sessionId,
+      turnId: turn.turnId,
+      runId: turn.runId,
+      outcome: new TurnOutcomeClassifier(turn.runId),
+    };
+    this.#activeTurn = activeTurn;
+    try {
+      if (this.#stopRequested) await this.#stopTurn(activeTurn);
+      yield* this.#observeTurn(turn, activeTurn);
+    } finally {
+      if (this.#activeTurn === activeTurn) this.#activeTurn = undefined;
+    }
   }
 
   async stopSession(sessionId: string): Promise<void> {
diff --git a/packages/cli/src/runtime-host-session-driver.ts b/packages/cli/src/runtime-host-session-driver.ts
index 0a53e498fb..c480c3a28b 100644
--- a/packages/cli/src/runtime-host-session-driver.ts
+++ b/packages/cli/src/runtime-host-session-driver.ts
@@ -76,6 +76,7 @@ import {
   type GoalProjection,
   type SessionContinuitySnapshot,
   type SessionDomainChangedFrame,
+  type TurnResumePlan,
   type TurnResumeParkReason,
 } from '@maka/runtime-host/protocol';
 import { RuntimeHostSessionChannel } from './runtime-host-session-channel.js';
@@ -173,6 +174,9 @@ export interface RuntimeHostMakaSessionDriver extends MakaSessionDriver {
   readMessages(): Promise<StoredMessage[]>;
   getWorkspaceTarget(): WorkspaceTarget | undefined;
   resumeLatest(): AsyncIterable<SessionEvent>;
+  resumeLatestTurn(
+    plan: Extract<TurnResumePlan, { disposition: 'ready' }>,
+  ): Promise<MakaPreparedSessionTurn>;
   subscribePendingInteractions(listener: (pending: InteractionPendingSnapshot) => void): () => void;
   subscribeStartedTurns(listener: (turn: MakaAttachedSessionTurn) => void): () => void;
   subscribeResolvedInteractions(
@@ -496,6 +500,17 @@ class RuntimeHostMakaSessionDriverImpl implements RuntimeHostMakaSessionDriver {
     if (plan.disposition !== 'ready') {
       throw new SafeBoundaryResumeParkedError(plan.reason);
     }
+    const turn = await this.resumeLatestTurn(plan);
+    yield* turn.events;
+  }
+
+  async resumeLatestTurn(
+    plan: Extract<TurnResumePlan, { disposition: 'ready' }>,
+  ): Promise<MakaPreparedSessionTurn> {
+    const sessionId = this.#requireSession('resume');
+    if (plan.sessionId !== sessionId) {
+      throw new Error('Runtime Host resume plan changed Session identity');
+    }
     const channel = await this.#ensureChannel(sessionId);
     const turnId = this.#newId();
     this.#claimedTurnIds.add(turnId);
@@ -508,13 +523,18 @@ class RuntimeHostMakaSessionDriverImpl implements RuntimeHostMakaSessionDriver {
         sourceRuntimeEventHighWater: plan.sourceRuntimeEventHighWater,
       });
       if (result.kind !== 'started') {
-        channel.failTurn(turnId, new SafeBoundaryResumeParkedError(result.plan.reason));
+        throw new SafeBoundaryResumeParkedError(result.plan.reason);
       }
+      return {
+        sessionId: result.turn.sessionId,
+        turnId: result.turn.turnId,
+        runId: result.turn.runId,
+        events,
+      };
     } catch (error) {
       channel.failTurn(turnId, error);
       throw error;
     }
-    yield* events;
   }
 
   submitMessage(
diff --git a/packages/core/src/__tests__/runtime-event.test.ts b/packages/core/src/__tests__/runtime-event.test.ts
index a0d6b8b023..48c8e6c9f8 100644
--- a/packages/core/src/__tests__/runtime-event.test.ts
+++ b/packages/core/src/__tests__/runtime-event.test.ts
@@ -149,6 +149,7 @@ test('decodes a released provider dropping note that nothing writes any more', (
 test('shares one decoder across all TurnOrigin variants', () => {
   const origins = [
     { kind: 'scheduled_task', scheduledTaskId: 'task-1' },
+    { kind: 'cloud_activation', activationId: 'activation-1' },
     { kind: 'goal', goalId: 'goal-1' },
     { kind: 'agent_graph', graphId: 'graph-1', wakeId: 'wake-1', attemptId: 'attempt-1' },
   ] as const;
diff --git a/packages/core/src/backend-types.ts b/packages/core/src/backend-types.ts
index ae933a1a41..1c757cb530 100644
--- a/packages/core/src/backend-types.ts
+++ b/packages/core/src/backend-types.ts
@@ -92,6 +92,13 @@ export interface BackendSendInput {
    * Optional prior RuntimeEvent ledger for model-history projection.
    */
   runtimeContext?: RuntimeEvent[];
+  /**
+   * Trusted marker for an explicit client-authored fresh turn. When prior
+   * history contains a sealed dispatched tool with no result, the backend may
+   * project that uncertainty into this request only. Continuations and hosted
+   * automation must never set this.
+   */
+  allowPriorUnknownToolOutcomes?: boolean;
   /**
    * The invocations `runtimeContext` came from, used only to verify
    * provider-owned replay against the current model route. RuntimeEvents stay
diff --git a/packages/core/src/turn-origin.ts b/packages/core/src/turn-origin.ts
index c6bbae7662..96844772da 100644
--- a/packages/core/src/turn-origin.ts
+++ b/packages/core/src/turn-origin.ts
@@ -29,8 +29,14 @@ export interface WorkHubResultOrigin {
   targetTurnId: string;
 }
 
+export interface CloudActivationOrigin {
+  kind: 'cloud_activation';
+  activationId: string;
+}
+
 export type TurnOrigin =
   | WorkHubResultOrigin
+  | CloudActivationOrigin
   | { kind: 'scheduled_task'; scheduledTaskId: string }
   | { kind: 'legacy_automation'; automationId: string }
   | { kind: 'goal'; goalId: string }
@@ -44,6 +50,7 @@ export type TurnOrigin =
     };
 
 type ScheduledTaskOrigin = Extract<TurnOrigin, { kind: 'scheduled_task' }>;
+type CloudActivationOriginType = Extract<TurnOrigin, { kind: 'cloud_activation' }>;
 type LegacyAutomationOrigin = Extract<TurnOrigin, { kind: 'legacy_automation' }>;
 type GoalOrigin = Extract<TurnOrigin, { kind: 'goal' }>;
 type AgentGraphOrigin = Extract<TurnOrigin, { kind: 'agent_graph' }>;
@@ -52,6 +59,10 @@ const SCHEDULED_TASK_ORIGIN_SHAPE = defineObjectShape<ScheduledTaskOrigin>()(
   ['kind', 'scheduledTaskId'],
   [],
 );
+const CLOUD_ACTIVATION_ORIGIN_SHAPE = defineObjectShape<CloudActivationOriginType>()(
+  ['kind', 'activationId'],
+  [],
+);
 const LEGACY_AUTOMATION_ORIGIN_SHAPE = defineObjectShape<LegacyAutomationOrigin>()(
   ['kind', 'automationId'],
   [],
@@ -91,6 +102,13 @@ export function decodeTurnOrigin(value: unknown): TurnOrigin | undefined {
   ) {
     return { kind: 'scheduled_task', scheduledTaskId: value.scheduledTaskId };
   }
+  if (
+    hasExactShape(value, CLOUD_ACTIVATION_ORIGIN_SHAPE) &&
+    value.kind === 'cloud_activation' &&
+    typeof value.activationId === 'string'
+  ) {
+    return { kind: 'cloud_activation', activationId: value.activationId };
+  }
   if (
     hasExactShape(value, LEGACY_AUTOMATION_ORIGIN_SHAPE) &&
     (value.kind === 'automation' || value.kind === 'legacy_automation') &&
diff --git a/packages/runtime/src/__tests__/ai-sdk-backend.test.ts b/packages/runtime/src/__tests__/ai-sdk-backend.test.ts
index 1948c14265..12a5bd336c 100644
--- a/packages/runtime/src/__tests__/ai-sdk-backend.test.ts
+++ b/packages/runtime/src/__tests__/ai-sdk-backend.test.ts
@@ -64,6 +64,7 @@ import type { DurableSessionEventSink, MakaTool, ToolRuntime } from '../tool-run
 import { TOOL_SEARCH_NAME } from '../tool-availability.js';
 import { buildNativeWebSearchTool } from '../native-web-search-tool.js';
 import { canonicalizeToolSet } from '../request-shape.js';
+import { canonicalToolArgsHash } from '@maka/core/tool-args-identity';
 import {
   ARCHIVED_TOOL_RESULT_PLACEHOLDER_KIND,
   ARCHIVED_TOOL_RESULT_REWRITE_VERSION,
@@ -103,7 +104,7 @@ import { deferred, waitFor as pollFor } from '@maka/core/test-only/async-primiti
 import { Context } from '../plugin-kernel.js';
 import { MakaCompositionLoader } from '../plugin-composition-loader.js';
 import { PluginToolService } from '../plugin-tool-service.js';
-import { testInvocationOpening } from './invocation-fixture.js';
+import { testInvocationOpening, testInvocationRecord } from './invocation-fixture.js';
 
 for (const terminal of ['gateway', 'eof', 'other'] as const) {
   test(`recovers ${terminal} SSE with one failed attempt and no repeated tool effects`, async () => {
@@ -15126,7 +15127,14 @@ describe('AiSdkBackend steering durability and identity', () => {
   const steeringBackend = (
     model: MockLanguageModelV4,
     options: Partial<
-      Pick<AiSdkBackendInput, 'supportsVision' | 'readAttachmentBytes' | 'loadTurnRuntimeEvents'>
+      Pick<
+        AiSdkBackendInput,
+        | 'supportsVision'
+        | 'readAttachmentBytes'
+        | 'loadTurnRuntimeEvents'
+        | 'loadHistoryCompactCheckpoint'
+        | 'contextBudget'
+      >
     > = {},
   ): AiSdkBackend =>
     createTestAiSdkBackend({
@@ -15380,6 +15388,271 @@ describe('AiSdkBackend steering durability and identity', () => {
     );
   });
 
+  test('a fresh client message projects prior unknown tool outcomes only into the model request', async () => {
+    const args = { command: 'touch marker.txt' };
+    const priorIdentity = {
+      invocationId: 'prior-invocation',
+      runId: 'prior-run',
+      sessionId: 'session-1',
+      turnId: 'prior-turn',
+      ts: 1,
+      partial: false,
+    } as const;
+    const earlierIdentity = {
+      invocationId: 'earlier-invocation',
+      runId: 'earlier-run',
+      sessionId: 'session-1',
+      turnId: 'earlier-turn',
+      ts: 1,
+      partial: false,
+    } as const;
+    const priorEvents: RuntimeEvent[] = [
+      {
+        ...earlierIdentity,
+        id: 'earlier-protocol',
+        role: 'system',
+        author: 'system',
+        actions: { runtimeProtocol: { toolBoundary: 't1_after_preflight_v1' } },
+      },
+      {
+        ...earlierIdentity,
+        id: 'earlier-user',
+        role: 'user',
+        author: 'user',
+        content: { kind: 'text', text: 'the first turn completed normally' },
+      },
+      {
+        ...priorIdentity,
+        id: 'prior-protocol',
+        role: 'system',
+        author: 'system',
+        actions: { runtimeProtocol: { toolBoundary: 't1_after_preflight_v1' } },
+      },
+      {
+        ...priorIdentity,
+        id: 'prior-user',
+        role: 'user',
+        author: 'user',
+        content: { kind: 'text', text: 'make a marker file' },
+      },
+      {
+        ...priorIdentity,
+        id: 'prior-call',
+        role: 'model',
+        author: 'agent',
+        origin: 'provider',
+        modelVisibility: 'visible',
+        content: { kind: 'function_call', id: 'provider-call-1', name: 'Bash', args },
+        refs: { operationId: 'prior-operation', toolCallId: 'provider-call-1' },
+      },
+      {
+        ...priorIdentity,
+        id: 'prior-dispatch',
+        role: 'system',
+        author: 'system',
+        actions: {
+          toolDispatch: {
+            protocol: 't1_after_preflight_v1',
+            operationId: 'prior-operation',
+            providerToolCallId: 'provider-call-1',
+            toolName: 'Bash',
+            canonicalArgsHash: canonicalToolArgsHash('Bash', args),
+            recoveryMode: 'never_auto_retry',
+          },
+        },
+        refs: { operationId: 'prior-operation', toolCallId: 'provider-call-1' },
+      },
+      {
+        ...priorIdentity,
+        id: 'hidden-nested-call',
+        role: 'model',
+        author: 'agent',
+        origin: 'code_mode',
+        modelVisibility: 'hidden',
+        content: {
+          kind: 'function_call',
+          id: 'hidden-nested-call-1',
+          name: 'SecretNestedTool',
+          args: { secret: 'hidden-operation-argument' },
+        },
+        refs: {
+          operationId: 'hidden-nested-operation',
+          toolCallId: 'hidden-nested-call-1',
+          parentOperationId: 'prior-operation',
+          parentToolCallId: 'provider-call-1',
+        },
+      },
+      {
+        ...priorIdentity,
+        id: 'hidden-nested-dispatch',
+        role: 'system',
+        author: 'system',
+        origin: 'code_mode',
+        modelVisibility: 'hidden',
+        actions: {
+          toolDispatch: {
+            protocol: 't1_after_preflight_v1',
+            operationId: 'hidden-nested-operation',
+            providerToolCallId: 'hidden-nested-call-1',
+            toolName: 'SecretNestedTool',
+            canonicalArgsHash: canonicalToolArgsHash('SecretNestedTool', {
+              secret: 'hidden-operation-argument',
+            }),
+            recoveryMode: 'never_auto_retry',
+          },
+        },
+        refs: {
+          operationId: 'hidden-nested-operation',
+          toolCallId: 'hidden-nested-call-1',
+          parentOperationId: 'prior-operation',
+          parentToolCallId: 'provider-call-1',
+        },
+      },
+    ];
+    const earlierInvocation = testInvocationRecord({
+      sessionId: 'session-1',
+      invocationId: 'earlier-invocation',
+      runId: 'earlier-run',
+      turnId: 'earlier-turn',
+      outcome: 'completed',
+    });
+    const priorInvocation = testInvocationRecord({
+      sessionId: 'session-1',
+      invocationId: 'prior-invocation',
+      runId: 'prior-run',
+      turnId: 'prior-turn',
+      outcome: 'failed',
+      failureClass: 'outcome_unknown',
+    });
+    const model = textCompletionModel('I will inspect the current state first.');
+    const priorCheckpoint = buildHistoryCompactCheckpoint({
+      sessionId: 'session-1',
+      coveredRuntimeEvents: [priorEvents[1]!],
+      summary: structuredSummary('older settled history was compacted'),
+    });
+    const durable = durableTurnHarness('turn-resume', 'check whether the marker exists', {
+      runId: 'fresh-run',
+    });
+    const backend = steeringBackend(model, {
+      loadTurnRuntimeEvents: durable.loadTurnRuntimeEvents,
+      loadHistoryCompactCheckpoint: () => priorCheckpoint,
+      contextBudget: buildDefaultContextBudgetPolicy(),
+    });
+
+    await drainDurably(
+      backend.send(
+        durable.input({
+          runtimeContext: priorEvents,
+          runtimeContextInvocations: [earlierInvocation, priorInvocation],
+          allowPriorUnknownToolOutcomes: true,
+        }),
+      ),
+      durable,
+    );
+
+    const prompt = JSON.stringify(model.doStreamCalls[0]);
+    assert.match(prompt, /provider-call-1/);
+    assert.match(prompt, /outcome_unknown/);
+    assert.match(prompt, /may or may not have happened/);
+    assert.match(prompt, /check whether the marker exists/);
+    assert.doesNotMatch(
+      prompt,
+      /SecretNestedTool|hidden-nested-operation|hidden-operation-argument/,
+    );
+    assert.match(prompt, /older settled history was compacted/);
+    assert.equal(
+      durable.ledger.some(
+        (event) =>
+          event.content?.kind === 'function_response' && event.content.id === 'provider-call-1',
+      ),
+      false,
+      'request-only unknown results must not be written into the new turn ledger',
+    );
+
+    const checkpointCoveringUnknownCall = buildHistoryCompactCheckpoint({
+      sessionId: 'session-1',
+      coveredRuntimeEvents: priorEvents.slice(0, 6),
+      summary: structuredSummary('checkpoint omitted the unresolved provider call'),
+    });
+    const checkpointed = durableTurnHarness(
+      'turn-checkpointed-unknown',
+      'inspect the marker before deciding what to do',
+      { runId: 'checkpointed-run' },
+    );
+    const checkpointedModel = textCompletionModel('I will inspect the marker first.');
+    const checkpointedBackend = steeringBackend(checkpointedModel, {
+      loadTurnRuntimeEvents: checkpointed.loadTurnRuntimeEvents,
+      loadHistoryCompactCheckpoint: () => checkpointCoveringUnknownCall,
+      contextBudget: buildDefaultContextBudgetPolicy(),
+    });
+    await drainDurably(
+      checkpointedBackend.send(
+        checkpointed.input({
+          runtimeContext: priorEvents,
+          runtimeContextInvocations: [earlierInvocation, priorInvocation],
+          allowPriorUnknownToolOutcomes: true,
+        }),
+      ),
+      checkpointed,
+    );
+    const checkpointedPrompt = JSON.stringify(checkpointedModel.doStreamCalls[0]);
+    assert.match(checkpointedPrompt, /provider-call-1/);
+    assert.match(checkpointedPrompt, /outcome_unknown/);
+    assert.match(checkpointedPrompt, /may or may not have happened/);
+    assert.doesNotMatch(checkpointedPrompt, /checkpoint omitted the unresolved provider call/);
+
+    const inconsistentModel = textCompletionModel('must not be sent');
+    const inconsistent = durableTurnHarness('turn-inconsistent', 'new message', {
+      runId: 'inconsistent-run',
+    });
+    const inconsistentBackend = steeringBackend(inconsistentModel, {
+      loadTurnRuntimeEvents: inconsistent.loadTurnRuntimeEvents,
+    });
+    await assert.rejects(
+      drainDurably(
+        inconsistentBackend.send(
+          inconsistent.input({
+            runtimeContext: priorEvents,
+            runtimeContextInvocations: [
+              earlierInvocation,
+              {
+                ...priorInvocation,
+                terminalEvent: {
+                  ...priorInvocation.terminalEvent!,
+                  status: 'completed',
+                },
+              },
+            ],
+            allowPriorUnknownToolOutcomes: true,
+          }),
+        ),
+        inconsistent,
+      ),
+      /prior unknown tool outcome has no sealed invocation/,
+    );
+    assert.equal(inconsistentModel.doStreamCalls.length, 0);
+
+    const unprivilegedModel = textCompletionModel('No recovery context was admitted.');
+    const unprivileged = durableTurnHarness('turn-unprivileged', 'ordinary message', {
+      runId: 'unprivileged-run',
+    });
+    const unprivilegedBackend = steeringBackend(unprivilegedModel, {
+      loadTurnRuntimeEvents: unprivileged.loadTurnRuntimeEvents,
+    });
+    await drainDurably(
+      unprivilegedBackend.send(
+        unprivileged.input({
+          runtimeContext: priorEvents,
+          runtimeContextInvocations: [earlierInvocation, priorInvocation],
+        }),
+      ),
+      unprivileged,
+    );
+    const unprivilegedPrompt = JSON.stringify(unprivilegedModel.doStreamCalls[0]);
+    assert.doesNotMatch(unprivilegedPrompt, /outcome_unknown/);
+    assert.doesNotMatch(unprivilegedPrompt, /provider-call-1/);
+  });
+
   test('persists canonical steering content and materializes attachments for the model', async () => {
     const model = textCompletionModel('done');
     const pngBytes = new Uint8Array([137, 80, 78, 71]);
diff --git a/packages/runtime/src/__tests__/recovery-resolver.test.ts b/packages/runtime/src/__tests__/recovery-resolver.test.ts
index b85b5bb6d7..3b027d7d73 100644
--- a/packages/runtime/src/__tests__/recovery-resolver.test.ts
+++ b/packages/runtime/src/__tests__/recovery-resolver.test.ts
@@ -18,17 +18,10 @@
  */
 
 import assert from 'node:assert/strict';
-import { mkdtemp, rm } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
 import { describe, it } from 'node:test';
 import { canonicalToolArgsHash } from '@maka/core/tool-args-identity';
 import type { RuntimeEvent } from '@maka/core/runtime-event';
-import { createSqliteRuntimeStore } from '@maka/storage/sqlite-runtime-store';
-import {
-  buildInterruptedToolOutcomeCommits,
-  resolveRuntimeRecovery,
-} from '../recovery-resolver.js';
+import { resolveRuntimeRecovery } from '../recovery-resolver.js';
 
 describe('RecoveryResolver', () => {
   it('proves a new-protocol call without dispatch was never dispatched', () => {
@@ -72,7 +65,7 @@ describe('RecoveryResolver', () => {
     assert.equal(resolution.requiresReconciliation, true);
   });
 
-  it('settles every dispatched operation, including hidden nested calls', () => {
+  it('keeps dispatched operations unresolved instead of inventing durable tool results', () => {
     const outerCall = event({
       id: 'outer-call',
       role: 'model',
@@ -115,219 +108,43 @@ describe('RecoveryResolver', () => {
       parentToolCallId: 'exec-1',
     });
 
-    const commits = buildInterruptedToolOutcomeCommits(
-      [initialEvent('t1_after_preflight_v1'), outerCall, outerDispatch, nestedCall, nestedDispatch],
-      50,
-      'code_mode',
-    );
+    const events = [
+      initialEvent('t1_after_preflight_v1'),
+      outerCall,
+      outerDispatch,
+      nestedCall,
+      nestedDispatch,
+    ];
+    const resolution = resolveRuntimeRecovery(events);
 
-    assert.equal(commits.length, 2);
-    const outerCommit = commits.find((commit) => commit.operationId === 'outer-op');
-    const nestedCommit = commits.find((commit) => commit.operationId === 'nested-op');
-    assert.ok(outerCommit);
-    assert.ok(nestedCommit);
-    assert.equal(outerCommit.runtimeEvent.content?.kind, 'function_response');
-    assert.equal(
-      outerCommit.runtimeEvent.content?.kind === 'function_response'
-        ? outerCommit.runtimeEvent.content.isError
-        : false,
-      true,
-    );
     assert.deepEqual(
-      outerCommit.runtimeEvent.content?.kind === 'function_response'
-        ? outerCommit.runtimeEvent.content.result
-        : undefined,
-      {
-        kind: 'json',
-        value: {
-          kind: 'code_mode',
-          status: 'interrupted',
-          message:
-            'Code Mode execution was interrupted by runtime recovery. Its side effects may or may not have occurred; do not retry it immediately. Inspect the current state first.',
-          uncertainOutcome: { code: 'outcome_unknown', retrySafe: false },
-        },
-      },
-    );
-    assert.deepEqual(
-      outerCommit.runtimeEvent.content?.kind === 'function_response'
-        ? outerCommit.runtimeEvent.content.modelProjection
-        : undefined,
-      {
-        version: 1,
-        kind: 'json',
-        value: {
-          kind: 'json',
-          value: {
-            kind: 'code_mode',
-            status: 'interrupted',
-            message:
-              'Code Mode execution was interrupted by runtime recovery. Its side effects may or may not have occurred; do not retry it immediately. Inspect the current state first.',
-            uncertainOutcome: { code: 'outcome_unknown', retrySafe: false },
-          },
-        },
-        isError: true,
-      },
-    );
-    assert.equal(nestedCommit.runtimeEvent.modelVisibility, 'hidden');
-    assert.equal(
-      nestedCommit.runtimeEvent.content?.kind === 'function_response'
-        ? nestedCommit.runtimeEvent.content.isError
-        : false,
-      true,
-    );
-    assert.equal(
-      nestedCommit.runtimeEvent.content?.kind === 'function_response' &&
-        typeof nestedCommit.runtimeEvent.content.result === 'object' &&
-        nestedCommit.runtimeEvent.content.result !== null &&
-        'uncertainOutcome' in nestedCommit.runtimeEvent.content.result,
-      true,
-    );
-  });
-
-  it('commits a projected recovery outcome through the projection-aware SQLite T2 gate', async () => {
-    const root = await mkdtemp(join(tmpdir(), 'maka-recovery-projection-'));
-    const store = createSqliteRuntimeStore(join(root, 'runtime.sqlite'));
-    try {
-      const call = event({
-        id: 'outer-call',
-        role: 'model',
-        author: 'agent',
-        origin: 'provider',
-        modelVisibility: 'visible',
-        content: { kind: 'function_call', id: 'exec-1', name: 'exec', args: { code: 'work()' } },
-        refs: { operationId: 'outer-op', toolCallId: 'exec-1' },
-      });
-      const dispatch = dispatchFor({
-        id: 'outer-dispatch',
-        operationId: 'outer-op',
-        toolCallId: 'exec-1',
-        toolName: 'exec',
-        args: { code: 'work()' },
-        resultProjectionVersion: 1,
-      });
-      await store.commitToolPrepared({
-        operationId: 'outer-op',
-        journalEventId: 'outer-op_prepared',
-        runtimeEvent: call,
-        dispatchRuntimeEvent: dispatch,
-        providerToolCallId: 'exec-1',
-        toolName: 'exec',
-        canonicalArgsHash: canonicalToolArgsHash('exec', { code: 'work()' }),
-        recoveryMode: 'never_auto_retry',
-        committedAt: 10,
-      });
-
-      const [commit] = buildInterruptedToolOutcomeCommits(
-        await store.readImmutableRuntimeEvents('session-1', 'run-1'),
-        50,
-        'code_mode',
-      );
-      assert.ok(commit);
-      await store.commitToolOutcome(commit);
-
-      assert.equal((await store.readToolOperation('outer-op'))?.currentState, 'outcome_committed');
-      const response = (await store.readImmutableRuntimeEvents('session-1', 'run-1')).at(-1);
-      assert.equal(response?.content?.kind, 'function_response');
-      assert.equal(
-        response?.content?.kind === 'function_response'
-          ? response.content.modelProjection?.version
-          : undefined,
-        1,
-      );
-    } finally {
-      store.close();
-      await rm(root, { recursive: true, force: true });
-    }
-  });
-
-  it('marks generic interrupted tools as outcome-unknown and does not retry them', () => {
-    const commits = buildInterruptedToolOutcomeCommits(
+      resolution.decisions.map(({ toolCallId, status, reason }) => ({
+        toolCallId,
+        status,
+        reason,
+      })),
       [
-        initialEvent('t1_after_preflight_v1'),
-        event({
-          id: 'direct-exec-call',
-          role: 'model',
-          author: 'agent',
-          origin: 'provider',
-          modelVisibility: 'visible',
-          content: { kind: 'function_call', id: 'exec-1', name: 'exec', args: {} },
-          refs: { operationId: 'direct-exec-op', toolCallId: 'exec-1' },
-        }),
-        dispatchFor({
-          id: 'direct-exec-dispatch',
-          operationId: 'direct-exec-op',
-          toolCallId: 'exec-1',
-          toolName: 'exec',
-          args: {},
-        }),
+        { toolCallId: 'exec-1', status: 'indeterminate', reason: 'dispatch_without_response' },
+        { toolCallId: 'nested-1', status: 'indeterminate', reason: 'dispatch_without_response' },
       ],
-      50,
-      'direct',
     );
-
-    assert.equal(commits.length, 1);
-    assert.equal(commits[0]?.operationId, 'direct-exec-op');
     assert.equal(
-      commits[0]?.runtimeEvent.content?.kind === 'function_response' &&
-        typeof commits[0].runtimeEvent.content.result === 'object' &&
-        commits[0].runtimeEvent.content.result !== null &&
-        'uncertainOutcome' in commits[0].runtimeEvent.content.result,
-      true,
-    );
-  });
-
-  it('settles a dispatched user question as interrupted without claiming a side effect', () => {
-    const args = { questions: [{ question: 'Continue?', options: ['Yes', 'No'] }] };
-    const call = event({
-      id: 'question-call',
-      role: 'model',
-      author: 'agent',
-      content: {
-        kind: 'function_call',
-        id: 'question-1',
-        name: 'AskUserQuestion',
-        args,
-      },
-    });
-    const dispatch = dispatchFor({
-      id: 'question-dispatch',
-      operationId: 'question-op',
-      toolCallId: 'question-1',
-      toolName: 'AskUserQuestion',
-      args,
-    });
-
-    const [commit] = buildInterruptedToolOutcomeCommits(
-      [initialEvent('t1_after_preflight_v1'), call, dispatch],
-      50,
-      'direct',
-    );
-    assert.ok(commit);
-    assert.equal(commit.runtimeEvent.content?.kind, 'function_response');
-    assert.deepEqual(
-      commit.runtimeEvent.content?.kind === 'function_response'
-        ? commit.runtimeEvent.content.result
-        : undefined,
-      {
-        kind: 'text',
-        text: 'This question was interrupted by runtime recovery before an answer was submitted.',
-      },
+      events.some((candidate) => candidate.content?.kind === 'function_response'),
+      false,
     );
   });
 
-  it('does not append an interrupted result after the invocation terminal event', () => {
-    const commits = buildInterruptedToolOutcomeCommits(
-      [
-        initialEvent('t1_after_preflight_v1'),
-        functionCallEvent(),
-        toolDispatchEvent(),
-        event({ id: 'terminal-1', status: 'aborted', actions: { endInvocation: true } }),
-      ],
-      50,
-      'direct',
-    );
+  it('a terminal invocation does not turn a dispatched operation into a settled tool result', () => {
+    const resolution = resolveRuntimeRecovery([
+      initialEvent('t1_after_preflight_v1'),
+      functionCallEvent(),
+      toolDispatchEvent(),
+      event({ id: 'terminal-1', status: 'failed', actions: { endInvocation: true } }),
+    ]);
 
-    assert.deepEqual(commits, []);
+    assert.equal(resolution.decisions[0]?.status, 'indeterminate');
+    assert.equal(resolution.decisions[0]?.reason, 'dispatch_without_response');
+    assert.equal(resolution.requiresReconciliation, true);
   });
 
   it('treats a matching response without dispatch as a completed pre-T1 result', () => {
diff --git a/packages/runtime/src/__tests__/session-manager.test.ts b/packages/runtime/src/__tests__/session-manager.test.ts
index 05c743c36c..997cf7076b 100644
--- a/packages/runtime/src/__tests__/session-manager.test.ts
+++ b/packages/runtime/src/__tests__/session-manager.test.ts
@@ -65,7 +65,7 @@ import { RUNTIME_CONTINUATION_AUTHORITY_V1 } from '@maka/core/runtime-event-stor
 import { deriveTurnRecords } from '@maka/core/session';
 import { isTerminalRuntimeEvent } from '@maka/core/runtime-event';
 import { canonicalToolArgsHash } from '@maka/core/tool-args-identity';
-import { buildInterruptedToolOutcomeCommits } from '../recovery-resolver.js';
+import { resolveRuntimeRecovery } from '../recovery-resolver.js';
 import { buildImmutableRuntimePrefix, decodeContinuationClaim } from '@maka/core/runtime-boundary';
 import type {
   CreateSandboxBoundaryRequest,
@@ -141,7 +141,6 @@ import { RuntimeReadModel, RuntimeReadModelError } from '../runtime-read-model.j
 import type { AgentBackend } from '@maka/core/backend-types';
 import type { MakaTool } from '../tool-runtime.js';
 import type { ShellRunProcessManager } from '../shell-run-manager.js';
-import type { RuntimeCommitSink } from '../runtime-commit-sink.js';
 import {
   buildHistoryCompactCheckpoint,
   type HistoryCompactCheckpoint,
@@ -6414,6 +6413,16 @@ describe('SessionManager permission mode updates', () => {
       ['turn-1-final', 'turn-1-complete'],
     );
     assert.strictEqual(backend?.sendInputs[0]?.toolMode, 'code_mode');
+    assert.strictEqual(backend?.sendInputs[0]?.allowPriorUnknownToolOutcomes, true);
+
+    await collectSessionEvents(
+      manager.sendMessage(session.id, {
+        turnId: 'turn-2',
+        text: 'automated activation',
+        origin: { kind: 'cloud_activation', activationId: 'activation-2' },
+      }),
+    );
+    assert.strictEqual(backend?.sendInputs[1]?.allowPriorUnknownToolOutcomes, undefined);
 
     const [run] = await runtimeEventStore.listSessionInvocations(session.id);
     if (!run) throw new Error('the run opened no invocation');
@@ -12814,38 +12823,20 @@ describe('SessionManager permission mode updates', () => {
     assert.strictEqual((await turnOf(activeDone.id, 'active-turn'))?.status, 'completed');
   });
 
-  test('startup recovery settles arbitrary dispatched tools before terminalizing the run', async () => {
+  test('startup recovery seals dispatched tools as unknown without inventing durable results', async () => {
     const store = new MemorySessionStore();
     const runStore = new MemoryAgentRunStore();
     const backends = new BackendRegistry();
     backends.register('ai-sdk', (ctx) => new TestBackend(ctx));
-    let sessionId = '';
-    let outcomeCommitFailuresRemaining = 3;
-    let outcomeCommitAttempts = 0;
-    const runtimeCommitSink: RuntimeCommitSink = {
-      commitToolPrepared: async () => {
-        throw new Error('not used during recovery');
-      },
-      commitToolOutcome: async (input) => {
-        outcomeCommitAttempts += 1;
-        if (outcomeCommitFailuresRemaining > 0) {
-          outcomeCommitFailuresRemaining -= 1;
-          throw new Error('transient outcome commit failure');
-        }
-        await runStore.appendRuntimeEvent(sessionId, 'run-1', input.runtimeEvent);
-        return { created: true, runtimeEventSeq: 4 };
-      },
-    };
     const manager = new SessionManager({
       store,
       runStore,
-      runtimeEventStore: Object.assign(runStore, runtimeCommitSink),
+      runtimeEventStore: runStore,
       backends,
       newId: nextId(),
       now: nextNow(12_825),
     });
     const session = await manager.createSession(makeInput({ status: 'running' }));
-    sessionId = session.id;
     await seedRunningTurn(store, session.id, 'turn-1');
     await seedRun(
       runStore,
@@ -12913,48 +12904,28 @@ describe('SessionManager permission mode updates', () => {
       }),
     );
 
-    const preRecoveryEvents = await runStore.readRuntimeEvents(session.id, 'run-1');
-    assert.equal(
-      buildInterruptedToolOutcomeCommits(preRecoveryEvents, 12_825, 'code_mode').length,
-      1,
-    );
     await manager.recoverInterruptedSessions();
 
-    assert.equal((await readInvocation(runStore, session.id, 'run-1')).terminalEvent, undefined);
-    assert.equal(outcomeCommitAttempts, 2);
+    const runtimeEvents = await runStore.readRuntimeEvents(session.id, 'run-1');
+    const recovery = resolveRuntimeRecovery(runtimeEvents);
     assert.equal(
-      (await runStore.readRuntimeEvents(session.id, 'run-1')).some(
-        (event) => event.content?.kind === 'function_response',
-      ),
+      runtimeEvents.some((event) => event.content?.kind === 'function_response'),
       false,
     );
-
-    await manager.recoverInterruptedSessions();
-
-    assert.equal(outcomeCommitAttempts, 4);
-    const runtimeEvents = await runStore.readRuntimeEvents(session.id, 'run-1');
-    const response = runtimeEvents.find(
-      (event) => event.content?.kind === 'function_response' && event.content.id === 'exec-1',
-    );
-    assert.equal(response?.content?.kind, 'function_response');
-    assert.equal(response?.content?.kind === 'function_response' && response.content.isError, true);
     assert.deepEqual(
-      response?.content?.kind === 'function_response' ? response.content.result : undefined,
-      {
-        kind: 'text',
-        text: 'Tool Bash was interrupted before its result was committed. Its side effects may or may not have occurred. Do not retry it immediately; inspect the current state first.',
-        uncertainOutcome: { code: 'outcome_unknown', retrySafe: false },
-      },
-    );
-    const responseIndex = runtimeEvents.findIndex(
-      (event) => event.content?.kind === 'function_response',
-    );
-    const terminalIndex = runtimeEvents.findIndex(isTerminalRuntimeEvent);
-    assert.ok(responseIndex >= 0 && terminalIndex > responseIndex);
-    assert.equal(
-      runtimeInvocationOutcome(await readInvocation(runStore, session.id, 'run-1')),
-      'failed',
-    );
+      recovery.decisions.map(({ toolCallId, status, reason }) => ({
+        toolCallId,
+        status,
+        reason,
+      })),
+      [{ toolCallId: 'exec-1', status: 'indeterminate', reason: 'dispatch_without_response' }],
+    );
+    const terminalEvent = runtimeEvents.find(isTerminalRuntimeEvent);
+    assert.equal(terminalEvent?.status, 'failed');
+    const invocation = await readInvocation(runStore, session.id, 'run-1');
+    assert.ok(invocation.terminalEvent);
+    assert.equal(runtimeInvocationFailureClass(invocation), 'outcome_unknown');
+    assert.equal(runtimeInvocationOutcome(invocation), 'failed');
   });
 
   test('startup recovery does not leave stale permission waits stuck', async () => {
diff --git a/packages/runtime/src/ai-sdk-turn.ts b/packages/runtime/src/ai-sdk-turn.ts
index cb2f3cca8b..541f76cb47 100644
--- a/packages/runtime/src/ai-sdk-turn.ts
+++ b/packages/runtime/src/ai-sdk-turn.ts
@@ -130,15 +130,19 @@ import {
 } from './sandbox-boundary-tool.js';
 import {
   buildRuntimeEventModelReplayPlan,
+  appendPriorUnknownToolResponses,
   buildSteeringEnvelope,
   collectToolActivityTurnIds,
   compatibleProviderReasoningReplayEventIds,
   formatTextWithInlineRefs,
+  inspectPriorUnknownToolOutcomes,
   steeringMessagesMissingFromBase,
   steeringModelMessage,
+  type PriorUnknownToolOutcomeProjection,
   type RuntimeEventModelReplayPlan,
   type RuntimeEventReplayFallbackGate,
 } from './model-history.js';
+import type { ContextBudgetPolicy } from './context-budget.js';
 import {
   toolSchemaCharsForDiagnostics,
   requestCompositionToolSchemas,
@@ -855,7 +859,20 @@ export class AiSdkTurn {
     const toolRuntime = this.toolRuntime;
     const turnAbortController = this.abortController;
 
-    const midTurnState = this.deps.compaction.buildMidTurnCapacityCompactState(input);
+    const priorEvents = (input.runtimeContext ?? []).filter(
+      (event) => input.continuation !== undefined || event.turnId !== input.turnId,
+    );
+    const priorUnknownProjection: PriorUnknownToolOutcomeProjection =
+      input.allowPriorUnknownToolOutcomes && !input.continuation
+        ? inspectPriorUnknownToolOutcomes(priorEvents, input.runtimeContextInvocations)
+        : { kind: 'none' };
+    if (priorUnknownProjection.kind === 'blocked') {
+      throw new Error(`Cannot use prior tool history: ${priorUnknownProjection.reason}`);
+    }
+    const preservingUnknownHistory = priorUnknownProjection.kind === 'projected';
+    const midTurnState = preservingUnknownHistory
+      ? undefined
+      : this.deps.compaction.buildMidTurnCapacityCompactState(input);
     const queue = new AsyncEventQueue<SessionEvent>();
     const codeModeExecTool = this.createCodeModeExecTool(queue);
 
@@ -1131,7 +1148,7 @@ export class AiSdkTurn {
     let systemPrompt: string | undefined;
 
     // --- Build messages from RuntimeEvent history and its compatibility projection. ---
-    const priorReplayResult = await this.buildPriorMessages(input);
+    const priorReplayResult = await this.buildPriorMessages(input, priorUnknownProjection);
     if (this.aborted) {
       queue.push({
         type: 'abort',
@@ -1283,6 +1300,10 @@ export class AiSdkTurn {
         };
         const loadDurableTurnProjection = async (): Promise<ModelMessage[]> => {
           const turnEvents = await loadDurableTurnEvents();
+          // Prior unknown call/result pairs are outside this current-turn event
+          // set and are preserved separately in priorReplay. Continue pruning
+          // new tool results from this turn so one unknown predecessor does not
+          // make an unrelated large result permanently unprunable.
           const pruned = await this.deps.compaction.pruneToolResults(turnEvents, turnId);
           if (pruned.stats) {
             contextBudgetForTelemetry = addToolResultPruneStats(
@@ -1468,6 +1489,9 @@ export class AiSdkTurn {
           }
           const requestSystemPromptBase = joinPromptFragments([
             systemPrompt,
+            priorUnknownProjection.kind === 'projected'
+              ? priorUnknownProjection.systemNotice
+              : undefined,
             finalChildSummaryStep ? CHILD_STEP_BUDGET_FINALIZATION_PROMPT : undefined,
             toolRuntime.hasSandboxBoundaryDenial() ? SANDBOX_BOUNDARY_DENIED_FOR_TURN : undefined,
             sandboxBoundaryFinalizationStep ? SANDBOX_BOUNDARY_FINALIZATION_PROMPT : undefined,
@@ -1948,6 +1972,7 @@ export class AiSdkTurn {
               // nothing left to grant it, so the error is terminal.
               const stepBudgetRemains = maxSteps === undefined || runtimeSteps < maxSteps;
               const recovered =
+                !preservingUnknownHistory &&
                 stepBudgetRemains &&
                 failure.kind === 'context_overflow' &&
                 providerAttempt < MAX_PROVIDER_ATTEMPTS_PER_STEP &&
@@ -2678,7 +2703,10 @@ export class AiSdkTurn {
   }
 
   /** Materialize canonical RuntimeEvent history into ai-sdk's message format. */
-  private async buildPriorMessages(input: BackendSendInput): Promise<PriorReplayResult> {
+  private async buildPriorMessages(
+    input: BackendSendInput,
+    priorUnknownProjection: PriorUnknownToolOutcomeProjection,
+  ): Promise<PriorReplayResult> {
     if (!input.runtimeContext) {
       return {
         status: 'ready',
@@ -2696,40 +2724,81 @@ export class AiSdkTurn {
     // the durable projection-transition reducer (#4283). Replay, budgeting and
     // compaction share one input, so no RuntimeEvent replay path can resurrect
     // content a committed transition removed.
-    const preparedContextBudget = await this.deps.compaction.prepareContextBudgetPolicy(
-      rawPriorRuntimeContext,
-      input.turnId,
-    );
-    const priorRuntimeContext = preparedContextBudget.events;
+    const preservingUnknownHistory = priorUnknownProjection.kind === 'projected';
+    let priorRuntimeContext: RuntimeEvent[];
+    let runtimeContext: RuntimeEvent[];
+    let contextBudget: ContextBudgetPolicy | undefined;
+    let contextBudgetDiagnostic: ContextBudgetDiagnostic | undefined;
+    let projectedHistoryCompactCheckpoint: HistoryCompactCheckpoint | undefined;
+    if (priorUnknownProjection.kind === 'projected') {
+      const preparedContextBudget = await this.deps.compaction.prepareContextBudgetPolicy(
+        rawPriorRuntimeContext,
+        input.turnId,
+      );
+      priorRuntimeContext = preparedContextBudget.events;
+      contextBudget = preparedContextBudget.policy;
+      const budgeted = applyRuntimeEventContextBudget(rawPriorRuntimeContext, contextBudget);
+      const budgetedEvents = budgeted?.events ?? rawPriorRuntimeContext;
+      const preservesUnknownCalls = priorUnknownProjection.outcomes.every((outcome) =>
+        budgetedEvents.some((event) => event.id === outcome.callEventId),
+      );
+      // Existing checkpoints and durable result pruning are safe when they
+      // leave every unknown call available to pair with its temporary result.
+      // Otherwise replay the full effective ledger: a summary that erases T1
+      // would make the request-local T2 orphaned or hide the uncertainty.
+      const selectedEvents = preservesUnknownCalls ? budgetedEvents : rawPriorRuntimeContext;
+      const effectiveEvents = await this.deps.compaction.foldEffectiveModelHistory(
+        selectedEvents,
+        preparedContextBudget.projectionSnapshot,
+      );
+      runtimeContext = appendPriorUnknownToolResponses(effectiveEvents, priorUnknownProjection);
+      if (preservesUnknownCalls) {
+        contextBudgetDiagnostic = budgeted?.diagnostic;
+        projectedHistoryCompactCheckpoint = budgeted?.historyCompactCheckpoint;
+      }
+      if (preparedContextBudget.diagnosticPatch) {
+        contextBudgetDiagnostic = mergeContextBudgetDiagnostic(
+          contextBudgetDiagnostic ??
+            buildContextBudgetDiagnosticShell(priorRuntimeContext, effectiveEvents, contextBudget),
+          preparedContextBudget.diagnosticPatch,
+        );
+      }
+    } else {
+      const preparedContextBudget = await this.deps.compaction.prepareContextBudgetPolicy(
+        rawPriorRuntimeContext,
+        input.turnId,
+      );
+      priorRuntimeContext = preparedContextBudget.events;
+      contextBudget = preparedContextBudget.policy;
+      // Match the durable checkpoint against the RAW ledger prefix: every
+      // creation path (standalone compactHistory and the mid-turn state) pins
+      // its coverage digest on raw events, so matching the folded view here
+      // lets any durable projection transition inside the covered prefix orphan
+      // the checkpoint and silently fail open into a full-history replay
+      // (#4842). The projected [block, tail] is then folded through the
+      // transition reducer before it becomes messages, so a committed
+      // transition still cannot resurrect content for the model (#4283).
+      const budgeted = applyRuntimeEventContextBudget(rawPriorRuntimeContext, contextBudget);
+      runtimeContext = await this.deps.compaction.foldEffectiveModelHistory(
+        budgeted?.events ?? rawPriorRuntimeContext,
+        preparedContextBudget.projectionSnapshot,
+      );
+      contextBudgetDiagnostic = budgeted?.diagnostic;
+      projectedHistoryCompactCheckpoint = budgeted?.historyCompactCheckpoint;
+      if (preparedContextBudget.diagnosticPatch) {
+        contextBudgetDiagnostic = mergeContextBudgetDiagnostic(
+          contextBudgetDiagnostic ??
+            buildContextBudgetDiagnosticShell(priorRuntimeContext, runtimeContext, contextBudget),
+          preparedContextBudget.diagnosticPatch,
+        );
+      }
+    }
     const providerReasoningReplayEventIds = compatibleProviderReasoningReplayEventIds(
       priorRuntimeContext,
       input.runtimeContextInvocations,
       this.deps.backend.providerStateIdentity,
       this.deps.backend.modelId,
     );
-    let contextBudget = preparedContextBudget.policy;
-    // Match the durable checkpoint against the RAW ledger prefix: every
-    // creation path (standalone compactHistory and the mid-turn state) pins
-    // its coverage digest on raw events, so matching the folded view here
-    // lets any durable projection transition inside the covered prefix orphan
-    // the checkpoint and silently fail open into a full-history replay
-    // (#4842). The projected [block, tail] is then folded through the
-    // transition reducer before it becomes messages, so a committed
-    // transition still cannot resurrect content for the model (#4283).
-    const budgeted = applyRuntimeEventContextBudget(rawPriorRuntimeContext, contextBudget);
-    let runtimeContext = await this.deps.compaction.foldEffectiveModelHistory(
-      budgeted?.events ?? rawPriorRuntimeContext,
-      preparedContextBudget.projectionSnapshot,
-    );
-    let contextBudgetDiagnostic = budgeted?.diagnostic;
-    let projectedHistoryCompactCheckpoint = budgeted?.historyCompactCheckpoint;
-    if (preparedContextBudget.diagnosticPatch) {
-      contextBudgetDiagnostic = mergeContextBudgetDiagnostic(
-        contextBudgetDiagnostic ??
-          buildContextBudgetDiagnosticShell(priorRuntimeContext, runtimeContext, contextBudget),
-        preparedContextBudget.diagnosticPatch,
-      );
-    }
 
     // No pre-turn estimate gate: the turn's first request is judged by the
     // request-projection hook from the previous request's real usage, and by
diff --git a/packages/runtime/src/model-history.ts b/packages/runtime/src/model-history.ts
index 476424e66c..f70feb3196 100644
--- a/packages/runtime/src/model-history.ts
+++ b/packages/runtime/src/model-history.ts
@@ -66,6 +66,7 @@ import type {
   UserContent,
   UserModelMessage,
 } from './model-protocol.js';
+import { runtimeInvocationFailureClass } from './runtime-event-read-model.js';
 import {
   decodeEffectiveToolResultProjection,
   durableProjectionToToolResultOutput,
@@ -74,9 +75,176 @@ import {
 import { MATERIALIZED_IMAGE_TOKENS } from '@maka/core/attachments';
 import { estimateTokens, stableJsonLength, turnKey } from './context-budget-helpers.js';
 import type { DurableToolResultProjection } from '@maka/core/durable-tool-result-projection';
+import { resolveRuntimeRecovery } from './recovery-resolver.js';
 
 export const PROVIDER_REPLAY_PROJECTION_VERSION = 2;
 
+export interface PriorUnknownToolOutcome {
+  readonly callEventId: string;
+  readonly toolCallId: string;
+  readonly toolName: string;
+  readonly operationId: string;
+}
+
+export type PriorUnknownToolOutcomeProjection =
+  | { readonly kind: 'none' }
+  | { readonly kind: 'blocked'; readonly reason: string }
+  | {
+      readonly kind: 'projected';
+      readonly outcomes: readonly PriorUnknownToolOutcome[];
+      readonly systemNotice: string;
+    };
+
+/**
+ * Admit only sealed T1-without-T2 facts for a manual fresh message. The
+ * synthetic tool response is request-local; it is never appended to the event
+ * ledger and must not be mistaken for evidence that the tool settled.
+ */
+export function inspectPriorUnknownToolOutcomes(
+  events: readonly RuntimeEvent[],
+  invocations: readonly RuntimeInvocationRecord[] | undefined,
+): PriorUnknownToolOutcomeProjection {
+  const eventsByInvocationId = new Map<string, RuntimeEvent[]>();
+  for (const event of events) {
+    const invocationEvents = eventsByInvocationId.get(event.invocationId) ?? [];
+    invocationEvents.push(event);
+    eventsByInvocationId.set(event.invocationId, invocationEvents);
+  }
+  const indeterminate = [];
+  for (const invocationEvents of eventsByInvocationId.values()) {
+    const recovery = resolveRuntimeRecovery(invocationEvents);
+    if (recovery.hasCorruption) {
+      return { kind: 'blocked', reason: 'prior tool history is corrupt' };
+    }
+    indeterminate.push(
+      ...recovery.decisions.filter((decision) => decision.status === 'indeterminate'),
+    );
+  }
+  if (indeterminate.length === 0) return { kind: 'none' };
+  if (
+    indeterminate.some(
+      (decision) =>
+        decision.reason !== 'dispatch_without_response' ||
+        !decision.operationId ||
+        !decision.callRuntimeEventId ||
+        !decision.dispatchRuntimeEventId,
+    )
+  ) {
+    return { kind: 'blocked', reason: 'prior tool outcome is not a sealed dispatched operation' };
+  }
+
+  const eventsById = new Map(events.map((event) => [event.id, event] as const));
+  const invocationById = new Map(
+    (invocations ?? []).map((run) => [run.invocationId, run] as const),
+  );
+  const outcomes: PriorUnknownToolOutcome[] = [];
+  for (const decision of indeterminate) {
+    const callEvent = eventsById.get(decision.callRuntimeEventId!);
+    const dispatchEvent = eventsById.get(decision.dispatchRuntimeEventId!);
+    const call = callEvent?.content;
+    const invocation = callEvent ? invocationById.get(callEvent.invocationId) : undefined;
+    const dispatch = dispatchEvent?.actions?.toolDispatch;
+    if (
+      !callEvent ||
+      call?.kind !== 'function_call' ||
+      !dispatch ||
+      dispatchEvent.invocationId !== callEvent.invocationId ||
+      dispatch.operationId !== decision.operationId ||
+      dispatch.providerToolCallId !== call.id ||
+      dispatch.toolName !== call.name ||
+      !decision.operationId ||
+      !invocation?.terminalEvent ||
+      invocation.sessionId !== callEvent.sessionId ||
+      invocation.runId !== callEvent.runId ||
+      invocation.turnId !== callEvent.turnId ||
+      invocation.terminalEvent.sessionId !== callEvent.sessionId ||
+      invocation.terminalEvent.runId !== callEvent.runId ||
+      invocation.terminalEvent.turnId !== callEvent.turnId ||
+      invocation.terminalEvent.invocationId !== callEvent.invocationId ||
+      !isTerminalRuntimeEvent(invocation.terminalEvent) ||
+      invocation.terminalEvent.status !== 'failed' ||
+      runtimeInvocationFailureClass(invocation) !== 'outcome_unknown'
+    ) {
+      return { kind: 'blocked', reason: 'prior unknown tool outcome has no sealed invocation' };
+    }
+    // Hidden nested operations are an implementation detail of their parent
+    // tool. Validate their durable boundary above, but never surface their
+    // names or operation identities in model-visible request context.
+    if (callEvent.modelVisibility === 'hidden') continue;
+    outcomes.push({
+      callEventId: callEvent.id,
+      toolCallId: call.id,
+      toolName: call.name,
+      operationId: decision.operationId,
+    });
+  }
+  if (outcomes.length === 0) return { kind: 'none' };
+
+  const rows = outcomes
+    .slice(0, 64)
+    .map((outcome) => `- ${outcome.toolName} (operation ${outcome.operationId})`);
+  if (outcomes.length > 64) rows.push(`- and ${outcomes.length - 64} more unknown operations`);
+  return {
+    kind: 'projected',
+    outcomes,
+    systemNotice: [
+      'A prior execution was interrupted after these tools were dispatched. No durable tool results were recorded; their side effects may or may not have happened.',
+      'The outcome_unknown tool responses in history are temporary context, not proof of success or failure. Inspect current state before repeating any action.',
+      ...rows,
+    ].join('\n'),
+  };
+}
+
+/** Insert request-only tool responses beside their calls so provider history stays well-formed. */
+export function appendPriorUnknownToolResponses(
+  events: readonly RuntimeEvent[],
+  projection: Extract<PriorUnknownToolOutcomeProjection, { kind: 'projected' }>,
+): RuntimeEvent[] {
+  const byCallEventId = new Map(
+    projection.outcomes.map((outcome) => [outcome.callEventId, outcome] as const),
+  );
+  const projected: RuntimeEvent[] = [];
+  for (const event of events) {
+    projected.push(event);
+    const outcome = byCallEventId.get(event.id);
+    const call = event.content;
+    if (!outcome || call?.kind !== 'function_call') continue;
+    projected.push({
+      id: `model-projection:outcome-unknown:${event.id}`,
+      invocationId: event.invocationId,
+      runId: event.runId,
+      sessionId: event.sessionId,
+      turnId: event.turnId,
+      ts: event.ts,
+      partial: false,
+      role: 'tool',
+      author: 'tool',
+      origin: event.origin ?? 'provider',
+      modelVisibility: event.modelVisibility ?? 'visible',
+      content: {
+        kind: 'function_response',
+        id: call.id,
+        name: call.name,
+        result: {
+          kind: 'text',
+          text: `outcome_unknown: ${call.name} was dispatched, but no durable result was recorded. Its effect may have happened. Inspect current state before deciding whether to repeat it.`,
+          uncertainOutcome: { code: 'outcome_unknown', retrySafe: false },
+        },
+        isError: true,
+      },
+      refs: {
+        operationId: outcome.operationId,
+        toolCallId: call.id,
+        ...(event.refs?.parentToolCallId ? { parentToolCallId: event.refs.parentToolCallId } : {}),
+        ...(event.refs?.parentOperationId
+          ? { parentOperationId: event.refs.parentOperationId }
+          : {}),
+      },
+    });
+  }
+  return projected;
+}
+
 /**
  * Resolve the RuntimeEvents whose provider-owned reasoning may cross the
  * current provider boundary.
diff --git a/packages/runtime/src/recovery-resolver.ts b/packages/runtime/src/recovery-resolver.ts
index a989c4ee87..23b8c4ea3d 100644
--- a/packages/runtime/src/recovery-resolver.ts
+++ b/packages/runtime/src/recovery-resolver.ts
@@ -19,7 +19,6 @@
 
 import {
   TOOL_BOUNDARY_PROTOCOL_V1,
-  isTerminalRuntimeEvent,
   type RuntimeEvent,
   type ToolBoundaryProtocol,
 } from '@maka/core/runtime-event';
@@ -29,9 +28,6 @@ import {
   type ToolLedgerScanOperation,
 } from '@maka/core/tool-ledger-scanner';
 import { interpretScannedToolRecovery } from '@maka/core/tool-recovery-bundle';
-import type { ToolOutcomeCommit } from './runtime-commit-sink.js';
-import type { ToolMode } from '@maka/core/tool-mode';
-import { compatibilityToolResultProjection } from './durable-tool-result-projection.js';
 
 export type ToolRecoveryDecisionStatus =
   | 'completed'
@@ -125,105 +121,6 @@ export function resolveRuntimeRecovery(events: readonly RuntimeEvent[]): Runtime
   };
 }
 
-export function buildInterruptedToolOutcomeCommits(
-  events: readonly RuntimeEvent[],
-  now: number,
-  toolMode: ToolMode,
-): ToolOutcomeCommit[] {
-  const eventsById = new Map(events.map((event) => [event.id, event] as const));
-  const terminalInvocations = new Set(
-    events.filter(isTerminalRuntimeEvent).map((event) => event.invocationId),
-  );
-  const recovery = resolveRuntimeRecovery(events);
-  if (recovery.hasCorruption) return [];
-  return recovery.decisions.flatMap((decision) => {
-    if (
-      decision.status !== 'indeterminate' ||
-      decision.reason !== 'dispatch_without_response' ||
-      !decision.operationId ||
-      !decision.callRuntimeEventId
-    ) {
-      return [];
-    }
-    const callEvent = eventsById.get(decision.callRuntimeEventId);
-    const call = callEvent?.content;
-    if (!callEvent || call?.kind !== 'function_call') {
-      return [];
-    }
-    // A sealed invocation cannot accept new RuntimeEvents. Legacy sessions can
-    // still contain this gap; their projection is repaired from the terminal
-    // fact instead of appending a result after the immutable tail.
-    if (terminalInvocations.has(callEvent.invocationId)) return [];
-
-    const codeModeExec =
-      toolMode === 'code_mode' &&
-      call.name === 'exec' &&
-      callEvent.origin !== 'code_mode' &&
-      callEvent.modelVisibility !== 'hidden';
-    const interaction = call.name === 'AskUserQuestion';
-    const result = codeModeExec
-      ? {
-          kind: 'json' as const,
-          value: {
-            kind: 'code_mode' as const,
-            status: 'interrupted' as const,
-            message:
-              'Code Mode execution was interrupted by runtime recovery. Its side effects may or may not have occurred; do not retry it immediately. Inspect the current state first.',
-            uncertainOutcome: { code: 'outcome_unknown' as const, retrySafe: false as const },
-          },
-        }
-      : {
-          kind: 'text' as const,
-          text: interaction
-            ? 'This question was interrupted by runtime recovery before an answer was submitted.'
-            : `Tool ${call.name} was interrupted before its result was committed. Its side effects may or may not have occurred. Do not retry it immediately; inspect the current state first.`,
-          ...(!interaction
-            ? { uncertainOutcome: { code: 'outcome_unknown' as const, retrySafe: false as const } }
-            : {}),
-        };
-    const responseContent = {
-      kind: 'function_response' as const,
-      id: call.id,
-      name: call.name,
-      result,
-      isError: true as const,
-    };
-    const modelProjection = compatibilityToolResultProjection(responseContent, callEvent.sessionId);
-    const runtimeEvent: RuntimeEvent = {
-      id: `${decision.operationId}_response`,
-      invocationId: callEvent.invocationId,
-      runId: callEvent.runId,
-      sessionId: callEvent.sessionId,
-      turnId: callEvent.turnId,
-      ts: now,
-      partial: false,
-      role: 'tool',
-      author: 'tool',
-      origin: callEvent.origin ?? 'provider',
-      modelVisibility: callEvent.modelVisibility ?? 'visible',
-      content: { ...responseContent, ...(modelProjection ? { modelProjection } : {}) },
-      refs: {
-        operationId: decision.operationId,
-        toolCallId: call.id,
-        ...(callEvent.refs?.parentToolCallId
-          ? { parentToolCallId: callEvent.refs.parentToolCallId }
-          : {}),
-        ...(callEvent.refs?.parentOperationId
-          ? { parentOperationId: callEvent.refs.parentOperationId }
-          : {}),
-      },
-    };
-    return [
-      {
-        operationId: decision.operationId,
-        journalEventId: `${decision.operationId}_outcome`,
-        runtimeEvent,
-        committedAt: now,
-      },
-    ];
-  });
-}
-
 function decisionFromOperation(
   operation: ToolLedgerScanOperation,
   toolBoundaryProtocol: ToolBoundaryProtocol | undefined,
diff --git a/packages/runtime/src/runtime-kernel.ts b/packages/runtime/src/runtime-kernel.ts
index a5de4ddedf..c926f5af44 100644
--- a/packages/runtime/src/runtime-kernel.ts
+++ b/packages/runtime/src/runtime-kernel.ts
@@ -724,6 +724,7 @@ export class RuntimeKernel implements RuntimeKernelLike {
       this.attachExecutionClaim(execution, run);
       yield* this.runAgentTurn(sessionId, run, execution, {
         steering: true,
+        allowPriorUnknownToolOutcomes: isExplicitClientMessage(input),
         onRunStarted: options.onRunStarted,
         initialHeader: header,
       });
@@ -1325,6 +1326,7 @@ export class RuntimeKernel implements RuntimeKernelLike {
     execution: PendingExecutionClaim,
     options: {
       steering?: boolean;
+      allowPriorUnknownToolOutcomes?: boolean;
       onRunStarted?: (runId: string, initialHeader: SessionHeader) => void | Promise<void>;
       initialHeader?: SessionHeader;
       prepareBackendActivation?: () => Promise<void>;
@@ -1376,6 +1378,7 @@ export class RuntimeKernel implements RuntimeKernelLike {
         invocationId: begin.initialRuntimeEvent.invocationId,
         runId: run.runId,
         ...begin.backendInput,
+        ...(options.allowPriorUnknownToolOutcomes ? { allowPriorUnknownToolOutcomes: true } : {}),
         headAnchorRuntimeEvent: begin.initialRuntimeEvent,
         handoffBoundary: (signal, remainingSteps) =>
           run.reachHandoffBoundary(signal, remainingSteps),
@@ -3539,6 +3542,19 @@ function assertNoRemovedChildAgentRunLineage(input: UserMessageInput): void {
   }
 }
 
+function isExplicitClientMessage(input: UserMessageInput): boolean {
+  return (
+    input.origin === undefined &&
+    input.agentId === undefined &&
+    input.agentName === undefined &&
+    input.parentSessionId === undefined &&
+    input.parentTurnId === undefined &&
+    input.retriedFromTurnId === undefined &&
+    input.regeneratedFromTurnId === undefined &&
+    input.branchOfTurnId === undefined
+  );
+}
+
 async function interactionResumeAllowed(
   interactionRun: RuntimeInteractionRunBinding | undefined,
   event: SessionEvent,
diff --git a/packages/runtime/src/session-manager.ts b/packages/runtime/src/session-manager.ts
index 40b020fc83..4dd371e31f 100644
--- a/packages/runtime/src/session-manager.ts
+++ b/packages/runtime/src/session-manager.ts
@@ -187,13 +187,12 @@ import type { HistoryCompactCheckpoint } from './history-compact-checkpoint.js';
 import type { ModelProjectionTransition } from '@maka/core/model-projection-transition';
 import type { LoadedModelProjectionTransitions } from './model-projection-transition-ledger.js';
 import type { RuntimeContinuationFailpoint } from './agent-run.js';
-import type { RuntimeCommitResult, RuntimeCommitSink } from './runtime-commit-sink.js';
 import {
   attributeSandboxBoundaryRestartClosure,
   classifyAgentRunRecovery,
   type AgentRunRecoveryDecision,
 } from './agent-run-recovery.js';
-import { buildInterruptedToolOutcomeCommits, resolveRuntimeRecovery } from './recovery-resolver.js';
+import { resolveRuntimeRecovery } from './recovery-resolver.js';
 import {
   isRuntimeHostedRootAuthority,
   RuntimeMessageAuthorityInvariantError,
@@ -259,16 +258,6 @@ function runtimeContinuationAuthority(
     : undefined;
 }
 
-function runtimeCommitSinkFromEventStore(
-  store: RuntimeEventStore | undefined,
-): RuntimeCommitSink | undefined {
-  const candidate = store as Partial<RuntimeCommitSink> | undefined;
-  return typeof candidate?.commitToolPrepared === 'function' &&
-    typeof candidate.commitToolOutcome === 'function'
-    ? (candidate as RuntimeCommitSink)
-    : undefined;
-}
-
 export type StopSessionInput =
   | {
       source?: 'stop_button' | 'graph_supervisor';
@@ -814,7 +803,6 @@ interface SessionManagerBaseDeps {
   planStore?: PlanStore;
   runStore?: AgentRunStore;
   runtimeEventStore?: RuntimeEventStore;
-  runtimeCommitSink?: RuntimeCommitSink;
   /** Host capability; RuntimeKernel gates it by the selected backend. */
   toolBoundaryProtocol?: ToolBoundaryProtocol;
   backends: BackendRegistry;
@@ -908,7 +896,6 @@ export class SessionManager {
   private readonly runtimeKernel: RuntimeKernelLike;
   private readonly runtimeLedgerRepair?: RuntimeLedgerRepair;
   private readonly preparedTranscriptLedgers = new Set<string>();
-  private readonly runtimeCommitSink?: RuntimeCommitSink;
   private readonly activeHostedLinkedChildSessions = new Set<string>();
   private readonly childSessionSpawns = new Map<
     string,
@@ -927,8 +914,6 @@ export class SessionManager {
     if (deps.publishChildWorkspacePatch && !deps.listArtifactsForTurn) {
       throw new Error('Child workspace patch publication requires Artifact turn listing');
     }
-    this.runtimeCommitSink =
-      deps.runtimeCommitSink ?? runtimeCommitSinkFromEventStore(deps.runtimeEventStore);
     if (deps.runStore && deps.runtimeEventStore) {
       this.runtimeLedgerRepair = new RuntimeLedgerRepair({
         runtimeEventStore: deps.runtimeEventStore,
@@ -4855,51 +4840,24 @@ export class SessionManager {
         // T1 states; generic app-restart repair must never write into them.
         continue;
       }
-      if (this.runtimeCommitSink) {
-        const interruptedOutcomes = buildInterruptedToolOutcomeCommits(
-          inspected.runtimeEvents,
-          this.deps.now(),
-          run.opening.configuration.toolMode,
-        );
-        let outcomeCommitFailed = false;
-        for (const outcome of interruptedOutcomes) {
-          const committed = await commitInterruptedOutcomeWithRetry(policy, () =>
-            this.runtimeCommitSink!.commitToolOutcome(outcome),
-          );
-          if (!committed) {
-            // Keep the run non-terminal so a later recovery pass can retry the
-            // missing outcome before any terminal repair seals the ledger.
-            outcomeCommitFailed = true;
-          } else {
-            recovered ||= committed.created;
-          }
-        }
-        if (outcomeCommitFailed) {
-          continue;
-        }
-        if (interruptedOutcomes.length > 0) {
-          inspected = await inspectAgentRunReadModel(
-            recoveryRunStore,
-            this.deps.runtimeEventStore,
-            {
-              sessionId,
-              runId: run.runId,
-              invocation: run,
-              includeModelReplay: false,
-              includeProjection: false,
-            },
-          );
-        }
-      }
+      let unknownDispatchedTools: { toolCallId: string; toolName?: string }[] = [];
       if (!inspected.runtimeEvents.some(isTerminalRuntimeEvent)) {
         const toolRecovery = resolveRuntimeRecovery(inspected.runtimeEvents);
+        const indeterminate = toolRecovery.decisions.filter(
+          (decision) => decision.status === 'indeterminate',
+        );
+        unknownDispatchedTools = indeterminate
+          .filter((decision) => decision.reason === 'dispatch_without_response')
+          .map(({ toolCallId, toolName }) => ({
+            toolCallId,
+            ...(toolName ? { toolName } : {}),
+          }));
         if (
           toolRecovery.hasCorruption ||
-          toolRecovery.decisions.some((decision) => decision.status === 'indeterminate')
+          (indeterminate.length > 0 && unknownDispatchedTools.length !== indeterminate.length)
         ) {
-          // Never seal an invocation while a dispatched operation still lacks
-          // a result or an explicit recovery decision. A later recovery pass
-          // may retry the durable settlement; corruption stays fail-closed.
+          // Only a structurally valid T1-without-T2 boundary can be sealed as
+          // unknown. Legacy gaps and corrupt recovery facts still fail closed.
           continue;
         }
       }
@@ -4915,10 +4873,25 @@ export class SessionManager {
       const runtimeDecision = this.classifyRuntimeEventRecovery(inspected);
       const classified = runtimeDecision ?? classifyAgentRunRecovery(run, inspected.events);
       if (!classified) continue;
-      const decision =
+      let decision =
         classified.status === 'failed'
           ? attributeSandboxBoundaryRestartClosure(classified, await readBoundaryClosures())
           : classified;
+      if (unknownDispatchedTools.length > 0) {
+        decision = {
+          ...decision,
+          status: 'failed',
+          failureClass: 'outcome_unknown',
+          diagnostic: {
+            ...decision.diagnostic,
+            recoveryReason: 'outcome_unknown',
+            unresolvedToolCalls: unknownDispatchedTools.map(({ toolCallId, toolName }) => ({
+              toolCallId,
+              ...(toolName ? { toolName } : {}),
+            })),
+          },
+        };
+      }
       if (await this.applyAgentRunRecovery(sessionId, decision, inspected, policy)) {
         recovered = true;
       }
@@ -5030,8 +5003,6 @@ function groupContinuationClaimsBySession(
   return grouped;
 }
 
-const MAX_BEST_EFFORT_OUTCOME_COMMIT_ATTEMPTS = 2;
-
 function listSessionsForRecovery(
   store: SessionStore,
   policy: RecoveryPolicy,
@@ -5052,21 +5023,6 @@ async function recoverOr<T>(
   }
 }
 
-async function commitInterruptedOutcomeWithRetry(
-  policy: RecoveryPolicy,
-  operation: () => Promise<RuntimeCommitResult>,
-): Promise<RuntimeCommitResult | undefined> {
-  const attempts = policy.kind === 'strict' ? 1 : MAX_BEST_EFFORT_OUTCOME_COMMIT_ATTEMPTS;
-  for (let attempt = 0; attempt < attempts; attempt += 1) {
-    try {
-      return await operation();
-    } catch (error) {
-      if (policy.kind === 'strict') throw error;
-    }
-  }
-  return undefined;
-}
-
 function continuationRepairEventId(
   kind: 'start' | 'terminal' | 'run-terminal',
   claimId: string,


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org