sneakoscope 2.0.11 → 2.0.12

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 (44) 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/build-manifest.json +11 -8
  8. package/dist/core/agents/agent-orchestrator.js +279 -1
  9. package/dist/core/agents/agent-scheduler.js +12 -1
  10. package/dist/core/agents/agent-slot-pane-binding-proof.js +3 -3
  11. package/dist/core/agents/agent-work-queue.js +26 -2
  12. package/dist/core/agents/agent-worker-pipeline.js +2 -0
  13. package/dist/core/agents/native-cli-session-swarm.js +2 -2
  14. package/dist/core/commands/naruto-command.js +104 -51
  15. package/dist/core/fsx.js +1 -1
  16. package/dist/core/git/git-worktree-merge-queue.js +34 -14
  17. package/dist/core/naruto/naruto-rebalance-policy.js +15 -3
  18. package/dist/core/naruto/naruto-work-graph.js +13 -0
  19. package/dist/core/version.js +1 -1
  20. package/dist/core/zellij/zellij-slot-column-anchor.js +163 -4
  21. package/dist/core/zellij/zellij-worker-pane-manager.js +13 -7
  22. package/dist/scripts/agent-real-codex-in-zellij-worker-pane-check.js +8 -2
  23. package/dist/scripts/agent-slot-pane-binding-proof-check.js +4 -4
  24. package/dist/scripts/codex-sdk-release-review-pipeline-check.js +2 -1
  25. package/dist/scripts/codex-sdk-zellij-pane-binding-check.js +2 -2
  26. package/dist/scripts/git-worktree-cross-rebase-check.js +13 -1
  27. package/dist/scripts/git-worktree-merge-queue-check.js +1 -0
  28. package/dist/scripts/local-collab-worktree-gpt-final-apply-policy-check.js +63 -0
  29. package/dist/scripts/naruto-actual-worker-control-plane-check.js +30 -3
  30. package/dist/scripts/naruto-allocation-runtime-wiring-check.js +92 -0
  31. package/dist/scripts/naruto-orchestrator-runtime-source-check.js +65 -6
  32. package/dist/scripts/naruto-rebalance-policy-check.js +15 -2
  33. package/dist/scripts/naruto-shadow-clone-swarm-check.js +1 -1
  34. package/dist/scripts/release-dag-full-coverage-check.js +4 -0
  35. package/dist/scripts/release-real-check.js +258 -77
  36. package/dist/scripts/zellij-first-slot-down-stack-check.js +1 -1
  37. package/dist/scripts/zellij-first-slot-down-stack-real-check.js +344 -4
  38. package/dist/scripts/zellij-right-column-manager-check.js +1 -1
  39. package/dist/scripts/zellij-slot-column-anchor-check.js +23 -2
  40. package/dist/scripts/zellij-slot-only-ui-check.js +3 -1
  41. package/dist/scripts/zellij-slot-renderer-proof-semantics-check.js +59 -0
  42. package/dist/scripts/zellij-worker-pane-manager-check.js +23 -1
  43. package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +21 -4
  44. package/package.json +5 -2
package/README.md CHANGED
@@ -16,12 +16,14 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
16
16
 
17
17
  ## Current Release
18
18
 
19
- SKS **2.0.11** is the slot-only Zellij and Naruto runtime stabilization release. Compact slot panes are now the default visual worker surface, the initial Zellij session stays main-only until the first visible worker is reserved, overflow workers continue headlessly with runtime evidence instead of opening excess panes, and dashboard panes stay opt-in. The release path remains manifest-backed through the v2 DAG runner, with real Zellij/Naruto/worktree proof gates split into `real-check`.
19
+ SKS **2.0.12** is the public-ready parallel runtime stabilization release. It closes release DAG coverage around Zellij slot renderer proof semantics, wires Naruto allocation/rebalance into the production scheduler, keeps pre-run worker smoke opt-in, and requires GPT Final approval before local/worktree candidate output can apply.
20
20
 
21
21
  What changed:
22
22
 
23
- - Zellij slot panes render compact worker slots without nested dashboard chrome, and right-column state records visible panes plus headless overflow lifecycle.
24
- - Naruto active-pool checks now exercise real child-worker spawn/result collection paths, including high-fanout overflow and completed-worker collection order.
23
+ - Zellij slot panes distinguish `slot_status_renderer` panes from Codex worker panes, and the first visible worker now stacks downward below the `SLOTS` anchor with real geometry proof available under `real-check`.
24
+ - Naruto allocation owners now flow into work graph items, scheduler slices, queue ownership, and worker runtime proof; inactive owners are rebalanced and active write conflicts stay out of concurrent execution.
25
+ - Naruto active-pool checks now exercise actual child-worker spawn/result collection paths while production source-of-truth stays with the agent orchestrator scheduler.
26
+ - Worktree candidate output requires GPT Final approval before apply; GPT `modified` output replaces candidate patches and GPT `rejected` blocks apply.
25
27
  - Visible Zellij reservations are capped before pane launch so concurrent worker starts cannot over-open the right column.
