@deepstrike/sdk 0.2.39 → 0.2.41

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 (102) hide show
  1. package/README.md +64 -34
  2. package/dist/collaboration/contract.d.ts +2 -2
  3. package/dist/collaboration/contract.js +2 -2
  4. package/dist/collaboration/handoff.d.ts +2 -14
  5. package/dist/collaboration/handoff.js +1 -17
  6. package/dist/collaboration/harness.d.ts +16 -47
  7. package/dist/collaboration/harness.js +57 -158
  8. package/dist/collaboration/index.d.ts +2 -2
  9. package/dist/collaboration/index.js +1 -2
  10. package/dist/collaboration/modes/creator-verifier.js +42 -6
  11. package/dist/collaboration/pool.d.ts +8 -0
  12. package/dist/collaboration/pool.js +56 -3
  13. package/dist/harness/harness.d.ts +97 -97
  14. package/dist/harness/harness.js +190 -144
  15. package/dist/harness/judge.d.ts +3 -2
  16. package/dist/harness/judge.js +7 -3
  17. package/dist/harness/public.d.ts +5 -3
  18. package/dist/harness/public.js +3 -2
  19. package/dist/index.d.ts +22 -7
  20. package/dist/index.js +8 -1
  21. package/dist/kernel.d.ts +12 -39
  22. package/dist/memory/agent.d.ts +8 -41
  23. package/dist/memory/agent.js +34 -117
  24. package/dist/memory/extraction.d.ts +4 -0
  25. package/dist/memory/extraction.js +79 -0
  26. package/dist/memory/in-memory-store.d.ts +28 -15
  27. package/dist/memory/in-memory-store.js +74 -25
  28. package/dist/memory/protocols.d.ts +56 -56
  29. package/dist/memory/protocols.js +1 -0
  30. package/dist/memory/public.d.ts +6 -1
  31. package/dist/memory/public.js +3 -0
  32. package/dist/memory/ranking.d.ts +32 -0
  33. package/dist/memory/ranking.js +77 -0
  34. package/dist/memory/retention.d.ts +17 -0
  35. package/dist/memory/retention.js +54 -0
  36. package/dist/os/public.d.ts +5 -4
  37. package/dist/os/public.js +2 -1
  38. package/dist/providers/base.d.ts +8 -0
  39. package/dist/providers/base.js +0 -0
  40. package/dist/providers/gemini.js +12 -0
  41. package/dist/providers/ollama.js +3 -1
  42. package/dist/providers/openai-responses.js +9 -2
  43. package/dist/providers/profiles.d.ts +5 -3
  44. package/dist/providers/profiles.js +3 -3
  45. package/dist/runtime/context-policy.d.ts +35 -0
  46. package/dist/runtime/context-policy.js +66 -0
  47. package/dist/runtime/eval.d.ts +6 -2
  48. package/dist/runtime/eval.js +2 -2
  49. package/dist/runtime/event-stream.d.ts +9 -0
  50. package/dist/runtime/event-stream.js +25 -11
  51. package/dist/runtime/execution-plane.d.ts +5 -1
  52. package/dist/runtime/execution-plane.js +9 -3
  53. package/dist/runtime/facade.js +2 -1
  54. package/dist/runtime/kernel-event-log.d.ts +0 -2
  55. package/dist/runtime/kernel-event-log.js +61 -13
  56. package/dist/runtime/kernel-primitives-dashboard.js +1 -1
  57. package/dist/runtime/kernel-rebuild.d.ts +13 -0
  58. package/dist/runtime/kernel-rebuild.js +75 -0
  59. package/dist/runtime/kernel-step.d.ts +157 -8
  60. package/dist/runtime/kernel-step.js +220 -7
  61. package/dist/runtime/kernel-transaction-log.d.ts +61 -0
  62. package/dist/runtime/kernel-transaction-log.js +149 -0
  63. package/dist/runtime/large-result-spool.d.ts +3 -1
  64. package/dist/runtime/large-result-spool.js +24 -5
  65. package/dist/runtime/loop-driver.d.ts +1 -1
  66. package/dist/runtime/loop-driver.js +2 -7
  67. package/dist/runtime/mcp-proxy-plane.d.ts +1 -0
  68. package/dist/runtime/mcp-proxy-plane.js +23 -6
  69. package/dist/runtime/os-profile.d.ts +9 -10
  70. package/dist/runtime/os-profile.js +14 -10
  71. package/dist/runtime/os-snapshot.d.ts +19 -0
  72. package/dist/runtime/os-snapshot.js +33 -3
  73. package/dist/runtime/process-sandbox-plane.js +16 -11
  74. package/dist/runtime/reaction-checkpoint.d.ts +51 -0
  75. package/dist/runtime/reaction-checkpoint.js +83 -0
  76. package/dist/runtime/reactive-session.d.ts +9 -3
  77. package/dist/runtime/reactive-session.js +44 -14
  78. package/dist/runtime/reliability.d.ts +48 -0
  79. package/dist/runtime/reliability.js +86 -0
  80. package/dist/runtime/remote-vpc-plane.js +4 -3
  81. package/dist/runtime/run-group.d.ts +38 -35
  82. package/dist/runtime/run-group.js +97 -54
  83. package/dist/runtime/runner.d.ts +117 -78
  84. package/dist/runtime/runner.js +1516 -1197
  85. package/dist/runtime/session-log.d.ts +71 -12
  86. package/dist/runtime/session-log.js +192 -32
  87. package/dist/runtime/session-repair.d.ts +11 -7
  88. package/dist/runtime/session-repair.js +11 -8
  89. package/dist/runtime/sub-agent-orchestrator.d.ts +6 -2
  90. package/dist/runtime/sub-agent-orchestrator.js +45 -18
  91. package/dist/signals/gateway.d.ts +23 -10
  92. package/dist/signals/gateway.js +81 -17
  93. package/dist/signals/scheduled.js +0 -1
  94. package/dist/signals/types.d.ts +21 -13
  95. package/dist/skills/loader.js +12 -2
  96. package/dist/tools/index.d.ts +2 -0
  97. package/dist/types/agent.d.ts +40 -1
  98. package/dist/types/agent.js +61 -1
  99. package/dist/types.d.ts +6 -1
  100. package/dist/workflow/public.d.ts +2 -3
  101. package/dist/workflow/public.js +0 -1
  102. package/package.json +2 -2
