sneakoscope 2.0.15 → 2.0.17

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 (46) hide show
  1. package/README.md +5 -3
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/.sks-build-stamp.json +4 -4
  6. package/dist/bin/sks.js +1 -1
  7. package/dist/cli/command-registry.js +1 -1
  8. package/dist/commands/proof.js +21 -0
  9. package/dist/commands/zellij-slot-pane.js +7 -1
  10. package/dist/core/agents/agent-orchestrator.js +68 -3
  11. package/dist/core/agents/agent-scheduler.js +217 -86
  12. package/dist/core/agents/agent-schema.js +1 -1
  13. package/dist/core/agents/native-cli-session-swarm.js +97 -27
  14. package/dist/core/agents/native-cli-worker.js +56 -7
  15. package/dist/core/agents/parallel-runtime-proof.js +276 -0
  16. package/dist/core/agents/runtime-proof-summary.js +75 -0
  17. package/dist/core/codex-control/codex-task-runner.js +32 -4
  18. package/dist/core/codex-control/model-call-concurrency.js +106 -0
  19. package/dist/core/commands/naruto-command.js +65 -8
  20. package/dist/core/commands/team-command.js +6 -487
  21. package/dist/core/commands/team-legacy-observe-command.js +182 -0
  22. package/dist/core/db-safety.js +49 -6
  23. package/dist/core/feature-registry.js +4 -2
  24. package/dist/core/fsx.js +1 -1
  25. package/dist/core/git/git-worktree-capability.js +18 -0
  26. package/dist/core/git/git-worktree-manager.js +80 -0
  27. package/dist/core/git/git-worktree-pool.js +4 -0
  28. package/dist/core/hooks-runtime.js +41 -4
  29. package/dist/core/init.js +1 -0
  30. package/dist/core/mad-db/mad-db-capability.js +42 -2
  31. package/dist/core/mad-db/mad-db-ledger.js +14 -0
  32. package/dist/core/mad-db/mad-db-policy-resolver.js +2 -0
  33. package/dist/core/mad-db/mad-db-result-lifecycle.js +136 -0
  34. package/dist/core/naruto/naruto-concurrency-governor.js +14 -1
  35. package/dist/core/release/release-gate-affected-selector.js +47 -5
  36. package/dist/core/release/release-gate-dag.js +5 -1
  37. package/dist/core/release/release-gate-scheduler.js +2 -1
  38. package/dist/core/routes.js +3 -1
  39. package/dist/core/version.js +1 -1
  40. package/dist/core/zellij/zellij-slot-pane-renderer.js +74 -1
  41. package/dist/core/zellij/zellij-slot-telemetry.js +81 -3
  42. package/dist/core/zellij/zellij-ui-mode.js +12 -2
  43. package/dist/scripts/prepublish-release-check-or-fast.js +3 -3
  44. package/dist/scripts/release-speed-summary.js +23 -1
  45. package/package.json +38 -3
  46. package/schemas/agents/parallel-runtime-proof.schema.json +79 -0
package/README.md CHANGED
@@ -16,7 +16,7 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
16
16
 
17
17
  ## Current Release
18
18
 
19
- SKS **2.0.15** is the ultra-stabilized Research synthesis release. It keeps the 2.0.14 stage-aware runtime, then hardens final synthesis so non-mock Research uses an evidence-bound Codex/GPT writer, rejects repeated or template-like reports, records source/claim density, and produces handoffs that Team or Naruto can consume directly.
19
+ SKS **2.0.17** is the micro-hardening release for strict production PID proof, true scheduler active-time utilization, live Zellij slot telemetry freshness, Mad-DB result lifecycle audit, and unified runtime/release proof summaries.
20
20
 
21
21
  What changed:
22
22
 
@@ -613,7 +613,9 @@ SKS_HERMES=1 sks status --json
613
613
 
614
614
  Use these inside Codex App or another agent prompt. They are prompt commands, not terminal commands.
615
615
 
