@algosuite/vo-mcp 0.2.0-beta.58 → 0.2.0-beta.59

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.
@@ -3666,6 +3666,93 @@ var init_control_plane_knowledge_context = __esm({
3666
3666
  }
3667
3667
  });
3668
3668
 
3669
+ // ../../scripts/virtual-office/code-runner/control-plane-prepared-job.mjs
3670
+ function preparedJobQuery({ agent = "claude", env: env2 = {} } = {}) {
3671
+ const params = new URLSearchParams();
3672
+ params.set("agent", String(agent));
3673
+ const sent = [];
3674
+ const dropped = [];
3675
+ for (const key of PREPARED_JOB_ENV_QUERY_KEYS) {
3676
+ const raw = env2?.[key];
3677
+ if (typeof raw !== "string" || raw.length === 0) continue;
3678
+ if (raw.length > PREPARED_JOB_ENV_VALUE_MAX) {
3679
+ dropped.push(key);
3680
+ continue;
3681
+ }
3682
+ params.set(key, raw);
3683
+ sent.push(key);
3684
+ }
3685
+ return { query: params.toString(), sent, dropped };
3686
+ }
3687
+ async function refusalCode(res) {
3688
+ try {
3689
+ const body = await res.json();
3690
+ return typeof body?.error === "string" && body.error ? body.error : null;
3691
+ } catch {
3692
+ return null;
3693
+ }
3694
+ }
3695
+ async function getPreparedJobRequest(req, taskId, options = {}, invalidateToken = () => {
3696
+ }) {
3697
+ const { agent = "claude", env: env2 = {}, timeoutMs = 15e3 } = options;
3698
+ const { query, sent, dropped } = preparedJobQuery({ agent, env: env2 });
3699
+ const envMeta = { envSent: sent, envDropped: dropped };
3700
+ if (typeof taskId !== "string" || taskId.length === 0) {
3701
+ return { ok: false, reason: "missing_task_id", status: 0, ...envMeta };
3702
+ }
3703
+ const path22 = `/api/v1/code-task/${encodeURIComponent(taskId)}/prepared-job?${query}`;
3704
+ let res;
3705
+ try {
3706
+ res = await req("GET", path22, void 0, { timeoutMs });
3707
+ } catch (err) {
3708
+ return { ok: false, reason: `transport: ${err?.message || String(err)}`, status: 0, ...envMeta };
3709
+ }
3710
+ if (res?.status === 401) {
3711
+ try {
3712
+ invalidateToken();
3713
+ } catch {
3714
+ }
3715
+ return { ok: false, reason: "unauthorized", status: 401, ...envMeta };
3716
+ }
3717
+ if (!res?.ok) {
3718
+ const code = await refusalCode(res);
3719
+ return { ok: false, reason: code || `http_${res?.status ?? "unknown"}`, status: res?.status ?? 0, ...envMeta };
3720
+ }
3721
+ let body;
3722
+ try {
3723
+ body = await res.json();
3724
+ } catch (err) {
3725
+ return { ok: false, reason: `unreadable_body: ${err?.message || String(err)}`, status: res.status, ...envMeta };
3726
+ }
3727
+ const job = body?.prepared_job;
3728
+ if (!job || typeof job !== "object") {
3729
+ return { ok: false, reason: "no_prepared_job_in_body", status: res.status, ...envMeta };
3730
+ }
3731
+ return {
3732
+ ok: true,
3733
+ job,
3734
+ composition: body?.composition && typeof body.composition === "object" ? body.composition : {},
3735
+ ...envMeta
3736
+ };
3737
+ }
3738
+ var PREPARED_JOB_ENV_QUERY_KEYS, PREPARED_JOB_ENV_VALUE_MAX;
3739
+ var init_control_plane_prepared_job = __esm({
3740
+ "../../scripts/virtual-office/code-runner/control-plane-prepared-job.mjs"() {
3741
+ "use strict";
3742
+ PREPARED_JOB_ENV_QUERY_KEYS = [
3743
+ "VO_CODE_RUNNER_NO_WEB",
3744
+ "VO_CODE_RUNNER_NO_WORKFLOW",
3745
+ "VO_CODE_RUNNER_NO_CONSENSUS",
3746
+ "VO_CODE_RUNNER_PERMISSION_MODE",
3747
+ "VO_CODE_RUNNER_DEFAULT_BUDGET_USD",
3748
+ "VO_CODE_RUNNER_META_REASONING_EFFORT",
3749
+ "VO_CODE_RUNNER_ALLOW_MISSING_KNOWLEDGE_CONTEXT",
3750
+ "VO_ENABLE_CONTEXT7"
3751
+ ];
3752
+ PREPARED_JOB_ENV_VALUE_MAX = 64;
3753
+ }
3754
+ });
3755
+
3669
3756
  // src/runner/control-plane-auth-stub.mjs
3670
3757
  var control_plane_auth_stub_exports = {};