@@ -4,10 +4,10 @@
4
4
  * Wraps the three kernel free functions `buildEvalMessages` / `parseVerdict` / `verdictOutputSchema`
5
5
  * (folded out of the old EvalPipeline class in 0.5.0) into a small typed surface that's safe to
6
6
  * call from a benchmark harness, a CI gate, or any caller that just wants "does this result meet
7
- * the criteria?" without setting up `HarnessLoop`.
7
+ * the criteria?" without setting up `AttemptLoop`.
8
8
  *
9
9
  * The judge is a single LLM call: build the eval prompt → stream → parse verdict. No retry loop,
10
- * no skill extraction, no harness state. Use `HarnessLoop` if you want the retry/refine flow.
10
+ * no skill extraction, no loop state. Use `AttemptLoop` if you want the retry/refine flow.
11
11
  */
12
12
  import type { LLMProvider, Message } from "../types.js";
13
13
  export interface Criterion {
@@ -17,6 +17,10 @@ export interface Criterion {
17
17
  required?: boolean;
18
18
  /** Optional weight for weighted scoring (kernel-defined semantics). */
19
19
  weight?: number;
20
+ /** Stable host contract identifier, passed through to deterministic judges. */
21
+ id?: string;
22
+ /** Signals that the host can evaluate this criterion without an LLM. */
23
+ machineCheckable?: boolean;
20
24
  }
21
25
  export interface VerdictDetail {
22
26
  criterion: string;
@@ -4,10 +4,10 @@
4
4
  * Wraps the three kernel free functions `buildEvalMessages` / `parseVerdict` / `verdictOutputSchema`
5
5
  * (folded out of the old EvalPipeline class in 0.5.0) into a small typed surface that's safe to
6
6
  * call from a benchmark harness, a CI gate, or any caller that just wants "does this result meet
7
- * the criteria?" without setting up `HarnessLoop`.
7
+ * the criteria?" without setting up `AttemptLoop`.
8
8
  *
9
9
  * The judge is a single LLM call: build the eval prompt → stream → parse verdict. No retry loop,
10
- * no skill extraction, no harness state. Use `HarnessLoop` if you want the retry/refine flow.
10
+ * no skill extraction, no loop state. Use `AttemptLoop` if you want the retry/refine flow.
11
11
  */
12
12
  import { getKernel } from "../kernel.js";
13
13
  /**
@@ -7,10 +7,16 @@
7
7
  * event to a subset of personas, enforced at the framework boundary (`readSince(seq, viewer)` + the
8
8
  * `read_recent` tool) — context isolation, not convention.
9
9
  */
10
+ import type { ObserverErrorHandler } from "./reliability.js";
11
+ export interface EventStreamOptions {
12
+ onObserverError?: ObserverErrorHandler;
13
+ }
10
14
  /** One entry on the shared blackboard. `channel`/`audience` are optional visibility scoping. */
11
15
  export interface BlackboardEvent {
12
16
  seq: number;
13
17
  payload: unknown;
18
+ /** Stable external event key. Re-appending the same key returns the original event. */
19
+ idempotencyKey?: string;
14
20
  /** Emitting persona id (or external source), for audit / `reactByMention`. */
15
21
  source?: string;
16
22
  /** Channel this event belongs to; only personas subscribed to it see it. Omit ⇒ all see it. */
@@ -36,8 +42,11 @@ export interface EventStream {
36
42
  }
37
43
  /** Process-local default blackboard. */
38
44
  export declare class InMemoryEventStream implements EventStream {
45
+ private readonly opts;
39
46
  private readonly events;
47
+ private readonly idempotentEvents;
40
48
  private readonly listeners;
49
+ constructor(opts?: EventStreamOptions);
41
50
  append(event: Omit<BlackboardEvent, "seq">): Promise<BlackboardEvent>;
42
51
  readSince(seq: number, viewer?: EventViewer): Promise<BlackboardEvent[]>;
43
52
  subscribe(cb: (e: BlackboardEvent) => void): () => void;
@@ -1,12 +1,4 @@
1
- /**
2
- * L2 (Blackboard) — a shared, append-only event stream that N peer agent sessions of one logical run
3
- * observe. This is the pluggable storage seam (like `SessionLog`): the default `InMemoryEventStream`
4
- * is process-local; back it with Postgres/Redis to span replicas/restarts.
5
- *
6
- * Visibility (spec §6.1): events are shared by default. Optional `channel` / `audience` tags scope an
7
- * event to a subset of personas, enforced at the framework boundary (`readSince(seq, viewer)` + the
8
- * `read_recent` tool) — context isolation, not convention.
9
- */
1
+ import { reportObserverFailure } from "./reliability.js";
10
2
  /** Default full-share visibility rule (spec §6.1). */
11
3
  export function isVisibleTo(event, viewer) {
12
4
  if (event.audience === undefined && event.channel === undefined)
@@ -19,13 +11,35 @@ export function isVisibleTo(event, viewer) {
19
11
  }
20
12
  /** Process-local default blackboard. */
21
13
  export class InMemoryEventStream {
14
+ opts;
22
15
  events = [];
16
+ idempotentEvents = new Map();
23
17
  listeners = new Set();
18
+ constructor(opts = {}) {
19
+ this.opts = opts;
20
+ }
24
21
  async append(event) {
22
+ if (event.idempotencyKey) {
23
+ const existing = this.idempotentEvents.get(event.idempotencyKey);
24
+ if (existing)
25
+ return existing;
26
+ }
25
27
  const stamped = { ...event, seq: this.events.length };
26
28
  this.events.push(stamped);
27
- for (const l of this.listeners)
28
- l(stamped);
29
+ if (stamped.idempotencyKey)
30
+ this.idempotentEvents.set(stamped.idempotencyKey, stamped);
31
+ for (const listener of this.listeners) {
32
+ try {
33
+ listener(stamped);
34
+ }
35
+ catch (cause) {
36
+ reportObserverFailure(this.opts.onObserverError, {
37
+ component: "InMemoryEventStream",
38
+ operation: "event_stream_listener",
39
+ cause,
40
+ });
41
+ }
42
+ }
29
43
  return stamped;
30
44
  }
31
45
  async readSince(seq, viewer) {
@@ -1,10 +1,14 @@
1
1
  import type { ToolCall, ToolSchema, StreamEvent, ToolSuspendEvent, PermissionRequestEvent, PermissionResponse } from "../types.js";
2
2
  import type { RegisteredTool } from "../tools/index.js";
3
- import type { DreamStore } from "../memory/protocols.js";
3
+ import type { DreamStore, MemoryScope } from "../memory/protocols.js";
4
4
  import type { KnowledgeSource } from "../knowledge/source.js";
5
5
  import { LargeResultSpool } from "./large-result-spool.js";
6
+ import type { OperationContext } from "./reliability.js";
6
7
  export interface RunContext {
8
+ /** Immutable identity, deadline, and cancellation boundary for this operation. */
9
+ operation?: OperationContext;
7
10
  agentId?: string;
11
+ memoryScope?: MemoryScope;
8
12
  skillDir?: string;
9
13
  dreamStore?: DreamStore;
10
14
  knowledgeSource?: KnowledgeSource;
@@ -30,11 +30,16 @@ export class LocalExecutionPlane {
30
30
  for (const c of memoryCalls) {
31
31
  const args = tryParseJson(c.arguments);
32
32
  const topK = typeof args?.top_k === "number" ? args.top_k : 5;
33
- const entries = (ctx.dreamStore && ctx.agentId)
34
- ? await ctx.dreamStore.search(ctx.agentId, String(args?.query ?? ""), topK)
33
+ const entries = (ctx.dreamStore && ctx.agentId && ctx.memoryScope)
34
+ ? await ctx.dreamStore.search(ctx.agentId, {
35
+ scope: ctx.memoryScope,
36
+ query: String(args?.query ?? ""),
37
+ top_k: topK,
38
+ kinds: [],
39
+ })
35
40
  : [];
36
41
  const content = entries.length
37
- ? entries.map((e) => `[score=${e.score.toFixed(3)}] ${e.text}`).join("\n---\n")
42
+ ? entries.map(e => `[memory record_id=${e.record.record_id} trust=${e.record.provenance.trust} score=${e.score.toFixed(3)}] ${e.record.content}`).join("\n---\n")
38
43
  : "No relevant memories found.";
39
44
  yield { type: "tool_result", callId: c.id, name: c.name, content, isError: false };
40
45
  }
@@ -107,6 +112,7 @@ export class LocalExecutionPlane {
107
112
  // best-effort failures recorded before the main throw.
108
113
  const auditFailures = [];
109
114
  const callCtx = {
115
+ ...(ctx.operation !== undefined ? { operation: ctx.operation } : {}),
110
116
  ...(ctx.cwd !== undefined ? { cwd: ctx.cwd } : {}),
111
117
  audit: async (label, fn) => {
112
118
  try {
@@ -62,7 +62,8 @@ export async function runFanout(opts) {
62
62
  // but fall back to the last completed node's output so a kernel id-scheme change can't silently
63
63
  // return an empty synthesis.
64
64
  const synthesisId = `wf-node${opts.tasks.length}`;
65
- const lastCompleted = outcome.completed[outcome.completed.length - 1];
65
+ const completed = outcome.nodeOutcomes.filter(node => node.status === "completed" || node.status === "completed_partial");
66
+ const lastCompleted = completed[completed.length - 1]?.nodeId;
66
67
  const synthesis = outcome.outputs[synthesisId] ?? (lastCompleted ? outcome.outputs[lastCompleted] : undefined) ?? "";
67
68
  return { synthesis, outputs: outcome.outputs };
68
69
  }
@@ -9,10 +9,8 @@ type CompressionAction = Extract<SessionEvent, {
9
9
  export declare function kernelObservationToSessionEvent(obs: KernelObservation, turn: number, opts?: {
10
10
  nextArchiveStart?: number;
11
11
  latestSeq?: number;
12
- archiveRef?: string;
13
12
  preservedRefs?: string[];
14
13
  compressionAction?: (action?: string) => CompressionAction;
15
- spoolRef?: string;
16
14
  }): SessionEvent | null;
17
15
  export type KernelPrimitive = "syscall" | "sched" | "mm";
18
16
  export declare function primitiveForCategory(category: KernelEventCategory): KernelPrimitive;
@@ -16,7 +16,7 @@ export function categoryForKind(kind) {
16
16
  return "mm";
17
17
  case "agent_process_changed":
18
18
  return "proc";
19
- case "signal_disposed":
19
+ case "signal_delivery_disposed":
20
20
  return "ipc";
21
21
  default:
22
22
  return "sched";
@@ -38,7 +38,6 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
38
38
  action: compressionAction(obs.action),
39
39
  summary: obs.summary,
40
40
  summary_tokens: obs.summary ? Math.max(1, Math.ceil(obs.summary.length / 4)) : undefined,
41
- archive_ref: opts.archiveRef,
42
41
  preserved_refs: opts.preservedRefs ?? [],
43
42
  };
44
43
  }
@@ -130,10 +129,13 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
130
129
  tool: obs.tool ?? "",
131
130
  reason: typeof obs.reason === "string" ? obs.reason : "",
132
131
  };
133
- case "signal_disposed":
132
+ case "signal_delivery_disposed":
134
133
  return {
135
- kind: "signal_disposed",
134
+ kind: "signal_delivery_disposed",
136
135
  turn: t,
136
+ operation_id: obs.operation_id ?? "",
137
+ delivery_id: obs.delivery_id ?? "",
138
+ attempt: obs.attempt ?? 0,
137
139
  signal_id: obs.signal_id ?? "",
138
140
  disposition: obs.disposition ?? "",
139
141
  queue_depth: obs.queue_depth ?? 0,
@@ -143,6 +145,26 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
143
145
  kind: "budget_exceeded",
144
146
  turn: t,
145
147
  budget: obs.budget ?? "",
148
+ operation_id: obs.operation_id ?? "",
149
+ ...(obs.reservation_id ? { reservation_id: obs.reservation_id } : {}),
150
+ };
151
+ case "budget_usage_reported":
152
+ return {
153
+ kind: "budget_usage_reported",
154
+ turn: t,
155
+ operation_id: obs.operation_id ?? "",
156
+ reservation_id: obs.reservation_id ?? "",
157
+ tokens: obs.tokens ?? 0,
158
+ subagents: obs.subagents ?? 0,
159
+ rounds: obs.rounds ?? 0,
160
+ };
161
+ case "operation_cancelled":
162
+ return {
163
+ kind: "operation_cancelled",
164
+ turn: t,
165
+ operation_id: obs.operation_id ?? "",
166
+ reason: (obs.reason ?? "user"),
167
+ pending_call_ids: obs.pending_call_ids ?? [],
146
168
  };
147
169
  case "suspended":
148
170
  return {
@@ -168,21 +190,34 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
168
190
  tool: obs.tool ?? "",
169
191
  original_size: obs.original_size ?? 0,
170
192
  preview_size: obs.preview_size ?? 0,
171
- spool_ref: opts.spoolRef,
193
+ spool_ref: obs.spool_ref,
194
+ };
195
+ case "page_out_archived":
196
+ return {
197
+ kind: "page_out",
198
+ turn: t,
199
+ action: compressionAction(obs.action),
200
+ summary: obs.summary,
201
+ tier_hint: obs.tier,
202
+ message_count: obs.message_count ?? 0,
203
+ archive_ref: obs.archive_ref,
172
204
  };
173
205
  case "memory_written":
174
206
  return {
175
207
  kind: "memory_written",
176
208
  turn: t,
177
- memory_id: obs.memory_id ?? "",
209
+ record_id: obs.record_id ?? "",
210
+ scope: obs.scope ?? { tenant_id: "", namespace: "" },
178
211
  memory_kind: obs.memory_kind ?? "",
212
+ name: obs.name ?? "",
179
213
  size_bytes: obs.size_bytes ?? 0,
180
214
  };
181
215
  case "memory_queried":
182
216
  return {
183
217
  kind: "memory_queried",
184
218
  turn: t,
185
- query_context: obs.query_context ?? "",
219
+ scope: obs.scope ?? { tenant_id: "", namespace: "" },
220
+ query: obs.query ?? "",
186
221
  requested_k: obs.requested_k ?? 0,
187
222
  requires_async_response: obs.requires_async_response ?? false,
188
223
  };
@@ -190,7 +225,22 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
190
225
  return {
191
226
  kind: "memory_validation_failed",
192
227
  turn: t,
193
- memory_id: obs.memory_id ?? "",
228
+ record_id: obs.record_id ?? "",
229
+ error: obs.error ?? "",
230
+ };
231
+ case "memory_write_failed":
232
+ return {
233
+ kind: "memory_write_failed",
234
+ turn: t,
235
+ record_id: obs.record_id ?? "",
236
+ error: obs.error ?? "",
237
+ };
238
+ case "memory_query_failed":
239
+ return {
240
+ kind: "memory_query_failed",
241
+ turn: t,
242
+ scope: obs.scope ?? { tenant_id: "", namespace: "" },
243
+ query: obs.query ?? "",
194
244
  error: obs.error ?? "",
195
245
  };
196
246
  case "workflow_batch_spawned": {
@@ -205,14 +255,12 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
205
255
  };
206
256
  }
207
257
  case "workflow_completed": {
208
- const completed = obs.completed ?? [];
209
- const failed = obs.failed ?? [];
258
+ const nodeOutcomes = obs.node_outcomes ?? [];
210
259
  return {
211
260
  kind: "workflow_completed",
212
261
  turn: t,
213
- completed,
214
- failed,
215
- total_nodes: completed.length + failed.length,
262
+ node_outcomes: nodeOutcomes,
263
+ total_nodes: nodeOutcomes.length,
216
264
  };
217
265
  }
218
266
  default:
@@ -54,7 +54,7 @@ export class KernelPrimitivesDashboard {
54
54
  else if (event.kind === "resumed") {
55
55
  this.stats.sched.resumedCount++;
56
56
  }
57
- else if (event.kind === "signal_disposed") {
57
+ else if (event.kind === "signal_delivery_disposed") {
58
58
  this.stats.sched.signalDisposedCount++;
59
59
  }
60
60
  else if (event.kind === "budget_exceeded") {
@@ -0,0 +1,13 @@
1
+ import type { KernelRuntimeHandle } from "./kernel-step.js";
2
+ import { type KernelOperationCursor, type KernelOperationGenesis, type KernelTransaction } from "./kernel-transaction-log.js";
3
+ export interface KernelRebuildResult {
4
+ runtime: KernelRuntimeHandle;
5
+ cursor: KernelOperationCursor;
6
+ }
7
+ /**
8
+ * Deterministically fold an authoritative operation stream into a fresh runtime.
9
+ *
10
+ * The caller owns runtime construction, but its initial policy and replay-affecting defaults must
11
+ * exactly match genesis. A failure leaves the supplied runtime unusable; callers must discard it.
12
+ */
13
+ export declare function rebuildKernelRuntime(runtime: KernelRuntimeHandle, genesis: KernelOperationGenesis, transactions: readonly KernelTransaction[]): KernelRebuildResult;
@@ -0,0 +1,75 @@
1
+ import { KernelLogIntegrityError, kernelRecordDigest, verifyKernelTransactionStream, } from "./kernel-transaction-log.js";
2
+ /**
3
+ * Deterministically fold an authoritative operation stream into a fresh runtime.
4
+ *
5
+ * The caller owns runtime construction, but its initial policy and replay-affecting defaults must
6
+ * exactly match genesis. A failure leaves the supplied runtime unusable; callers must discard it.
7
+ */
8
+ export function rebuildKernelRuntime(runtime, genesis, transactions) {
9
+ const cursor = verifyKernelTransactionStream(genesis, transactions);
10
+ assertFreshRuntimeMatchesGenesis(runtime, genesis);
11
+ for (const transaction of transactions) {
12
+ const prepared = JSON.parse(runtime.prepareStep(JSON.stringify(transaction.input)));
13
+ const token = prepared.prepare_token;
14
+ try {
15
+ if (prepared.status !== "prepared" || !token) {
16
+ throw new KernelLogIntegrityError(`kernel rebuild step ${transaction.step_seq} was not accepted as a new transition`);
17
+ }
18
+ if (prepared.base_generation !== transaction.base_generation) {
19
+ throw new KernelLogIntegrityError(`kernel rebuild generation ${prepared.base_generation} does not match transaction ${transaction.base_generation}`);
20
+ }
21
+ if (prepared.step.step_seq !== transaction.step_seq) {
22
+ throw new KernelLogIntegrityError(`kernel rebuild step_seq ${prepared.step.step_seq} does not match transaction ${transaction.step_seq}`);
23
+ }
24
+ if (kernelRecordDigest(prepared.input) !== transaction.input_digest) {
25
+ throw new KernelLogIntegrityError(`kernel rebuild normalized input diverged at step ${transaction.step_seq}`);
26
+ }
27
+ if (kernelRecordDigest(prepared.step) !== transaction.step_digest) {
28
+ throw new KernelLogIntegrityError(`kernel rebuild planned step diverged at step ${transaction.step_seq}`);
29
+ }
30
+ const committed = JSON.parse(runtime.commitPrepared(token));
31
+ if (kernelRecordDigest(committed) !== transaction.step_digest) {
32
+ throw new KernelLogIntegrityError(`kernel rebuild committed step diverged at step ${transaction.step_seq}`);
33
+ }
34
+ }
35
+ catch (error) {
36
+ if (token && prepared.status === "prepared") {
37
+ try {
38
+ runtime.abortPrepared(token);
39
+ }
40
+ catch {
41
+ // The caller must discard a failed rebuild runtime; preserve the primary integrity error.
42
+ }
43
+ }
44
+ throw error;
45
+ }
46
+ }
47
+ return { runtime, cursor };
48
+ }
49
+ function assertFreshRuntimeMatchesGenesis(runtime, genesis) {
50
+ const snapshot = JSON.parse(runtime.snapshot());
51
+ if (snapshot.abi_version !== genesis.abi_version) {
52
+ throw new KernelLogIntegrityError("kernel runtime ABI version does not match operation genesis");
53
+ }
54
+ if (genesis.default_policy_version !== 1) {
55
+ throw new KernelLogIntegrityError("kernel operation uses an unsupported default policy version");
56
+ }
57
+ if (snapshot.operation_id || snapshot.next_step_seq !== 1 || snapshot.accepted_inputs.length !== 0) {
58
+ throw new KernelLogIntegrityError("kernel rebuild requires a fresh runtime");
59
+ }
60
+ if (kernelRecordDigest(snapshot.initial_policy) !== kernelRecordDigest(genesis.initial_scheduler_policy)) {
61
+ throw new KernelLogIntegrityError("kernel runtime initial policy does not match operation genesis");
62
+ }
63
+ const defaults = resolvedRuntimeDefaults(snapshot);
64
+ if (kernelRecordDigest(defaults) !== kernelRecordDigest(genesis.resolved_runtime_defaults)) {
65
+ throw new KernelLogIntegrityError("kernel runtime defaults do not match operation genesis");
66
+ }
67
+ }
68
+ function resolvedRuntimeDefaults(snapshot) {
69
+ return {
70
+ snapshot_version: snapshot.snapshot_version,
71
+ snapshot_input_limit: snapshot.snapshot_input_limit,
72
+ max_input_bytes: snapshot.max_input_bytes,
73
+ snapshot_journal_bytes_limit: snapshot.snapshot_journal_bytes_limit,
74
+ };
75
+ }