616
- Common prompts: `$Team`, `$From-Chat-IMG`, `$with-local-llm-on`, `$with-local-llm-off`, `$DFix`, `$Answer`, `$SKS`, `$QA-LOOP`, `$PPT`, `$Computer-Use`/`$CU`, `$Goal`, `$Research`, `$AutoResearch`, `$DB`, `$MAD-SKS`, `$GX`, `$Wiki`, and `$Help`.
616
+ Common prompts: `$Team`, `$From-Chat-IMG`, `$with-local-llm-on`, `$with-local-llm-off`, `$DFix`, `$Answer`, `$SKS`, `$QA-LOOP`, `$PPT`, `$Computer-Use`/`$CU`, `$Goal`, `$Research`, `$AutoResearch`, `$DB`, `$MAD-SKS`, `$MAD-DB`, `$GX`, `$Wiki`, and `$Help`.
617
+
618
+ `$MAD-DB` is the prompt-visible Mad-DB alias for one-cycle DB break-glass work. It maps to the same guarded MAD-SKS permission route, while the terminal lifecycle remains `sks mad-db status|enable|revoke`; it is not a permanent DB unlock and catastrophic DB safeguards remain active.
617
619
 
618
620
  ## Common Workflows
619
621
 
@@ -759,7 +761,7 @@ npm run release:check
759
761
  npm run publish:dry