3671
3758
  __export(control_plane_auth_stub_exports, {
@@ -3902,6 +3989,10 @@ function createControlPlaneClient({
3902
3989
  log: (m) => console.warn(`[code-runner ${(/* @__PURE__ */ new Date()).toISOString()}] ${m}`)
3903
3990
  });
3904
3991
  },
3992
+ /** ADR-004 § 11.1b: the plane's prepared job, for SHADOW comparison. Never throws. */
3993
+ getPreparedJob: (taskId, options) => getPreparedJobRequest(req, taskId, options, () => {
3994
+ cachedFirebaseToken = null;
3995
+ }),
3905
3996
  /** Weekly Claude token usage report — see control-plane-weekly-tokens.mjs. */
3906
3997
  async postWeeklyTokens(report) {
3907
3998
  return postWeeklyTokensRequest(taskReq, report, () => {
@@ -3923,8 +4014,8 @@ function createControlPlaneClient({
3923
4014
  * authenticated operator so the web shows a TRUE "runner online" signal.
3924
4015
  * Best-effort caller; throws on 401/non-ok so the daemon can log + retry.
3925
4016
  */
3926
- async postHeartbeat({ runnerId: runnerId2, runnerInstanceId: runnerInstanceId2, operatorId, uptimeSec, activeTasks, maxConcurrency, effectiveConcurrency, measuredTaskSlots, measuredCpuSlots, measuredMemorySlots, version, daemonVersion, defaultAgent, supervisorInstanceId, supervisorVersion, supervisorCapabilities, servedRepos, servedOperators, availableAgents, accountUsage, availableLocalModels }) {
3927
- const body = { runner_id: runnerId2 };
4017
+ async postHeartbeat({ runnerId: runnerId2, runnerInstanceId: runnerInstanceId2, operatorId, uptimeSec, activeTasks, maxConcurrency, effectiveConcurrency, measuredTaskSlots, measuredCpuSlots, measuredMemorySlots, version, daemonVersion, defaultAgent, supervisorInstanceId, supervisorVersion, supervisorCapabilities, servedRepos, servedOperators, availableAgents, accountUsage, availableLocalModels, prepared_job_shadow: preparedJobShadow }) {
4018
+ const body = { runner_id: runnerId2, ...preparedJobShadow ? { prepared_job_shadow: preparedJobShadow } : {} };
3928
4019
  if (runnerInstanceId2) body.runner_instance_id = runnerInstanceId2;
3929
4020
  if (operatorId) body.operator_id = operatorId;
3930
4021
  if (typeof uptimeSec === "number") body.uptime_sec = uptimeSec;
@@ -4055,6 +4146,7 @@ var init_control_plane_client = __esm({
4055
4146
  init_control_plane_telemetry_relay();
4056
4147
  init_claim_gate_notice();
4057
4148
  init_control_plane_knowledge_context();
4149
+ init_control_plane_prepared_job();
4058
4150
  cachedFirebaseToken = null;
4059
4151
  ClaimAuthorityChangedError = class extends Error {
4060
4152
  constructor() {
@@ -8784,13 +8876,13 @@ async function materializeTaskAttachments(client, task, { tempRoot = os2.tmpdir(
8784
8876
  const content = await client.downloadTaskAttachment(task.code_task_id, ref.attachment_id);
8785
8877
  if (!Buffer.isBuffer(content)) throw new Error(`attachment ${ref.attachment_id} did not return binary content`);
8786
8878
  if (content.byteLength !== ref.size_bytes) throw new Error(`attachment ${ref.attachment_id} size mismatch`);
8787
- const sha256 = createHash4("sha256").update(content).digest("hex");
8788
- if (sha256 !== ref.sha256) throw new Error(`attachment ${ref.attachment_id} sha256 mismatch`);
8879
+ const sha2562 = createHash4("sha256").update(content).digest("hex");
8880
+ if (sha2562 !== ref.sha256) throw new Error(`attachment ${ref.attachment_id} sha256 mismatch`);
8789
8881
  const name = sanitizeTaskAttachmentName(ref.name, index);
8790
8882
  const filePath = path16.join(state.directory, name);
8791
8883
  await writeFile(filePath, content, { flag: "wx", mode: 384 });
8792
8884
  await chmod(filePath, 384);
8793
- files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256, path: path16.resolve(filePath) });
8885
+ files.push({ attachmentId: ref.attachment_id, name, mime: ref.mime, sizeBytes: ref.size_bytes, sha256: sha2562, path: path16.resolve(filePath) });
8794
8886
  }
8795
8887
  return { directory: state.directory, files, manifestMarkdown: buildManifest(files), cleanup: () => cleanupGeneratedDirectory(state) };
8796
8888
  } catch (error) {
@@ -9443,6 +9535,13 @@ function makeLoopTicks({
9443
9535
  applyRemoteConfig: () => false,
9444
9536
  heartbeatFields: () => ({})
9445
9537
  },
9538
+ // ADR-004 § 11.1b-2: plane-delivered prepared-job consumption mode + the
9539
+ // counts-only shadow tally (prepared-job-remote-config.mjs). Same no-op
9540
+ // default contract as above, so an absent controller changes nothing.
9541
+ preparedJobController = {
9542
+ applyRemoteConfig: () => false,
9543
+ heartbeatFields: () => ({})
9544
+ },
9446
9545
  // Host version awareness: reads `update_status` off the heartbeat ACK and logs
9447
9546
  // ONE line per drift change (daemon-update-status.mjs). No-op default keeps
9448
9547
  // old callers working; absent update_status reads as unknown, never current.
@@ -9491,6 +9590,7 @@ function makeLoopTicks({
9491
9590
  request.then((response) => {
9492
9591
  capacityController.applyCapacity(response?.capacity, nextPayload.operatorId);
9493
9592
  localModelController.applyRemoteConfig(response?.local_model, nextPayload.operatorId);
9593
+ preparedJobController.applyRemoteConfig(response?.prepared_job, nextPayload.operatorId);
9494
9594
  updateStatusTracker.applyHeartbeatResponse(response);
9495
9595
  }).catch((e) => log2(`heartbeat failed: ${e.message}`)).finally(() => {
9496
9596
  for (const done of waiters) done();
@@ -9535,6 +9635,7 @@ function makeLoopTicks({
9535
9635
  const supervisorCapabilities = String(env2.VO_RUNNER_SUPERVISOR_CAPABILITIES || "").split(",").map((value) => value.trim()).filter(Boolean).slice(0, 8);
9536
9636
  const capacityFields = capacityController.heartbeatFields();
9537
9637
  const localModelFields = localModelController.heartbeatFields();
9638
+ const preparedJobFields = preparedJobController.heartbeatFields();
9538
9639
  const baseHeartbeat = {
9539
9640
  runnerId: cfg.runnerId,
9540
9641
  ...runnerInstanceId ? { runnerInstanceId } : {},
@@ -9552,7 +9653,8 @@ function makeLoopTicks({
9552
9653
  activeTasks: getActive(),
9553
9654
  maxConcurrency: cfg.maxConcurrency,
9554
9655
  ...capacityFields,
9555
- ...localModelFields
9656
+ ...localModelFields,
9657
+ ...preparedJobFields
9556
9658
  };
9557
9659
  const operatorIds = servedOperators.length > 0 ? servedOperators : [void 0];
9558
9660
  for (const operatorId of operatorIds) {
@@ -9919,6 +10021,434 @@ var init_local_model_remote_config = __esm({
9919
10021
  }
9920
10022
  });
9921
10023
 
10024
+ // ../../scripts/virtual-office/code-runner/prepared-job-shadow.mjs
10025
+ import { appendFileSync, mkdirSync as mkdirSync8 } from "node:fs";
10026
+ import { createHash as createHash6 } from "node:crypto";
10027
+ import { homedir as homedir9 } from "node:os";
10028
+ import { dirname as dirname10, join as join14 } from "node:path";
10029
+ function setRemotePreparedJobMode(mode) {
10030
+ const value = typeof mode === "string" ? mode.trim().toLowerCase() : "";
10031
+ remotePreparedJobMode = value && PREPARED_JOB_MODES.includes(value) ? value : "";
10032
+ }
10033
+ function preparedJobConsumptionMode(env2 = process.env) {
10034
+ const raw = String(env2?.[PREPARED_JOB_MODE_ENV] ?? "").trim().toLowerCase();
10035
+ if (raw && PREPARED_JOB_MODES.includes(raw)) return raw;
10036
+ return remotePreparedJobMode || "off";
10037
+ }
10038
+ function shadowTimeoutMs(env2 = process.env) {
10039
+ const n = Number(env2?.[PREPARED_JOB_SHADOW_TIMEOUT_ENV]);
10040
+ return Number.isFinite(n) && n > 0 ? Math.min(n, 6e4) : DEFAULT_SHADOW_TIMEOUT_MS;
10041
+ }
10042
+ function firstDivergenceIndex(a, b) {
10043
+ const A = String(a ?? "");
10044
+ const B = String(b ?? "");
10045
+ const limit = Math.min(A.length, B.length);
10046
+ for (let i = 0; i < limit; i += 1) if (A[i] !== B[i]) return i;
10047
+ return A.length === B.length ? -1 : limit;
10048
+ }
10049
+ function localCompositionAsPreparedJob(local = {}, { agent = "claude", env: env2 = process.env } = {}) {
10050
+ const isClaude = String(agent || "").trim().toLowerCase() === "claude";
10051
+ return {
10052
+ prompt: local.prompt ?? "",
10053
+ argv: buildClaudeArgs({
10054
+ permissionMode: local.permissionMode,
10055
+ maxTurns: isClaude ? local.maxTurns : void 0,
10056
+ model: local.model,
10057
+ effort: local.effort,
10058
+ maxBudgetUsd: isClaude ? local.maxBudgetUsd : void 0,
10059
+ researchHarness: local.methodology?.shape === "research",
10060
+ env: env2
10061
+ }),
10062
+ permission_mode: local.permissionMode ?? null,
10063
+ dispatch_mode: local.dispatchMode ?? null,
10064
+ tier: local.tier ?? null,
10065
+ model: local.model ?? null,
10066
+ effort: local.effort ?? null,
10067
+ max_turns: local.maxTurns ?? null,
10068
+ max_budget_usd: local.maxBudgetUsd ?? null,
10069
+ methodology_shape: local.methodology?.shape ?? null,
10070
+ methodology_stakes: local.methodology?.stakes ?? null
10071
+ };
10072
+ }
10073
+ function planeJobAsComparable(job = {}) {
10074
+ return {
10075
+ prompt: job.prompt ?? "",
10076
+ argv: job.argv ?? null,
10077
+ permission_mode: job.permission_mode ?? null,
10078
+ dispatch_mode: job.dispatch_mode ?? null,
10079
+ tier: job.tier ?? null,
10080
+ model: job.model ?? null,
10081
+ effort: job.effort ?? null,
10082
+ max_turns: job.max_turns ?? null,
10083
+ max_budget_usd: job.max_budget_usd ?? null,
10084
+ methodology_shape: job.methodology?.shape ?? null,
10085
+ methodology_stakes: job.methodology?.stakes ?? null
10086
+ };
10087
+ }
10088
+ function classifyDivergence(field, ctx = {}) {
10089
+ const known = (reason) => ({ class: "known_remainder", reason });
10090
+ if (Array.isArray(ctx.envDropped) && ctx.envDropped.length > 0) {
10091
+ return known(`env_value_too_long:${ctx.envDropped.join("+")}`);
10092
+ }
10093
+ if ((field === "model" || field === "tier") && ctx.planeModelRegistryUnavailable) {
10094
+ return known("no_plane_model_registry");
10095
+ }
10096
+ if (field === "dispatch_mode" && ctx.taskDispatchModeAbsent) return known("plane_dispatch_mode_default");
10097
+ if (ctx.dispatchModeDiverged && DISPATCH_MODE_DEPENDENT.has(field)) {
10098
+ return known("downstream_of_dispatch_mode");
10099
+ }
10100
+ if (field === "prompt" && ctx.attachmentManifestPresent) return known("attachment_manifest_not_sent");
10101
+ if (field === "prompt" && ctx.planeSkillCatalogUnavailable) return known("skill_catalog_unavailable");
10102
+ return { class: "unexplained", reason: null };
10103
+ }
10104
+ function comparePreparedJob({ local, plane, context = {} }) {
10105
+ const L = local || {};
10106
+ const P = plane || {};
10107
+ const raw = COMPARED_FIELDS.filter((f) => !sameValue(L[f], P[f]));
10108
+ const ctx = { ...context, dispatchModeDiverged: raw.includes("dispatch_mode") };
10109
+ const divergences = raw.map((field) => {
10110
+ const { class: cls, reason } = classifyDivergence(field, ctx);
10111
+ const entry = { field, class: cls, reason };
10112
+ if (field !== "prompt") {
10113
+ entry.runner = L[field] ?? null;
10114
+ entry.plane = P[field] ?? null;
10115
+ }
10116
+ return entry;
10117
+ });
10118
+ const unexplainedFields = divergences.filter((d) => d.class === "unexplained").map((d) => d.field);
10119
+ return {
10120
+ verdict: divergences.length === 0 ? "parity_ok" : unexplainedFields.length > 0 ? "parity_diverged" : "parity_known_remainder",
10121
+ divergences,
10122
+ divergentFields: raw,
10123
+ unexplainedFields,
10124
+ prompt: {
10125
+ runner_len: String(L.prompt ?? "").length,
10126
+ plane_len: String(P.prompt ?? "").length,
10127
+ runner_sha256: sha256(L.prompt),
10128
+ plane_sha256: sha256(P.prompt),
10129
+ first_diff_index: firstDivergenceIndex(L.prompt, P.prompt)
10130
+ }
10131
+ };
10132
+ }
10133
+ function selectDispatchComposition({ mode, local, plane, comparison }) {
10134
+ if (mode === "prepared" && plane && comparison?.verdict !== "unavailable") {
10135
+ return { source: "plane", composition: plane };
10136
+ }
10137
+ return { source: "local", composition: local };
10138
+ }
10139
+ function buildShadowRecord({
10140
+ taskId,
10141
+ repo,
10142
+ agent,
10143
+ mode,
10144
+ comparison,
10145
+ fetched,
10146
+ ts
10147
+ }) {
10148
+ const base = {
10149
+ schema_version: 1,
10150
+ kind: "prepared_job_shadow",
10151
+ adr: "ADR-004 \xA7 11.1b",
10152
+ ts,
10153
+ code_task_id: taskId ?? null,
10154
+ repo: repo ?? null,
10155
+ agent: agent ?? null,
10156
+ mode,
10157
+ env_sent: fetched?.envSent ?? [],
10158
+ env_dropped: fetched?.envDropped ?? []
10159
+ };
10160
+ if (!comparison) {
10161
+ return {
10162
+ ...base,
10163
+ verdict: "unavailable",
10164
+ reason: fetched?.reason ?? "unknown",
10165
+ status: fetched?.status ?? 0,
10166
+ divergent_fields: [],
10167
+ unexplained_fields: [],
10168
+ divergences: []
10169
+ };
10170
+ }
10171
+ return {
10172
+ ...base,
10173
+ verdict: comparison.verdict,
10174
+ reason: null,
10175
+ divergent_fields: comparison.divergentFields,
10176
+ unexplained_fields: comparison.unexplainedFields,
10177
+ divergences: comparison.divergences,
10178
+ prompt: comparison.prompt,
10179
+ plane_composition: {
10180
+ model_registry: fetched?.composition?.model_registry ?? null,
10181
+ skill_catalog_available: fetched?.composition?.skill_catalog_available ?? null
10182
+ }
10183
+ };
10184
+ }
10185
+ function formatShadowLogLine(record) {
10186
+ const parts = [
10187
+ `task=${record.code_task_id}`,
10188
+ `mode=${record.mode}`,
10189
+ `verdict=${record.verdict}`
10190
+ ];
10191
+ if (record.verdict === "unavailable") parts.push(`reason=${record.reason}`, `status=${record.status}`);
10192
+ if (record.unexplained_fields?.length) parts.push(`UNEXPLAINED=${record.unexplained_fields.join(",")}`);
10193
+ const known = (record.divergences || []).filter((d) => d.class === "known_remainder");
10194
+ if (known.length) parts.push(`known=${known.map((d) => `${d.field}(${d.reason})`).join(",")}`);
10195
+ if (record.verdict === "parity_diverged" && typeof record.prompt?.first_diff_index === "number" && record.prompt.first_diff_index >= 0 && record.unexplained_fields?.includes("prompt")) {
10196
+ parts.push(`prompt_first_diff_index=${record.prompt.first_diff_index}`);
10197
+ }
10198
+ const loud = record.unexplained_fields?.length ? "!! " : "";
10199
+ return `${loud}[prepared-job-shadow] ${parts.join(" ")}`;
10200
+ }
10201
+ function appendShadowRecord(record, { path: path22 = PREPARED_JOB_SHADOW_SINK, append = appendFileSync, mkdir: mkdir5 = mkdirSync8 } = {}) {
10202
+ try {
10203
+ mkdir5(dirname10(path22), { recursive: true });
10204
+ append(path22, `${JSON.stringify(record)}
10205
+ `, "utf8");
10206
+ return true;
10207
+ } catch {
10208
+ return false;
10209
+ }
10210
+ }
10211
+ async function preparedJobShadowPass({
10212
+ client,
10213
+ task,
10214
+ agent = "claude",
10215
+ env: env2 = process.env,
10216
+ local,
10217
+ log: log2 = () => {
10218
+ },
10219
+ now = () => (/* @__PURE__ */ new Date()).toISOString(),
10220
+ sinkOptions
10221
+ } = {}) {
10222
+ const mode = preparedJobConsumptionMode(env2);
10223
+ if (mode === "off") return { mode: "off" };
10224
+ try {
10225
+ if (mode === "prepared") {
10226
+ log2("[prepared-job-shadow] prepared_mode_not_wired \u2014 comparing only; ADR-004 \xA7 11.1c owns the flip");
10227
+ }
10228
+ if (typeof client?.getPreparedJob !== "function") {
10229
+ return { mode, verdict: "unavailable", reason: "client_lacks_get_prepared_job" };
10230
+ }
10231
+ const fetched = await client.getPreparedJob(task?.code_task_id, {
10232
+ agent,
10233
+ env: env2,
10234
+ timeoutMs: shadowTimeoutMs(env2)
10235
+ });
10236
+ const localJob = localCompositionAsPreparedJob(local, { agent, env: env2 });
10237
+ const comparison = fetched?.ok ? comparePreparedJob({
10238
+ local: localJob,
10239
+ plane: planeJobAsComparable(fetched.job),
10240
+ context: {
10241
+ planeModelRegistryUnavailable: fetched.composition?.model_registry !== "injected",
10242
+ planeSkillCatalogUnavailable: fetched.composition?.skill_catalog_available === false,
10243
+ taskDispatchModeAbsent: !task?.dispatch_mode,
10244
+ attachmentManifestPresent: Boolean(local?.attachmentManifestMarkdown),
10245
+ envDropped: fetched.envDropped
10246
+ }
10247
+ }) : null;
10248
+ const record = buildShadowRecord({
10249
+ taskId: task?.code_task_id,
10250
+ repo: task?.repo,
10251
+ agent,
10252
+ mode,
10253
+ comparison,
10254
+ fetched,
10255
+ ts: now()
10256
+ });
10257
+ appendShadowRecord(record, sinkOptions);
10258
+ log2(formatShadowLogLine(record));
10259
+ return {
10260
+ mode,
10261
+ verdict: record.verdict,
10262
+ record,
10263
+ selection: selectDispatchComposition({
10264
+ mode,
10265
+ local: localJob,
10266
+ plane: fetched?.ok ? planeJobAsComparable(fetched.job) : null,
10267
+ comparison
10268
+ })
10269
+ };
10270
+ } catch (err) {
10271
+ try {
10272
+ log2(`[prepared-job-shadow] shadow pass failed (dispatch unaffected): ${err?.message || err}`);
10273
+ } catch {
10274
+ }
10275
+ return { mode, verdict: "unavailable", reason: `shadow_error: ${err?.message || String(err)}` };
10276
+ }
10277
+ }
10278
+ function setPreparedJobShadowObserver(fn) {
10279
+ verdictObserver = typeof fn === "function" ? fn : null;
10280
+ }
10281
+ async function runPreparedJobShadow(options = {}) {
10282
+ const result = await preparedJobShadowPass(options);
10283
+ try {
10284
+ verdictObserver?.(result);
10285
+ } catch {
10286
+ }
10287
+ return result;
10288
+ }
10289
+ var PREPARED_JOB_MODES, PREPARED_JOB_MODE_ENV, PREPARED_JOB_SHADOW_TIMEOUT_ENV, DEFAULT_SHADOW_TIMEOUT_MS, PREPARED_JOB_SHADOW_SINK, remotePreparedJobMode, COMPARED_FIELDS, DISPATCH_MODE_DEPENDENT, sha256, sameValue, verdictObserver;
10290
+ var init_prepared_job_shadow = __esm({
10291
+ "../../scripts/virtual-office/code-runner/prepared-job-shadow.mjs"() {
10292
+ "use strict";
10293
+ init_claude_args();
10294
+ PREPARED_JOB_MODES = ["off", "shadow", "prepared"];
10295
+ PREPARED_JOB_MODE_ENV = "VO_CODE_RUNNER_PREPARED_JOB";
10296
+ PREPARED_JOB_SHADOW_TIMEOUT_ENV = "VO_PREPARED_JOB_SHADOW_TIMEOUT_MS";
10297
+ DEFAULT_SHADOW_TIMEOUT_MS = 15e3;
10298
+ PREPARED_JOB_SHADOW_SINK = join14(homedir9(), ".claude", "vo-prepared-job-shadow.jsonl");
10299
+ remotePreparedJobMode = "";
10300
+ COMPARED_FIELDS = [
10301
+ "prompt",
10302
+ "argv",
10303
+ "permission_mode",
10304
+ "dispatch_mode",
10305
+ "tier",
10306
+ "model",
10307
+ "effort",
10308
+ "max_turns",
10309
+ "max_budget_usd",
10310
+ "methodology_shape",
10311
+ "methodology_stakes"
10312
+ ];
10313
+ DISPATCH_MODE_DEPENDENT = /* @__PURE__ */ new Set([
10314
+ "prompt",
10315
+ "argv",
10316
+ "permission_mode",
10317
+ "tier",
10318
+ "model",
10319
+ "effort",
10320
+ "max_turns"
10321
+ ]);
10322
+ sha256 = (s) => createHash6("sha256").update(String(s ?? ""), "utf8").digest("hex");
10323
+ sameValue = (a, b) => Array.isArray(a) || Array.isArray(b) ? JSON.stringify(a) === JSON.stringify(b) : (a ?? null) === (b ?? null);
10324
+ verdictObserver = null;
10325
+ }
10326
+ });
10327
+
10328
+ // ../../scripts/virtual-office/code-runner/prepared-job-remote-config.mjs
10329
+ function emptyPreparedJobTally() {
10330
+ return {
10331
+ compared: 0,
10332
+ parity_ok: 0,
10333
+ parity_diverged: 0,
10334
+ unavailable: 0,
10335
+ unexplained: 0,
10336
+ diverged_fields: {},
10337
+ last_verdict_at: null
10338
+ };
10339
+ }
10340
+ function foldPreparedJobVerdict(tally, result, nowIso) {
10341
+ const verdict = result?.verdict;
10342
+ if (!verdict) return tally;
10343
+ tally.last_verdict_at = nowIso;
10344
+ if (verdict === "unavailable") {
10345
+ tally.unavailable += 1;
10346
+ return tally;
10347
+ }
10348
+ tally.compared += 1;
10349
+ if (verdict === "parity_ok") tally.parity_ok += 1;
10350
+ else if (verdict === "parity_diverged") tally.parity_diverged += 1;
10351
+ const record = result.record || {};
10352
+ tally.unexplained += (record.unexplained_fields || []).length;
10353
+ for (const field of record.divergent_fields || []) {
10354
+ const known = Object.prototype.hasOwnProperty.call(tally.diverged_fields, field);
10355
+ if (!known && Object.keys(tally.diverged_fields).length >= MAX_DIVERGED_FIELD_KEYS) continue;
10356
+ tally.diverged_fields[field] = (tally.diverged_fields[field] || 0) + 1;
10357
+ }
10358
+ return tally;
10359
+ }
10360
+ function createPreparedJobRemoteController({
10361
+ log: log2 = () => {
10362
+ },
10363
+ now = () => (/* @__PURE__ */ new Date()).toISOString(),
10364
+ apply = setRemotePreparedJobMode,
10365
+ observe = setPreparedJobShadowObserver
10366
+ } = {}) {
10367
+ const byOperator = /* @__PURE__ */ new Map();
10368
+ const tally = emptyPreparedJobTally();
10369
+ let planeSpeaksPreparedJob = false;
10370
+ let warnedNotWired = false;
10371
+ let warnedConflict = "";
10372
+ function desiredMode() {
10373
+ const modes = [...new Set(
10374
+ [...byOperator.values()].map((s) => s.mode).filter((m) => m && m !== "off")
10375
+ )];
10376
+ if (modes.length > 1) {
10377
+ const key = modes.slice().sort().join(",");
10378
+ if (warnedConflict !== key) {
10379
+ warnedConflict = key;
10380
+ log2(`prepared-job remote config: conflicting modes across served operators (${key}) \u2014 applying off`);
10381
+ }
10382
+ return "off";
10383
+ }
10384
+ return modes[0] ?? "off";
10385
+ }
10386
+ function syncEffective() {
10387
+ const mode = desiredMode();
10388
+ apply(mode);
10389
+ return mode;
10390
+ }
10391
+ observe((result) => foldPreparedJobVerdict(tally, result, now()));
10392
+ return {
10393
+ /**
10394
+ * Heartbeat payload extras. Silent until the plane has proven it speaks this
10395
+ * contract AND a pass has actually been counted — see safety property 3.
10396
+ */
10397
+ heartbeatFields() {
10398
+ if (!planeSpeaksPreparedJob || tally.last_verdict_at === null) return {};
10399
+ return {
10400
+ prepared_job_shadow: {
10401
+ schema_version: PREPARED_JOB_CONFIG_SCHEMA_VERSION,
10402
+ mode: desiredMode(),
10403
+ ...tally,
10404
+ diverged_fields: { ...tally.diverged_fields }
10405
+ }
10406
+ };
10407
+ },
10408
+ /**
10409
+ * Apply one operator's heartbeat-response echo
10410
+ * `{ schema_version, prepared_job_mode, revision }`. Returns whether the
10411
+ * echo was accepted.
10412
+ */
10413
+ applyRemoteConfig(echo, operatorId = "") {
10414
+ const scope = String(operatorId || "");
10415
+ const previous = byOperator.get(scope);
10416
+ if (!echo || echo.schema_version !== PREPARED_JOB_CONFIG_SCHEMA_VERSION || !Number.isInteger(echo.revision) || previous && echo.revision < previous.revision) {
10417
+ return false;
10418
+ }
10419
+ const raw = typeof echo.prepared_job_mode === "string" ? echo.prepared_job_mode.trim().toLowerCase() : "";
10420
+ if (!PREPARED_JOB_MODES.includes(raw)) return false;
10421
+ planeSpeaksPreparedJob = true;
10422
+ let mode = raw;
10423
+ if (mode === "prepared") {
10424
+ mode = "shadow";
10425
+ if (!warnedNotWired) {
10426
+ warnedNotWired = true;
10427
+ log2("prepared-job remote config: prepared_mode_not_wired \u2014 applying shadow; ADR-004 \xA7 11.1c owns the flip");
10428
+ }
10429
+ }
10430
+ byOperator.set(scope, { revision: echo.revision, mode });
10431
+ syncEffective();
10432
+ return true;
10433
+ },
10434
+ snapshot: () => ({
10435
+ mode: desiredMode(),
10436
+ planeSpeaksPreparedJob,
10437
+ tally: { ...tally, diverged_fields: { ...tally.diverged_fields } },
10438
+ operators: Object.fromEntries(byOperator)
10439
+ })
10440
+ };
10441
+ }
10442
+ var PREPARED_JOB_CONFIG_SCHEMA_VERSION, MAX_DIVERGED_FIELD_KEYS;
10443
+ var init_prepared_job_remote_config = __esm({
10444
+ "../../scripts/virtual-office/code-runner/prepared-job-remote-config.mjs"() {
10445
+ "use strict";
10446
+ init_prepared_job_shadow();
10447
+ PREPARED_JOB_CONFIG_SCHEMA_VERSION = 1;
10448
+ MAX_DIVERGED_FIELD_KEYS = 24;
10449
+ }
10450
+ });
10451
+
9922
10452
  // ../../scripts/virtual-office/code-runner/account-usage/shared.mjs
9923
10453
  import crypto from "node:crypto";
9924
10454
  import fs9 from "node:fs";
@@ -10539,7 +11069,7 @@ var init_error_message = __esm({
10539
11069
  });
10540
11070
 
10541
11071
  // ../../scripts/virtual-office/code-runner/watcher-coordination.mjs
10542
- import { createHash as createHash6 } from "node:crypto";
11072
+ import { createHash as createHash7 } from "node:crypto";
10543
11073
  function ciFixOccurrenceKey({ repo, prNumber, headSha, repairAttempt }) {
10544
11074
  const occurrence = JSON.stringify([
10545
11075
  String(repo).toLowerCase(),
@@ -10547,7 +11077,7 @@ function ciFixOccurrenceKey({ repo, prNumber, headSha, repairAttempt }) {
10547
11077
  String(headSha).toLowerCase(),
10548
11078
  Number(repairAttempt)
10549
11079
  ]);
10550
- return `ci-fix:v1:${createHash6("sha256").update(occurrence).digest("hex")}`;
11080
+ return `ci-fix:v1:${createHash7("sha256").update(occurrence).digest("hex")}`;
10551
11081
  }
10552
11082
  function coordinationRetryDue(entry, nowMs) {
10553
11083
  return !entry.nextRetryAt || nowMs >= entry.nextRetryAt;
@@ -10679,7 +11209,7 @@ var init_watcher_coordination = __esm({
10679
11209
  // ../../scripts/virtual-office/code-runner/watcher-state.mjs
10680
11210
  import { randomUUID as randomUUID4 } from "node:crypto";
10681
11211
  import { mkdir as mkdir3, open as open2, readFile as readFile4, rename, unlink as unlink2 } from "node:fs/promises";
10682
- import { dirname as dirname10 } from "node:path";
11212
+ import { dirname as dirname11 } from "node:path";
10683
11213
  async function readWatcherState(stateFile) {
10684
11214
  let raw;
10685
11215
  try {
@@ -10695,7 +11225,7 @@ async function readWatcherState(stateFile) {
10695
11225
  return parsed;
10696
11226
  }
10697
11227
  async function writeWatcherState(stateFile, state) {
10698
- const directory = dirname10(stateFile);
11228
+ const directory = dirname11(stateFile);
10699
11229
  await mkdir3(directory, { recursive: true });
10700
11230
  const temp = `${stateFile}.${process.pid}.${randomUUID4()}.tmp`;
10701
11231
  let handle;
@@ -11224,8 +11754,8 @@ var init_enqueue_autonomous_code_task = __esm({
11224
11754
  });
11225
11755
 
11226
11756
  // ../../scripts/virtual-office/code-runner/pr-watcher.mjs
11227
- import { homedir as homedir9 } from "node:os";
11228
- import { join as join14 } from "node:path";
11757
+ import { homedir as homedir10 } from "node:os";
11758
+ import { join as join15 } from "node:path";
11229
11759
  function parsePrCiStatus(view) {
11230
11760
  const state = (view && typeof view.state === "string" ? view.state : "UNKNOWN").toUpperCase();
11231
11761
  const rollup = latestCheckRunsByName(view && Array.isArray(view.statusCheckRollup) ? view.statusCheckRollup : []);
@@ -11597,7 +12127,7 @@ var init_pr_watcher = __esm({
11597
12127
  init_watcher_merge_authority();
11598
12128
  init_superseded_pr_source();
11599
12129
  init_ci_fix_prompt();
11600
- DEFAULT_STATE_FILE = join14(homedir9(), ".vo", "dispatched-prs.json");
12130
+ DEFAULT_STATE_FILE = join15(homedir10(), ".vo", "dispatched-prs.json");
11601
12131
  FAIL_CONCLUSIONS = /* @__PURE__ */ new Set([
11602
12132
  "FAILURE",
11603
12133
  "TIMED_OUT",
@@ -12371,13 +12901,13 @@ async function resolveModelForTier(tier, { agent = DEFAULT_AGENT2, resolveModelF
12371
12901
  if (resolved && modelCompatibleWithAgent(normalizedAgent, resolved)) return resolved;
12372
12902
  return fallbacks[effectiveTier];
12373
12903
  }
12374
- async function resolveTaskModel(task, { agent = DEFAULT_AGENT2 } = {}) {
12904
+ async function resolveTaskModel(task, { agent = DEFAULT_AGENT2, resolveModelFamily: resolver = resolveModelFamily } = {}) {
12375
12905
  const tier = task.tier && task.tier !== "auto" ? task.tier : classifyTier2(task.prompt);
12376
12906
  const pinned = typeof task.model === "string" ? task.model.trim() : "";
12377
12907
  if (pinned && modelCompatibleWithAgent(normalizeAgent(agent), pinned)) {
12378
12908
  return { tier, model: pinned };
12379
12909
  }
12380
- const model = await resolveModelForTier(tier, { agent });
12910
+ const model = await resolveModelForTier(tier, { agent, resolveModelFamily: resolver });
12381
12911
  return { tier, model };
12382
12912
  }
12383
12913
  var TASK_MODEL_AGENTS, DEFAULT_AGENT2, AGENT_TIER_FAMILIES, AGENT_TIER_FALLBACKS, AGENT_MODEL_COMPATIBILITY;
@@ -12844,8 +13374,8 @@ var init_classify_task = __esm({
12844
13374
 
12845
13375
  // ../../scripts/virtual-office/code-runner/auto-router/effort-policy.mjs
12846
13376
  import { readFileSync as readFileSync9 } from "node:fs";
12847
- import { homedir as homedir10 } from "node:os";
12848
- import { join as join15 } from "node:path";
13377
+ import { homedir as homedir11 } from "node:os";
13378
+ import { join as join16 } from "node:path";
12849
13379
  function difficultyToRung(difficulty, thresholds) {
12850
13380
  const b = thresholds.rungBounds;
12851
13381
  if (difficulty >= b.R5) return "R5";
@@ -12922,7 +13452,7 @@ var init_effort_policy = __esm({
12922
13452
  init_meta_model_catalog();
12923
13453
  RUNG_ORDER = ["R1", "R2", "R3", "R4", "R5"];
12924
13454
  rungIndex = (rung) => RUNG_ORDER.indexOf(rung);
12925
- DEFAULT_CODEX_MODELS_CACHE = join15(homedir10(), ".codex", "models_cache.json");
13455
+ DEFAULT_CODEX_MODELS_CACHE = join16(homedir11(), ".codex", "models_cache.json");
12926
13456
  }
12927
13457
  });
12928
13458
 
@@ -13052,9 +13582,9 @@ var init_role_cost_shadow = __esm({
13052
13582
  });
13053
13583
 
13054
13584
  // ../../scripts/virtual-office/code-runner/auto-router/auto-router.mjs
13055
- import { readFileSync as readFileSync10, appendFileSync, mkdirSync as mkdirSync8 } from "node:fs";
13056
- import { homedir as homedir11 } from "node:os";
13057
- import { join as join16, dirname as dirname11 } from "node:path";
13585
+ import { readFileSync as readFileSync10, appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "node:fs";
13586
+ import { homedir as homedir12 } from "node:os";
13587
+ import { join as join17, dirname as dirname12 } from "node:path";
13058
13588
  import { fileURLToPath as fileURLToPath7 } from "node:url";
13059
13589
  function getAutoRouterMode(env2 = process.env) {
13060
13590
  const raw = String(env2.VO_CODE_RUNNER_AUTO_ROUTER || "").trim().toLowerCase();
@@ -13062,8 +13592,8 @@ function getAutoRouterMode(env2 = process.env) {
13062
13592
  }
13063
13593
  function loadThresholds() {
13064
13594
  if (!cachedThresholds) {
13065
- const here = dirname11(fileURLToPath7(import.meta.url));
13066
- cachedThresholds = JSON.parse(readFileSync10(join16(here, "thresholds.json"), "utf8"));
13595
+ const here = dirname12(fileURLToPath7(import.meta.url));
13596
+ cachedThresholds = JSON.parse(readFileSync10(join17(here, "thresholds.json"), "utf8"));
13067
13597
  }
13068
13598
  return cachedThresholds;
13069
13599
  }
@@ -13129,9 +13659,9 @@ function formatDecisionReason(decision, maxLen = 480) {
13129
13659
  const s = `[${decision.routerVersion}] ${decision.taskClass} d=${decision.difficulty} c=${decision.confidence} \u2192 ${decision.rung}/${decision.tier}${decision.effort ? ` effort=${decision.effort}` : ""} turns=${decision.maxTurns} $${decision.maxBudgetUsd}${decision.flags.length ? ` [${decision.flags.join(",")}]` : ""} :: ${decision.reasons.join("; ")}`;
13130
13660
  return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
13131
13661
  }
13132
- function appendDecisionFallback(decision, { path: path22 = DECISION_FALLBACK_PATH, append = appendFileSync, mkdir: mkdir5 = mkdirSync8, task, thresholds, roleCostInputs } = {}) {
13662
+ function appendDecisionFallback(decision, { path: path22 = DECISION_FALLBACK_PATH, append = appendFileSync2, mkdir: mkdir5 = mkdirSync9, task, thresholds, roleCostInputs } = {}) {
13133
13663
  try {
13134
- mkdir5(dirname11(path22), { recursive: true });
13664
+ mkdir5(dirname12(path22), { recursive: true });
13135
13665
  append(path22, `${JSON.stringify(decision)}
13136
13666
  `, "utf8");
13137
13667
  if (isRouterDecision(decision)) {
@@ -13155,7 +13685,7 @@ var init_auto_router = __esm({
13155
13685
  init_effort_policy();
13156
13686
  init_role_cost_shadow();
13157
13687
  ROUTER_VERSION = "0.1.0";
13158
- DECISION_FALLBACK_PATH = join16(homedir11(), ".claude", "vo-auto-router-decisions.jsonl");
13688
+ DECISION_FALLBACK_PATH = join17(homedir12(), ".claude", "vo-auto-router-decisions.jsonl");
13159
13689
  MODES = /* @__PURE__ */ new Set(["off", "shadow", "on"]);
13160
13690
  cachedThresholds = null;
13161
13691
  isRouterDecision = (d) => Boolean(d && typeof d === "object" && typeof d.taskClass === "string" && typeof d.confidence === "number");
@@ -15291,8 +15821,8 @@ var init_cancellation_probe = __esm({
15291
15821
  });
15292
15822
 
15293
15823
  // ../../scripts/virtual-office/code-runner/detached-economics-spool.mjs
15294
- import { homedir as homedir12 } from "node:os";
15295
- import { dirname as dirname12, join as join17 } from "node:path";
15824
+ import { homedir as homedir13 } from "node:os";
15825
+ import { dirname as dirname13, join as join18 } from "node:path";
15296
15826
  import { mkdir as mkdir4, readFile as readFile5, rename as rename2, writeFile as writeFile4 } from "node:fs/promises";
15297
15827
  function withLock(operation) {
15298
15828
  const result = serialized.then(operation, operation);
@@ -15310,7 +15840,7 @@ async function readEntries(file) {
15310
15840
  }
15311
15841
  }
15312
15842
  async function writeEntries(file, entries) {
15313
- await mkdir4(dirname12(file), { recursive: true });
15843
+ await mkdir4(dirname13(file), { recursive: true });
15314
15844
  const temp = `${file}.${process.pid}.tmp`;
15315
15845
  await writeFile4(temp, `${JSON.stringify(entries)}
15316
15846
  `, "utf8");
@@ -15356,7 +15886,7 @@ var DEFAULT_FILE, serialized;
15356
15886
  var init_detached_economics_spool = __esm({
15357
15887
  "../../scripts/virtual-office/code-runner/detached-economics-spool.mjs"() {
15358
15888
  "use strict";
15359
- DEFAULT_FILE = join17(homedir12(), ".vo", "detached-run-economics.json");
15889
+ DEFAULT_FILE = join18(homedir13(), ".vo", "detached-run-economics.json");
15360
15890
  serialized = Promise.resolve();
15361
15891
  }
15362
15892
  });
@@ -15734,6 +16264,19 @@ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmissio
15734
16264
  allowMissingKnowledgeContext: process.env.VO_CODE_RUNNER_ALLOW_MISSING_KNOWLEDGE_CONTEXT === "1",
15735
16265
  attachmentManifestMarkdown: attachmentBundle.manifestMarkdown
15736
16266
  }) });
16267
+ await runPreparedJobShadow({ client, task, agent: sel.agent, env: process.env, log, local: {
16268
+ // ADR-004 § 11.1b SHADOW: default OFF; return value deliberately unread — slice C owns consumption
16269
+ prompt: effortPrompt,
16270
+ dispatchMode,
16271
+ tier,
16272
+ model,
16273
+ permissionMode: effectivePermissionMode,
16274
+ maxTurns: effectiveMaxTurns,
16275
+ effort: effectiveEffort,
16276
+ maxBudgetUsd: effectiveMaxBudgetUsd,
16277
+ methodology,
16278
+ attachmentManifestMarkdown: attachmentBundle.manifestMarkdown
16279
+ } });
15737
16280
  assertRunnerGovernors({
15738
16281
  agent: sel.agent,
15739
16282
  // Only persisted operator caps are hard contracts. Router/global values
@@ -15998,7 +16541,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
15998
16541
  const agentAvailability = makeAgentAvailabilityProvider({ onError: (e) => log(`agent probe failed: ${e.message}`) });
15999
16542
  await agentAvailability.ready();
16000
16543
  const accountUsage = makeAccountUsageProvider();
16001
- const loopTick = makeLoopTicks({ client, cfg, env: env2, log, getActive: () => active, runnerInstanceId, capacityController, localModelController: createLocalModelRemoteController({ env: env2, log }), getAgentAvailability: () => agentAvailability.get(), getAccountUsage: () => accountUsage.get() });
16544
+ const loopTick = makeLoopTicks({ client, cfg, env: env2, log, getActive: () => active, runnerInstanceId, capacityController, localModelController: createLocalModelRemoteController({ env: env2, log }), preparedJobController: createPreparedJobRemoteController({ log }), getAgentAvailability: () => agentAvailability.get(), getAccountUsage: () => accountUsage.get() });
16002
16545
  const backoff = makeReconnectBackoff({ baseMs: cfg.pollSec * 1e3, log });
16003
16546
  let detachedFlushRunning = false;
16004
16547
  while (!stopping) {
@@ -16102,6 +16645,7 @@ var init_code_runner_daemon = __esm({
16102
16645
  init_runner_capacity();
16103
16646
  init_agent_availability();
16104
16647
  init_local_model_remote_config();
16648
+ init_prepared_job_remote_config();
16105
16649
  init_account_usage2();
16106
16650
  init_pr_watcher();
16107
16651
  init_existing_pr_target();
@@ -16111,6 +16655,7 @@ var init_code_runner_daemon = __esm({
16111
16655
  init_claim_scoping_log();
16112
16656
  init_reconnect_backoff();
16113
16657
  init_task_helpers();
16658
+ init_prepared_job_shadow();
16114
16659
  init_agent_process_env();
16115
16660
  init_sandbox_config();
16116
16661
  init_inference_task_runner();