26
28
  - Git worktree integration now proves the primary repo receives validated worktree diffs, with rollback hash evidence recorded around the apply step.
27
29
  - Agent role config repair detects stale generated role files and rewrites structured GPT-5.5-compatible configs atomically.
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "2.0.11"
79
+ version = "2.0.12"
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.11"
3
+ version = "2.0.12"
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.11"),
7
+ Some("--version") => println!("sks-rs 2.0.12"),
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.11",
5
- "source_digest": "7f7339938c95fb98e1fb072192115eb0ca8cbc8136800d007b85d51fe413de19",
6
- "source_file_count": 2046,
7
- "built_at_source_time": 1780821479881
4
+ "package_version": "2.0.12",
5
+ "source_digest": "6f9f20ed184ebe714b41b9176d8414b7fded251a30591ada3c3bac53e49fcf61",
6
+ "source_file_count": 2053,
7
+ "built_at_source_time": 1780833723608
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.11';
2
+ const FAST_PACKAGE_VERSION = '2.0.12';
3
3
  const args = process.argv.slice(2);
4
4
  try {
5
5
  if (args[0] === '--agent' && args[1] === 'worker') {
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "schema": "sks.dist-build.v2",
3
- "version": "2.0.11",
4
- "package_version": "2.0.11",
3
+ "version": "2.0.12",
4
+ "package_version": "2.0.12",
5
5
  "typescript": true,
6
6
  "mjs_runtime_files": 0,
7
- "compiled_file_count": 1108,
8
- "compiled_js_count": 1108,
7
+ "compiled_file_count": 1111,
8
+ "compiled_js_count": 1111,
9
9
  "compiled_dts_count": 0,
10
- "source_digest": "7f7339938c95fb98e1fb072192115eb0ca8cbc8136800d007b85d51fe413de19",
11
- "source_file_count": 2046,
12
- "source_files_hash": "b94b6d01c22138f134b831e0e793a981744316d3e78bf457e00d81cadd9d5c07",
13
- "source_list_hash": "b94b6d01c22138f134b831e0e793a981744316d3e78bf457e00d81cadd9d5c07",
10
+ "source_digest": "6f9f20ed184ebe714b41b9176d8414b7fded251a30591ada3c3bac53e49fcf61",
11
+ "source_file_count": 2053,
12
+ "source_files_hash": "cf94f337fb28d923dd91214e01c2b80794f0d24659e7aaac0baf5c3110f1eb7a",
13
+ "source_list_hash": "cf94f337fb28d923dd91214e01c2b80794f0d24659e7aaac0baf5c3110f1eb7a",
14
14
  "src_mjs_runtime_files": 0,
15
15
  "dist_stamp_schema": "sks.dist-build-stamp.v1",
16
16
  "files": [
@@ -905,6 +905,7 @@
905
905
  "scripts/local-collab-gpt-final-availability-check.js",
906
906
  "scripts/local-collab-no-local-only-final-check.js",
907
907
  "scripts/local-collab-policy-check.js",
908
+ "scripts/local-collab-worktree-gpt-final-apply-policy-check.js",
908
909
  "scripts/local-llm-all-pipelines-check.js",
909
910
  "scripts/local-llm-cache-performance-check.js",
910
911
  "scripts/local-llm-capability-check.js",
@@ -942,6 +943,7 @@
942
943
  "scripts/naruto-active-pool-check.js",
943
944
  "scripts/naruto-actual-worker-control-plane-check.js",
944
945
  "scripts/naruto-allocation-policy-check.js",
946
+ "scripts/naruto-allocation-runtime-wiring-check.js",
945
947
  "scripts/naruto-concurrency-governor-check.js",
946
948
  "scripts/naruto-extreme-parallelism-check.js",
947
949
  "scripts/naruto-extreme-parallelism-real-check.js",
@@ -1117,6 +1119,7 @@
1117
1119
  "scripts/zellij-slot-column-anchor-check.js",
1118
1120
  "scripts/zellij-slot-only-ui-check.js",
1119
1121
  "scripts/zellij-slot-pane-renderer-check.js",
1122
+ "scripts/zellij-slot-renderer-proof-semantics-check.js",
1120
1123
  "scripts/zellij-spawn-on-demand-layout-check.js",
1121
1124
  "scripts/zellij-ui-design-check.js",
1122
1125
  "scripts/zellij-worker-pane-manager-check.js",
@@ -3,6 +3,8 @@ import { createMission, missionDir, setCurrent } from '../mission.js';
3
3
  import { exists, nowIso, readJson, readText, sha256, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
4
4
  import { buildAgentRoster, normalizeAgentConcurrency } from './agent-roster.js';
5
5
  import { buildAgentWorkPartition } from './agent-work-partition.js';
6
+ import { detectAgentLeaseConflicts } from './work-partition/conflict-detector.js';
7
+ import { buildNoOverlapProof } from './work-partition/no-overlap-proof.js';
6
8
  import { initializeAgentCentralLedger, appendAgentLedgerEvent, compactAgentLedger } from './agent-central-ledger.js';
7
9
  import { detectStaleAgentSessions, killTimedOutAgentSessions, openAgentSession, heartbeatAgentSession, collectAgentSession, completeAgentSession, closeAgentSession, writeAgentLifecycleAggregate, writeAgentLifecyclePolicy } from './agent-lifecycle.js';
8
10
  import { writeAgentConsensus } from './agent-consensus.js';
@@ -59,6 +61,8 @@ import { checkpointWorkerWorktree } from '../git/git-worktree-checkpoint.js';
59
61
  import { cleanupGitWorktree } from '../git/git-worktree-cleanup.js';
60
62
  import { createGitIntegrationWorktree } from '../git/git-integration-worktree.js';
61
63
  import { applyGitWorktreeMergeQueue } from '../git/git-worktree-merge-queue.js';
64
+ import { crossRebaseIdleWorktrees } from '../git/git-worktree-cross-rebase.js';
65
+ import { gitOutputLine, runGitCommand } from '../git/git-worktree-runner.js';
62
66
  export async function runNativeAgentOrchestrator(opts = {}) {
63
67
  const root = path.resolve(opts.root || process.cwd());
64
68
  const prompt = String(opts.prompt || 'Native agent run');
@@ -193,7 +197,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
193
197
  }
194
198
  };
195
199
  }
196
- const partition = await buildAgentWorkPartition(root, roster, prompt, {
200
+ let partition = await buildAgentWorkPartition(root, roster, prompt, {
197
201
  route,
198
202
  targetActiveSlots,
199
203
  desiredWorkItemCount,
@@ -204,12 +208,24 @@ export async function runNativeAgentOrchestrator(opts = {}) {
204
208
  strategyOwnershipPlan: strategyCompiled.file_ownership_plan,
205
209
  microWins: strategyCompiled.gate.micro_wins
206
210
  });
211
+ if (opts.narutoWorkGraph?.work_items?.length) {
212
+ partition = applyNarutoWorkGraphToPartition(partition, opts.narutoWorkGraph, roster, targetActiveSlots);
213
+ augmentVerificationRollbackDagForNaruto(strategyCompiled.verification_rollback_dag, partition.slices);
214
+ }
207
215
  await runAgentJanitor({ missionDir: dir, missionId, projectHash: namespace.root_hash });
208
216
  const ledgerRoot = await initializeAgentCentralLedger(dir, { missionId, roster, partition, route, prompt, dynamicScheduler: true });
209
217
  // Consult the TriWiki context pack (read-only) before dispatching workers, and
210
218
  // persist it as a proof artifact so the kernel proof references the wiki it acted on.
211
219
  const triwikiContext = await loadTriWikiRuntimeContext(root);
212
220
  await writeTriWikiContextArtifact(ledgerRoot, triwikiContext);
221
+ if (opts.narutoWorkGraph?.work_items?.length) {
222
+ await writeJsonAtomic(path.join(ledgerRoot, 'naruto-work-graph.json'), opts.narutoWorkGraph);
223
+ await writeJsonAtomic(path.join(ledgerRoot, 'naruto-runtime-wiring.json'), buildNarutoRuntimeWiringProof(partition, opts.narutoWorkGraph, roster, targetActiveSlots));
224
+ }
225
+ if (opts.narutoAllocationPolicy)
226
+ await writeJsonAtomic(path.join(ledgerRoot, 'naruto-allocation-policy.json'), opts.narutoAllocationPolicy);
227
+ if (opts.narutoRebalancePolicy)
228
+ await writeJsonAtomic(path.join(ledgerRoot, 'naruto-rebalance-policy.json'), opts.narutoRebalancePolicy);
213
229
  await writeAgentTaskGraph(ledgerRoot, partition.task_graph);
214
230
  await writeAdhdOrchestrationArtifacts(ledgerRoot, strategyCompiled.gate);
215
231
  await writeStrategyCompilerArtifacts(ledgerRoot, strategyCompiled);
@@ -344,6 +360,8 @@ export async function runNativeAgentOrchestrator(opts = {}) {
344
360
  const result = opts.nativeCliSwarm === false
345
361
  ? await runAgentByBackend(backend, runtimeAgent, runtimeSlice, backendOpts)
346
362
  : await nativeCliSwarm.launchWorker({ agent: runtimeAgent, slice: runtimeSlice, opts: backendOpts });
363
+ if (route === '$Naruto')
364
+ attachNarutoRuntimeProof(result, runtimeAgent, runtimeSlice);
347
365
  if (workerWorktree)
348
366
  await finalizeWorkerGitWorktree({
349
367
  root,
@@ -602,6 +620,247 @@ function withFinalGptPatchEnvelopes(results, patchEnvelopes = []) {
602
620
  next[0] = { ...next[0], patch_envelopes: patchEnvelopes };
603
621
  return next;
604
622
  }
623
+ function applyNarutoWorkGraphToPartition(partition, graph, roster, targetActiveSlots) {
624
+ const activeRoster = (Array.isArray(roster?.roster) ? roster.roster : []).slice(0, Math.max(1, targetActiveSlots));
625
+ const activeAgentIds = new Set(activeRoster.map((row) => String(row.id || '')).filter(Boolean));
626
+ const fallbackOwners = activeRoster.length ? activeRoster : [{ id: 'naruto_clone_001', role: 'verifier' }];
627
+ const referenceWorkItem = Array.isArray(partition?.task_graph?.work_items) ? partition.task_graph.work_items.find(Boolean) : null;
628
+ const sourceIntelligenceRefs = referenceWorkItem?.source_intelligence_refs || partition?.source_intelligence_refs || null;
629
+ const goalModeRef = referenceWorkItem?.goal_mode_ref || partition?.goal_mode_ref || null;
630
+ const strategyRefs = referenceWorkItem?.strategy_refs || partition?.strategy_refs || null;
631
+ const slices = (graph.work_items || []).map((item, index) => {
632
+ const requestedOwner = item.owner ? String(item.owner) : '';
633
+ const owner = requestedOwner && activeAgentIds.has(requestedOwner)
634
+ ? requestedOwner
635
+ : String(fallbackOwners[index % fallbackOwners.length]?.id || requestedOwner || `naruto_clone_${String(index + 1).padStart(3, '0')}`);
636
+ const sliceId = String(item.id || `NW-${String(index + 1).padStart(6, '0')}`);
637
+ const writePaths = normalizePathList(item.write_paths);
638
+ const readonlyPaths = normalizePathList(item.readonly_paths);
639
+ const targetPaths = normalizePathList(item.target_paths);
640
+ const verificationNodeId = writePaths.length ? `verify:${sliceId}` : null;
641
+ const rollbackNodeId = writePaths.length ? `rollback:${sliceId}` : null;
642
+ return {
643
+ id: sliceId,
644
+ owner_agent_id: owner,
645
+ owner,
646
+ lane: owner,
647
+ role: String(item.required_role || 'verifier'),
648
+ domain: String(item.allocation_hints?.domains?.[0] || item.kind || 'naruto'),
649
+ title: String(item.title || item.id || `Naruto work ${index + 1}`),
650
+ dependencies: Array.isArray(item.dependencies) ? item.dependencies.map(String) : [],
651
+ priority: index + 1,
652
+ required_persona_category: String(item.required_role || 'verifier'),
653
+ lease_requirements: Array.isArray(item.lease_requirements) ? item.lease_requirements : [],
654
+ generated_by: 'sks.naruto-work-graph.v1',
655
+ route_domain: String(item.kind || 'naruto'),
656
+ work_item_kind: String(item.kind || 'verification'),
657
+ target_paths: targetPaths,
658
+ readonly_paths: readonlyPaths,
659
+ write_paths: writePaths,
660
+ allocation_reason: item.allocation_reason || null,
661
+ allocation_score: item.allocation_score ?? null,
662
+ allocation_hints: item.allocation_hints || null,
663
+ allocation_original_owner: requestedOwner || null,
664
+ allocation_owner_rebalanced: Boolean(requestedOwner && owner !== requestedOwner),
665
+ micro_win_id: sliceId,
666
+ verification_node_id: verificationNodeId,
667
+ rollback_node_id: rollbackNodeId,
668
+ verification_required: item.verification_required === true,
669
+ source_intelligence_refs: sourceIntelligenceRefs,
670
+ goal_mode_ref: goalModeRef,
671
+ strategy_refs: strategyRefs,
672
+ max_attempts: 1,
673
+ description: [
674
+ String(item.title || item.id || 'Naruto work item'),
675
+ `Naruto owner: ${owner}`,
676
+ item.allocation_reason ? `Allocation: ${item.allocation_reason}` : null,
677
+ writePaths.length ? `Write paths: ${writePaths.join(', ')}` : 'Read-only or no-write work item.'
678
+ ].filter(Boolean).join('\n')
679
+ };
680
+ });
681
+ const workItems = (graph.work_items || []).map((item) => ({
682
+ ...item,
683
+ source_intelligence_refs: item.source_intelligence_refs || sourceIntelligenceRefs,
684
+ goal_mode_ref: item.goal_mode_ref || goalModeRef,
685
+ strategy_refs: item.strategy_refs || strategyRefs
686
+ }));
687
+ const leases = slices.flatMap((slice) => [
688
+ ...slice.write_paths.map((file, index) => ({
689
+ id: `${slice.id}:write:${index + 1}`,
690
+ agent_id: slice.owner_agent_id,
691
+ kind: 'write',
692
+ path: file,
693
+ domain: slice.domain,
694
+ status: 'active',
695
+ owner_agent: slice.owner_agent_id,
696
+ write_paths: slice.write_paths,
697
+ strategy_task_id: slice.id,
698
+ micro_win_id: slice.micro_win_id || slice.id,
699
+ verification_node_id: slice.verification_node_id || null,
700
+ rollback_node_id: slice.rollback_node_id || null,
701
+ protected_path_check: { ok: true, blockers: [] }
702
+ })),
703
+ ...slice.readonly_paths.map((file, index) => ({
704
+ id: `${slice.id}:read:${index + 1}`,
705
+ agent_id: slice.owner_agent_id,
706
+ kind: 'read',
707
+ path: file,
708
+ domain: slice.domain,
709
+ status: 'active',
710
+ owner_agent: slice.owner_agent_id,
711
+ write_paths: slice.write_paths,
712
+ strategy_task_id: slice.id,
713
+ micro_win_id: slice.micro_win_id || slice.id,
714
+ verification_node_id: slice.verification_node_id || null,
715
+ rollback_node_id: slice.rollback_node_id || null,
716
+ protected_path_check: { ok: true, blockers: [] }
717
+ }))
718
+ ]);
719
+ const conflict_report = detectAgentLeaseConflicts(leases);
720
+ const no_overlap_proof = buildNoOverlapProof(leases);
721
+ const taskGraph = partition.task_graph
722
+ ? {
723
+ ...partition.task_graph,
724
+ total_work_items: slices.length,
725
+ work_items: workItems,
726
+ route_work_count_summary: {
727
+ ...(partition.task_graph.route_work_count_summary || {}),
728
+ naruto_work_graph_items: slices.length,
729
+ allocation_owner_rebalanced_count: slices.filter((slice) => slice.allocation_owner_rebalanced).length
730
+ }
731
+ }
732
+ : null;
733
+ return {
734
+ ...partition,
735
+ ok: conflict_report.ok && no_overlap_proof.ok,
736
+ task_graph: taskGraph,
737
+ slices,
738
+ leases,
739
+ conflict_report,
740
+ no_overlap_proof,
741
+ source_intelligence_refs: sourceIntelligenceRefs,
742
+ goal_mode_ref: goalModeRef,
743
+ strategy_refs: strategyRefs,
744
+ blockers: [...(conflict_report.blockers || []), ...(no_overlap_proof.blockers || [])]
745
+ };
746
+ }
747
+ function augmentVerificationRollbackDagForNaruto(dag, slices) {
748
+ if (!dag || !Array.isArray(dag.nodes) || !Array.isArray(slices))
749
+ return dag;
750
+ const byId = new Set(dag.nodes.map((node) => String(node.id || '')).filter(Boolean));
751
+ for (const slice of slices) {
752
+ const sliceId = String(slice?.id || '');
753
+ if (!sliceId)
754
+ continue;
755
+ const writePaths = normalizePathList(slice.write_paths);
756
+ if (!byId.has(sliceId)) {
757
+ dag.nodes.push({
758
+ id: sliceId,
759
+ kind: writePaths.length ? 'write' : 'verification',
760
+ depends_on: [],
761
+ proof_artifact: writePaths.length ? 'agent-patch-queue.json' : 'agent-worker-result.json'
762
+ });
763
+ byId.add(sliceId);
764
+ }
765
+ if (!writePaths.length)
766
+ continue;
767
+ const verificationNodeId = String(slice.verification_node_id || `verify:${sliceId}`);
768
+ const rollbackNodeId = String(slice.rollback_node_id || `rollback:${sliceId}`);
769
+ if (!byId.has(verificationNodeId)) {
770
+ dag.nodes.push({
771
+ id: verificationNodeId,
772
+ kind: 'verification',
773
+ depends_on: [sliceId],
774
+ proof_artifact: 'agent-patch-verification-results.json'
775
+ });
776
+ byId.add(verificationNodeId);
777
+ }
778
+ if (!byId.has(rollbackNodeId)) {
779
+ dag.nodes.push({
780
+ id: rollbackNodeId,
781
+ kind: 'rollback',
782
+ depends_on: [sliceId, verificationNodeId],
783
+ proof_artifact: 'agent-patch-rollback-proof.json'
784
+ });
785
+ byId.add(rollbackNodeId);
786
+ }
787
+ }
788
+ dag.rollback_ready = true;
789
+ dag.verification_ready = true;
790
+ if (dag.validation?.blockers?.length)
791
+ dag.validation = { ok: true, blockers: [] };
792
+ return dag;
793
+ }
794
+ function buildNarutoRuntimeWiringProof(partition, graph, roster, targetActiveSlots) {
795
+ const activeAgentIds = new Set((Array.isArray(roster?.roster) ? roster.roster : []).slice(0, Math.max(1, targetActiveSlots)).map((row) => String(row.id || '')).filter(Boolean));
796
+ const slices = Array.isArray(partition?.slices) ? partition.slices : [];
797
+ const activeWriteConflicts = slices.flatMap((slice) => normalizePathList(slice.write_paths));
798
+ const duplicateActiveWrites = activeWriteConflicts.filter((file, index, all) => all.indexOf(file) !== index);
799
+ const ownerPreserved = slices.every((slice) => !slice.allocation_original_owner || slice.allocation_owner_rebalanced || slice.owner_agent_id === slice.allocation_original_owner);
800
+ const inactiveOwnersRebalanced = slices.every((slice) => !slice.allocation_original_owner || activeAgentIds.has(slice.allocation_original_owner) || slice.allocation_owner_rebalanced);
801
+ const blockers = [
802
+ ...(slices.length === Number(graph?.work_items?.length || 0) ? [] : ['naruto_runtime_slice_count_mismatch']),
803
+ ...(ownerPreserved ? [] : ['naruto_runtime_owner_not_preserved']),
804
+ ...(inactiveOwnersRebalanced ? [] : ['naruto_runtime_inactive_owner_not_rebalanced']),
805
+ ...(duplicateActiveWrites.length ? ['naruto_runtime_duplicate_write_paths_in_partition'] : [])
806
+ ];
807
+ return {
808
+ schema: 'sks.naruto-runtime-wiring.v1',
809
+ generated_at: nowIso(),
810
+ ok: blockers.length === 0,
811
+ source_of_truth: 'naruto-work-graph',
812
+ scheduler_slice_count: slices.length,
813
+ work_graph_item_count: Number(graph?.work_items?.length || 0),
814
+ owner_preserved: ownerPreserved,
815
+ inactive_owners_rebalanced: inactiveOwnersRebalanced,
816
+ write_conflict_free_partition: duplicateActiveWrites.length === 0,
817
+ slice_owners: slices.map((slice) => ({
818
+ id: slice.id,
819
+ owner_agent_id: slice.owner_agent_id,
820
+ original_owner: slice.allocation_original_owner || null,
821
+ rebalanced: slice.allocation_owner_rebalanced === true,
822
+ write_paths: slice.write_paths || [],
823
+ dependencies: slice.dependencies || []
824
+ })),
825
+ blockers
826
+ };
827
+ }
828
+ function attachNarutoRuntimeProof(result, agent, slice) {
829
+ const controlPlane = result?.codex_child_report || result?.codex_sdk_thread || result?.backend_router_report || null;
830
+ const selectedBackend = String(result?.backend_router_report?.selected_backend || result?.backend || '');
831
+ const actualWorkerControlPlane = selectedBackend === 'codex-sdk' || selectedBackend === 'local-llm'
832
+ ? Boolean(controlPlane?.sdk_thread_id || controlPlane?.worker_result_path || result?.codex_child_report?.worker_result_path)
833
+ : false;
834
+ result.naruto_runtime = {
835
+ schema: 'sks.naruto-worker-runtime-proof.v1',
836
+ source_of_truth: 'agent-orchestrator-scheduler',
837
+ actual_worker_control_plane: actualWorkerControlPlane,
838
+ work_item_id: String(slice?.id || result?.task_slice_id || ''),
839
+ owner: String(slice?.owner_agent_id || slice?.owner || agent?.id || ''),
840
+ allocation_reason: slice?.allocation_reason || null,
841
+ rebalance_generation: Number(slice?.allocation_owner_rebalanced === true ? 1 : 0),
842
+ selected_backend: selectedBackend || null,
843
+ explicit_fake_backend: selectedBackend === 'fake',
844
+ control_plane_result: controlPlane
845
+ ? {
846
+ worker_result_path: controlPlane.worker_result_path || null,
847
+ sdk_thread_id: controlPlane.sdk_thread_id || null,
848
+ sdk_run_id: controlPlane.sdk_run_id || null,
849
+ structured_output_valid: controlPlane.structured_output_valid === true,
850
+ stream_event_count: Number(controlPlane.stream_event_count || 0)
851
+ }
852
+ : null
853
+ };
854
+ if (result.naruto_runtime.control_plane_result)
855
+ result.control_plane_result = result.naruto_runtime.control_plane_result;
856
+ result.verification = {
857
+ status: result.verification?.status || 'not_run',
858
+ checks: [...(result.verification?.checks || []), 'naruto-agent-orchestrator-scheduler-source-of-truth']
859
+ };
860
+ }
861
+ function normalizePathList(values) {
862
+ return (Array.isArray(values) ? values : []).map((file) => String(file || '').replace(/\\/g, '/').replace(/^\.\/+/, '').replace(/\/+$/, '')).filter(Boolean);
863
+ }
605
864
  async function prepareWorkerGitWorktree(input) {
606
865
  if (input.policy?.mode !== 'git-worktree')
607
866
  return null;
@@ -1075,6 +1334,24 @@ async function runGitWorktreeIntegrationPrimary(root, ledgerRoot, missionId, ent
1075
1334
  checkpoints
1076
1335
  })
1077
1336
  : null;
1337
+ const integrationHead = mainApplyReport?.ok
1338
+ ? gitOutputLine(await runGitCommand(repoRoot, ['rev-parse', 'HEAD']).catch(() => ({ ok: false, stdout: '' })))
1339
+ : null;
1340
+ const crossRebase = integrationHead
1341
+ ? await crossRebaseIdleWorktrees({
1342
+ integrationHead,
1343
+ workers: diffs
1344
+ .filter((diff) => diff.worktree_path)
1345
+ .map((diff) => ({
1346
+ worker_id: diff.worker_id,
1347
+ worktree_path: diff.worktree_path,
1348
+ branch: diff.branch,
1349
+ state: 'done'
1350
+ }))
1351
+ })
1352
+ : null;
1353
+ if (crossRebase)
1354
+ await writeJsonAtomic(path.join(ledgerRoot, 'git-worktree-cross-rebase-report.json'), crossRebase);
1078
1355
  const rollbackEvidence = mainApplyReport?.ok
1079
1356
  ? await completeGitWorktreeRollbackPlan(repoRoot, rollbackPlan.rollback)
1080
1357
  : rollbackPlan;
@@ -1120,6 +1397,7 @@ async function runGitWorktreeIntegrationPrimary(root, ledgerRoot, missionId, ent
1120
1397
  conflicted_entry_ids: conflictedEntryIds,
1121
1398
  merge_queue: queueReport,
1122
1399
  main_repo_apply: mainApplyReport,
1400
+ cross_rebase: crossRebase,
1123
1401
  rollback_evidence: rollbackEvidence,
1124
1402
  apply_results: applyResults,
1125
1403
  blockers: reportBlockers
@@ -115,7 +115,11 @@ export async function runAgentScheduler(input) {
115
115
  break;
116
116
  const generationIndex = slot.generation_count + 1;
117
117
  const provisionalSessionId = `${slot.slot_id}-gen-${generationIndex}`;
118
- const workItem = leaseNextWorkItem(queue, provisionalSessionId);
118
+ const workItem = leaseNextWorkItem(queue, provisionalSessionId, {
119
+ slotId: slot.slot_id,
120
+ agentId: String(slot.persona_assignment?.agent_id || ''),
121
+ activeWritePaths: activeWritePaths(queue)
122
+ });
119
123
  if (!workItem)
120
124
  break;
121
125
  const generation = createAgentSessionGeneration({
@@ -314,6 +318,13 @@ function buildAgentForGeneration(slot, generation, workItem) {
314
318
  goal_mode_ref: generation.goal_mode_ref
315
319
  };
316
320
  }
321
+ function activeWritePaths(queue) {
322
+ return queue.items
323
+ .filter((item) => item.status === 'running')
324
+ .flatMap((item) => Array.isArray(item.slice?.write_paths) ? item.slice.write_paths : [])
325
+ .map((file) => String(file || '').replace(/\\/g, '/').replace(/^\.\/+/, '').replace(/\/+$/, ''))
326
+ .filter(Boolean);
327
+ }
317
328
  function delay(ms) {
318
329
  return new Promise((resolve) => setTimeout(resolve, ms));
319
330
  }
@@ -14,9 +14,9 @@ export async function evaluateAgentSlotPaneBindingProof(root, input = {}) {
14
14
  const summary = await readJson(path.join(root, 'agent-native-cli-session-swarm.json'), null);
15
15
  const ledger = await readJsonl(path.join(root, 'agent-zellij-pane-launch-ledger.jsonl'));
16
16
  const zellijRecords = Array.isArray(summary?.records)
17
- ? summary.records.filter((record) => record.scaling_primitive === 'native_cli_process_in_zellij_worker_pane')
17
+ ? summary.records.filter((record) => record.scaling_primitive === 'native_cli_process_in_zellij_worker_pane' || record.scaling_primitive === 'native_cli_process_with_zellij_slot_renderer')
18
18
  : [];
19
- const paneLedgers = ledger.filter((row) => row.scaling_primitive === 'native_cli_process_in_zellij_worker_pane' || row.pane_kind === 'worker_codex_sdk');
19
+ const paneLedgers = ledger.filter((row) => row.scaling_primitive === 'native_cli_process_in_zellij_worker_pane' || row.scaling_primitive === 'native_cli_process_with_zellij_slot_renderer' || row.pane_kind === 'worker_codex_sdk' || row.pane_kind === 'slot_status_renderer');
20
20
  const uniqueKeys = new Set();
21
21
  const duplicates = [];
22
22
  for (const row of zellijRecords) {
@@ -29,7 +29,7 @@ export async function evaluateAgentSlotPaneBindingProof(root, input = {}) {
29
29
  const zellijPaneWorkerSessions = Number(summary?.zellij_pane_worker_sessions || 0);
30
30
  const blockers = [
31
31
  ...(input.requireZellij && !zellijRecords.length ? ['slot_pane_binding_zellij_records_missing'] : []),
32
- ...(zellijRecords.some((record) => record.pane_kind !== 'worker_codex_sdk') ? ['slot_pane_binding_wrong_pane_kind'] : []),
32
+ ...(zellijRecords.some((record) => record.pane_kind !== 'worker_codex_sdk' && record.pane_kind !== 'slot_status_renderer') ? ['slot_pane_binding_wrong_pane_kind'] : []),
33
33
  ...(zellijRecords.some((record) => !isRealZellijWorkerPaneIdSource(record.zellij_pane_id_source)) ? ['slot_pane_binding_synthetic_or_missing_pane_id_source'] : []),
34
34
  ...(zellijRecords.some((record) => !record.zellij_pane_id) ? ['slot_pane_binding_pane_id_missing'] : []),
35
35
  ...(zellijRecords.some((record) => !record.sdk_thread_id) ? ['slot_pane_binding_sdk_thread_id_missing'] : []),
@@ -44,8 +44,15 @@ export function pendingWorkItems(queue) {
44
44
  .filter((item) => item.status === 'pending' && item.dependencies.every((dep) => completed.has(dep)))
45
45
  .sort((a, b) => a.priority - b.priority || a.id.localeCompare(b.id));
46
46
  }
47
- export function leaseNextWorkItem(queue, sessionId) {
48
- const item = pendingWorkItems(queue)[0];
47
+ export function leaseNextWorkItem(queue, sessionId, opts = {}) {
48
+ const activeWritePaths = new Set((opts.activeWritePaths || []).map(normalizePath).filter(Boolean));
49
+ const ready = pendingWorkItems(queue).filter((candidate) => {
50
+ const writePaths = sliceWritePaths(candidate);
51
+ return writePaths.every((file) => !activeWritePaths.has(file));
52
+ });
53
+ const item = ready.find((candidate) => ownerMatches(candidate, opts))
54
+ || ready.find((candidate) => !candidateOwner(candidate))
55
+ || ready[0];
49
56
  if (!item)
50
57
  return null;
51
58
  item.status = 'running';
@@ -54,6 +61,23 @@ export function leaseNextWorkItem(queue, sessionId) {
54
61
  queue.updated_at = nowIso();
55
62
  return item;
56
63
  }
64
+ function ownerMatches(item, opts) {
65
+ const owner = candidateOwner(item);
66
+ if (!owner)
67
+ return false;
68
+ return owner === opts.slotId || owner === opts.agentId;
69
+ }
70
+ function candidateOwner(item) {
71
+ const slice = item.slice || {};
72
+ return String(slice.owner_agent_id || slice.owner || slice.lane || '').trim();
73
+ }
74
+ function sliceWritePaths(item) {
75
+ const paths = Array.isArray(item.slice?.write_paths) ? item.slice.write_paths : [];
76
+ return paths.map((file) => normalizePath(String(file))).filter(Boolean);
77
+ }
78
+ function normalizePath(file) {
79
+ return String(file || '').replace(/\\/g, '/').replace(/^\.\/+/, '').replace(/\/+$/, '');
80
+ }
57
81
  export function completeWorkItem(queue, itemId, sessionId, status, reason = null) {
58
82
  const item = queue.items.find((row) => row.id === itemId);
59
83
  if (!item)
@@ -55,6 +55,8 @@ export function validateAgentWorkerResult(result) {
55
55
  ...(result?.source_intelligence_refs === undefined ? {} : { source_intelligence_refs: result.source_intelligence_refs }),
56
56
  ...(result?.goal_mode_ref === undefined ? {} : { goal_mode_ref: result.goal_mode_ref }),
57
57
  ...(result?.follow_up_work_items === undefined ? {} : { follow_up_work_items: followUps.accepted }),
58
+ ...(result?.naruto_runtime === undefined ? {} : { naruto_runtime: result.naruto_runtime }),
59
+ ...(result?.control_plane_result === undefined ? {} : { control_plane_result: result.control_plane_result }),
58
60
  recursion_guard: { ok: guard.ok, violations: guard.violations },
59
61
  verification: normalizeVerification(result?.verification)
60
62
  };
@@ -336,8 +336,8 @@ class NativeCliSessionSwarmRecorder {
336
336
  input.record.zellij_create_session = paneRecord.create_session;
337
337
  input.record.zellij_launch = paneRecord.launch;
338
338
  input.record.zellij_worker_pane = path.join(input.workerDirRel, 'zellij-worker-pane.json');
339
- input.record.pane_kind = 'worker_codex_sdk';
340
- input.record.scaling_primitive = 'native_cli_process_in_zellij_worker_pane';
339
+ input.record.pane_kind = paneRecord.pane_kind;
340
+ input.record.scaling_primitive = paneRecord.scaling_primitive;
341
341
  input.record.provider = paneRecord.provider;
342
342
  input.record.service_tier = paneRecord.service_tier;
343
343
  input.record.provider_context = paneRecord.provider_context;