760
762
  ```
761
763
 
762
- `release:check` runs the change-aware affected release gate for ordinary local checks. Publish readiness uses `release:check:full`, which runs the full release DAG and writes a source digest stamp under `.sneakoscope/reports/` so publish commands can verify the same source/dist state. The DAG preserves the 1.18 baseline gates and adds Codex 0.136 compatibility, inherited Codex 0.135/0.134 runner truth, patch swarm runtime truth, transaction journaling, serial conflict rebase, strict strategy-to-patch proof, rollback command proof, Native CLI Session Swarm 5/10/20-process proof, Real Worker Backend Router proof, Codex child overlap proof, model-authored patch-envelope separation, Zellij layout/pane/screen/socket-dir proof, no-subagent-scaling proof, Fast mode default/worker/Codex/MAD propagation proof, Appshots attachment provenance, MCP runtime overlap evidence, task graph expansion, schema-bound follow-up work, actual Agent/Team/Research/QA route blackboxes, scheduler proof hardening, Source Intelligence propagation, Goal mode propagation checks, slot telemetry, update notice, MAD-DB, and Naruto SSOT gates. Broader live gates remain explicit scripts such as `release:real-check`; real Codex patch smoke, real Codex parallel worker proof, and real Zellij proof are optional unless their `SKS_REQUIRE_REAL_*` or `SKS_REQUIRE_ZELLIJ=1` environment variables are set. Generate the human-readable registry with `sks features inventory --write-docs`. Plain `npm publish` uses the `latest` dist-tag. npm's `prepublishOnly` and `npm run publish:dry` both run `release:check:full`, verify the fresh stamp, and then run provenance/registry checks before the real or dry-run publish step.
764
+ `release:check` runs the change-aware affected release gate for ordinary local checks. Publish readiness uses `release:check:full`, which runs the full release DAG and writes a source digest stamp under `.sneakoscope/reports/` so publish commands can verify the same source/dist state. The DAG preserves the 1.18 baseline gates and adds Codex 0.136 compatibility, inherited Codex 0.135/0.134 runner truth, patch swarm runtime truth, transaction journaling, serial conflict rebase, strict strategy-to-patch proof, rollback command proof, Native CLI Session Swarm 5/10/20-process proof, Real Worker Backend Router proof, Codex child overlap proof, model-authored patch-envelope separation, Zellij layout/pane/screen/socket-dir proof, no-subagent-scaling proof, Fast mode default/worker/Codex/MAD propagation proof, Appshots attachment provenance, MCP runtime overlap evidence, task graph expansion, schema-bound follow-up work, actual Agent/Team/Research/QA route blackboxes, scheduler proof hardening, Source Intelligence propagation, Goal mode propagation checks, slot telemetry, update notice, MAD-DB, and Naruto SSOT gates. Broader live gates remain explicit scripts such as `release:real-check`; real Codex patch smoke, real Codex parallel worker proof, and real Zellij proof are optional unless their `SKS_REQUIRE_REAL_*` or `SKS_REQUIRE_ZELLIJ=1` environment variables are set. Generate the human-readable registry with `sks features inventory --write-docs`. Plain `npm publish` uses the `latest` dist-tag. `npm run publish:dry` runs `release:check:full`, verifies the fresh stamp, and then performs provenance/registry and npm dry-run checks. npm's `prepublishOnly` uses `prepublish-release-check-or-fast` to accept that current stamp before the real publish; if the stamp is missing or stale, it runs `release:check:full` once before continuing.
763
765
 
764
766
  Version bumps are manual. Run `sks versioning bump` only when preparing release metadata; SKS will not create `.git/hooks/pre-commit` or auto-bump during ordinary commits.
765
767
 
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "2.0.15"
79
+ version = "2.0.17"
80
80
  dependencies = [
81
81
  "serde_json",
82
82
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "2.0.15"
3
+ version = "2.0.17"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
4
4
  fn main() {
5
5
  let mut args = std::env::args().skip(1);
6
6
  match args.next().as_deref() {
7
- Some("--version") => println!("sks-rs 2.0.15"),
7
+ Some("--version") => println!("sks-rs 2.0.17"),
8
8
  Some("compact-info") => {
9
9
  let mut input = String::new();
10
10
  let _ = io::stdin().read_to_string(&mut input);
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schema": "sks.dist-build-stamp.v1",
3
3
  "package_name": "sneakoscope",
4
- "package_version": "2.0.15",
5
- "source_digest": "18f7432c59dd0bbd8090697c2cd4e0c4681d05923e3086f4a96cdc4e0b420280",
6
- "source_file_count": 2160,
7
- "built_at_source_time": 1780893056447
4
+ "package_version": "2.0.17",
5
+ "source_digest": "1c6ef84350a97acdfd592ae544ec9054e2ee0a997076e725bc99b771c4693cf2",
6
+ "source_file_count": 2201,
7
+ "built_at_source_time": 1780974441836
8
8
  }
package/dist/bin/sks.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const FAST_PACKAGE_VERSION = '2.0.15';
2
+ const FAST_PACKAGE_VERSION = '2.0.17';
3
3
  const args = process.argv.slice(2);
4
4
  try {
5
5
  if (args[0] === '--agent' && args[1] === 'worker') {
@@ -119,7 +119,7 @@ export const COMMANDS = {
119
119
  commit: entry('stable', 'Create a simple git commit', 'dist/commands/commit.js', directCommand(() => import('../commands/commit.js'), 'dist/commands/commit.js')),
120
120
  'commit-and-push': entry('stable', 'Create a simple git commit and push', 'dist/commands/commit-and-push.js', directCommand(() => import('../commands/commit-and-push.js'), 'dist/commands/commit-and-push.js')),
121
121
  dfix: entry('stable', 'Run DFix diagnose/plan/patch/verify loop', 'dist/core/commands/dfix-command.js', commandArgsCommand(() => import('../core/commands/dfix-command.js'), 'dfixCommand', 'dist/core/commands/dfix-command.js')),
122
- team: entry('beta', 'Create and observe Team missions', 'dist/core/commands/team-command.js', argsCommand(() => import('../core/commands/team-command.js'), 'team', 'dist/core/commands/team-command.js')),
122
+ team: entry('beta', 'Deprecated alias. New execution redirects to Naruto; legacy observe/watch remains.', 'dist/core/commands/team-command.js', argsCommand(() => import('../core/commands/team-command.js'), 'team', 'dist/core/commands/team-command.js')),
123
123
  agent: entry('beta', 'Run native multi-session agent missions', 'dist/core/commands/agent-command.js', argsCommand(() => import('../core/commands/agent-command.js'), 'agentCommand', 'dist/core/commands/agent-command.js')),
124
124
  'with-local-llm': entry('beta', 'Enable or inspect local Ollama worker backend', 'dist/core/commands/local-model-command.js', argsCommand(() => import('../core/commands/local-model-command.js'), 'localModelCommand', 'dist/core/commands/local-model-command.js')),
125
125
  naruto: entry('labs', 'Run $Naruto shadow-clone swarm (up to 100 parallel sessions)', 'dist/core/commands/naruto-command.js', argsCommand(() => import('../core/commands/naruto-command.js'), 'narutoCommand', 'dist/core/commands/naruto-command.js')),
@@ -8,10 +8,20 @@ import { writeRouteCompletionProof } from '../core/proof/route-adapter.js';
8
8
  import { finalizeRouteWithProof } from '../core/proof/route-finalizer.js';
9
9
  import { renderProofMarkdown, writeCompletionProof } from '../core/proof/proof-writer.js';
10
10
  import { validateCompletionProof } from '../core/proof/validation.js';
11
+ import { buildRuntimeProofSummary, renderRuntimeProofSummary } from '../core/agents/runtime-proof-summary.js';
11
12
  export async function run(_command, args = []) {
12
13
  const root = await projectRoot();
13
14
  const action = args[0] || 'show';
14
15
  const rest = args.slice(1);
16
+ if (action === 'latest' && !flag(args, '--completion')) {
17
+ const runtime = await tryRuntimeProofSummary(root);
18
+ if (runtime) {
19
+ if (flag(args, '--json'))
20
+ return printJson(runtime);
21
+ console.log(renderRuntimeProofSummary(runtime));
22
+ return;
23
+ }
24
+ }
15
25
  if (action === 'show' || action === 'latest') {
16
26
  const proof = await withFreshSummaries(root, await readLatestProof(root));
17
27
  if (flag(args, '--json') || action === 'latest')
@@ -122,6 +132,17 @@ export async function run(_command, args = []) {
122
132
  console.error('Usage: sks proof show|latest|validate|route <mission-id|latest>|finalize <mission-id|latest> [--route route] [--strict] [--mock] [--json]|export --md|repair latest|smoke [--json]');
123
133
  process.exitCode = 1;
124
134
  }
135
+ async function tryRuntimeProofSummary(root) {
136
+ try {
137
+ const summary = await buildRuntimeProofSummary(root, 'latest');
138
+ if (summary.blockers.includes('parallel_runtime_proof_missing') && summary.blockers.includes('agent_scheduler_state_missing'))
139
+ return null;
140
+ return summary;
141
+ }
142
+ catch {
143
+ return null;
144
+ }
145
+ }
125
146
  async function withFreshSummaries(root, proof) {
126
147
  const evidence = await collectProofEvidence(root);
127
148
  return {
@@ -1,4 +1,4 @@
1
- import { renderZellijSlotPaneFromArtifacts } from '../core/zellij/zellij-slot-pane-renderer.js';
1
+ import { renderZellijSlotPaneFromArtifacts, renderZellijSlotPaneStatusFromArtifacts } from '../core/zellij/zellij-slot-pane-renderer.js';
2
2
  export async function run(_command = 'zellij-slot-pane', args = []) {
3
3
  const artifactDir = readOption(args, '--artifact-dir', process.cwd()) || process.cwd();
4
4
  const artifactRoot = readOption(args, '--artifact-root', artifactDir) || artifactDir;
@@ -9,7 +9,13 @@ export async function run(_command = 'zellij-slot-pane', args = []) {
9
9
  const role = readOption(args, '--role', null);
10
10
  const mode = readOption(args, '--mode', 'compact-slots');
11
11
  const watch = hasFlag(args, '--watch');
12
+ const json = hasFlag(args, '--json');
12
13
  const intervalMs = Math.max(250, Number(readOption(args, '--interval-ms', '1000') || 1000));
14
+ if (json) {
15
+ const status = await renderZellijSlotPaneStatusFromArtifacts({ artifactDir, artifactRoot, missionId, slotId, generationIndex });
16
+ console.log(JSON.stringify(status, null, 2));
17
+ return;
18
+ }
13
19
  for (;;) {
14
20
  const text = await renderZellijSlotPaneFromArtifacts({ artifactDir, artifactRoot, missionId, slotId, generationIndex, backend, role, mode });
15
21
  process.stdout.write('\x1Bc' + text + '\n');
@@ -54,7 +54,7 @@ import { CODEX_AGENT_WORKER_RESULT_SCHEMA_ID, codexAgentWorkerResultSchema } fro
54
54
  import { resolveLocalCollaborationPolicy, localCollaborationParticipated } from '../local-llm/local-collaboration-policy.js';
55
55
  import { runFinalGptReviewStage } from '../pipeline/final-gpt-review-stage.js';
56
56
  import { selectFinalGptPatchSource } from '../pipeline/final-gpt-patch-stage.js';
57
- import { allocateWorkerWorktree } from '../git/git-worktree-manager.js';
57
+ import { allocateWorkerWorktree, allocateWorkerWorktreesBatch } from '../git/git-worktree-manager.js';
58
58
  import { exportGitWorktreeDiff } from '../git/git-worktree-diff.js';
59
59
  import { buildGitWorktreePatchEnvelope } from '../git/git-worktree-patch-envelope.js';
60
60
  import { checkpointWorkerWorktree } from '../git/git-worktree-checkpoint.js';
@@ -63,6 +63,7 @@ import { createGitIntegrationWorktree } from '../git/git-integration-worktree.js
63
63
  import { applyGitWorktreeMergeQueue } from '../git/git-worktree-merge-queue.js';
64
64
  import { crossRebaseIdleWorktrees } from '../git/git-worktree-cross-rebase.js';
65
65
  import { gitOutputLine, runGitCommand } from '../git/git-worktree-runner.js';
66
+ import { writeParallelRuntimeProof } from './parallel-runtime-proof.js';
66
67
  export async function runNativeAgentOrchestrator(opts = {}) {
67
68
  const root = path.resolve(opts.root || process.cwd());
68
69
  const prompt = String(opts.prompt || 'Native agent run');
@@ -289,9 +290,46 @@ export async function runNativeAgentOrchestrator(opts = {}) {
289
290
  diffs: [],
290
291
  checkpoints: [],
291
292
  cleanup: [],
293
+ prewarmed_allocations: [],
292
294
  blockers: []
293
295
  };
294
296
  await writeJsonAtomic(path.join(ledgerRoot, 'agent-git-worktree-runtime.json'), gitWorktreeRuntime);
297
+ const preparedWorktreeAllocations = new Map();
298
+ if (gitWorktreePolicy?.mode === 'git-worktree') {
299
+ const writeSlices = uniqueWritableSlicesForWorktrees(partition.slices, Math.max(1, targetActiveSlots));
300
+ if (writeSlices.length) {
301
+ const prewarmed = await allocateWorkerWorktreesBatch({
302
+ root: gitWorktreePolicy.main_repo_root || root,
303
+ missionId,
304
+ workers: writeSlices.map((slice, index) => ({
305
+ workerId: String(slice.owner_agent_id || slice.owner || `worker-${index + 1}`),
306
+ slotId: String(slice.owner_agent_id || slice.owner || `slot-${index + 1}`),
307
+ generationIndex: 1
308
+ })),
309
+ maxParallel: Math.min(targetActiveSlots, Number(process.env.SKS_NARUTO_GIT_WORKTREE_CAP || targetActiveSlots))
310
+ }).catch((err) => {
311
+ gitWorktreeRuntime.blockers.push('git_worktree_batch_prewarm_failed:' + (err instanceof Error ? err.message : String(err)));
312
+ gitWorktreeRuntime.ok = false;
313
+ return [];
314
+ });
315
+ gitWorktreeRuntime.prewarmed_allocations = prewarmed.map((allocation) => ({
316
+ worker_id: allocation.worker_id,
317
+ slot_id: allocation.slot_id,
318
+ ok: allocation.ok,
319
+ worktree_path: allocation.worktree_path,
320
+ branch: allocation.branch,
321
+ blockers: allocation.blockers
322
+ }));
323
+ for (const allocation of prewarmed) {
324
+ if (allocation.ok)
325
+ preparedWorktreeAllocations.set(String(allocation.worker_id), allocation);
326
+ else
327
+ gitWorktreeRuntime.blockers.push(...allocation.blockers);
328
+ }
329
+ gitWorktreeRuntime.ok = gitWorktreeRuntime.blockers.length === 0;
330
+ await writeJsonAtomic(path.join(ledgerRoot, 'agent-git-worktree-runtime.json'), gitWorktreeRuntime);
331
+ }
332
+ }
295
333
  const nativeCliSwarm = createNativeCliSessionSwarmRecorder(ledgerRoot, {
296
334
  missionId,
297
335
  requestedAgents: Number(opts.agents || roster.agent_count || targetActiveSlots),
@@ -329,7 +367,8 @@ export async function runNativeAgentOrchestrator(opts = {}) {
329
367
  agent,
330
368
  slice,
331
369
  policy: gitWorktreePolicy,
332
- runtime: gitWorktreeRuntime
370
+ runtime: gitWorktreeRuntime,
371
+ preparedAllocation: preparedWorktreeAllocations.get(String(agent.id || '')) || null
333
372
  });
334
373
  const runtimeAgent = workerWorktree ? { ...agent, worktree: workerWorktree.context } : agent;
335
374
  const runtimeSlice = workerWorktree ? { ...slice, worktree: workerWorktree.context } : slice;
@@ -432,6 +471,15 @@ export async function runNativeAgentOrchestrator(opts = {}) {
432
471
  }
433
472
  });
434
473
  await nativeCliSwarm.finalize();
474
+ const parallelRuntimeProof = await writeParallelRuntimeProof(ledgerRoot, missionId, {
475
+ requestedWorkers: Number(opts.agents || roster.agent_count || targetActiveSlots),
476
+ targetActiveSlots,
477
+ visiblePanes: visualLaneCount,
478
+ expectedWorkerRuntimeMs: targetActiveSlots >= 10 ? 8000 : targetActiveSlots >= 2 ? 2000 : 25,
479
+ minActiveWorkers: Math.min(targetActiveSlots, desiredWorkItemCount),
480
+ proofMode: opts.mock === true ? 'mock-process' : 'production',
481
+ requireWorkerPids: opts.nativeCliSwarm !== false && targetActiveSlots >= 16
482
+ });
435
483
  const results = scheduler.results;
436
484
  const nativeCliSessionProof = await writeNativeCliSessionProof(ledgerRoot, {
437
485
  requestedAgents: Number(opts.agents || roster.agent_count || targetActiveSlots),
@@ -600,6 +648,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
600
648
  gpt_final_arbiter: gptFinalArbiter,
601
649
  final_gpt_patch_stage: finalGptPatchStage,
602
650
  patch_swarm: patchSwarm,
651
+ parallel_runtime_proof: parallelRuntimeProof,
603
652
  proof
604
653
  };
605
654
  }
@@ -620,6 +669,22 @@ function withFinalGptPatchEnvelopes(results, patchEnvelopes = []) {
620
669
  next[0] = { ...next[0], patch_envelopes: patchEnvelopes };
621
670
  return next;
622
671
  }
672
+ function uniqueWritableSlicesForWorktrees(slices = [], limit) {
673
+ const selected = [];
674
+ const seenOwners = new Set();
675
+ for (const slice of Array.isArray(slices) ? slices : []) {
676
+ if (!Array.isArray(slice?.write_paths) || slice.write_paths.length === 0)
677
+ continue;
678
+ const owner = String(slice.owner_agent_id || slice.owner || slice.id || '');
679
+ if (!owner || seenOwners.has(owner))
680
+ continue;
681
+ seenOwners.add(owner);
682
+ selected.push(slice);
683
+ if (selected.length >= Math.max(1, limit))
684
+ break;
685
+ }
686
+ return selected;
687
+ }
623
688
  function applyNarutoWorkGraphToPartition(partition, graph, roster, targetActiveSlots, parentPrompt = '') {
624
689
  const activeRoster = (Array.isArray(roster?.roster) ? roster.roster : []).slice(0, Math.max(1, targetActiveSlots));
625
690
  const activeAgentIds = new Set(activeRoster.map((row) => String(row.id || '')).filter(Boolean));
@@ -873,7 +938,7 @@ async function prepareWorkerGitWorktree(input) {
873
938
  if (!sliceHasWritePaths && !agentWriteCapable)
874
939
  return null;
875
940
  const generationIndex = Math.max(1, Math.floor(Number(input.agent.generation_index || 1)));
876
- const allocation = await allocateWorkerWorktree({
941
+ const allocation = input.preparedAllocation || await allocateWorkerWorktree({
877
942
  repoRoot: input.policy.main_repo_root || input.root,
878
943
  missionId: input.missionId,
879
944
  workerId: String(input.agent.id || input.slice.id || 'worker'),