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.
- package/README.md +5 -3
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/.sks-build-stamp.json +4 -4
- package/dist/bin/sks.js +1 -1
- package/dist/build-manifest.json +11 -8
- package/dist/core/agents/agent-orchestrator.js +279 -1
- package/dist/core/agents/agent-scheduler.js +12 -1
- package/dist/core/agents/agent-slot-pane-binding-proof.js +3 -3
- package/dist/core/agents/agent-work-queue.js +26 -2
- package/dist/core/agents/agent-worker-pipeline.js +2 -0
- package/dist/core/agents/native-cli-session-swarm.js +2 -2
- package/dist/core/commands/naruto-command.js +104 -51
- package/dist/core/fsx.js +1 -1
- package/dist/core/git/git-worktree-merge-queue.js +34 -14
- package/dist/core/naruto/naruto-rebalance-policy.js +15 -3
- package/dist/core/naruto/naruto-work-graph.js +13 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-slot-column-anchor.js +163 -4
- package/dist/core/zellij/zellij-worker-pane-manager.js +13 -7
- package/dist/scripts/agent-real-codex-in-zellij-worker-pane-check.js +8 -2
- package/dist/scripts/agent-slot-pane-binding-proof-check.js +4 -4
- package/dist/scripts/codex-sdk-release-review-pipeline-check.js +2 -1
- package/dist/scripts/codex-sdk-zellij-pane-binding-check.js +2 -2
- package/dist/scripts/git-worktree-cross-rebase-check.js +13 -1
- package/dist/scripts/git-worktree-merge-queue-check.js +1 -0
- package/dist/scripts/local-collab-worktree-gpt-final-apply-policy-check.js +63 -0
- package/dist/scripts/naruto-actual-worker-control-plane-check.js +30 -3
- package/dist/scripts/naruto-allocation-runtime-wiring-check.js +92 -0
- package/dist/scripts/naruto-orchestrator-runtime-source-check.js +65 -6
- package/dist/scripts/naruto-rebalance-policy-check.js +15 -2
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +1 -1
- package/dist/scripts/release-dag-full-coverage-check.js +4 -0
- package/dist/scripts/release-real-check.js +258 -77
- package/dist/scripts/zellij-first-slot-down-stack-check.js +1 -1
- package/dist/scripts/zellij-first-slot-down-stack-real-check.js +344 -4
- package/dist/scripts/zellij-right-column-manager-check.js +1 -1
- package/dist/scripts/zellij-slot-column-anchor-check.js +23 -2
- package/dist/scripts/zellij-slot-only-ui-check.js +3 -1
- package/dist/scripts/zellij-slot-renderer-proof-semantics-check.js +59 -0
- package/dist/scripts/zellij-worker-pane-manager-check.js +23 -1
- package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +21 -4
- 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.
|
|
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
|
|
24
|
-
- Naruto
|
|
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.
|
|
@@ -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.
|
|
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.
|
|
5
|
-
"source_digest": "
|
|
6
|
-
"source_file_count":
|
|
7
|
-
"built_at_source_time":
|
|
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
package/dist/build-manifest.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.dist-build.v2",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"package_version": "2.0.
|
|
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":
|
|
8
|
-
"compiled_js_count":
|
|
7
|
+
"compiled_file_count": 1111,
|
|
8
|
+
"compiled_js_count": 1111,
|
|
9
9
|
"compiled_dts_count": 0,
|
|
10
|
-
"source_digest": "
|
|
11
|
-
"source_file_count":
|
|
12
|
-
"source_files_hash": "
|
|
13
|
-
"source_list_hash": "
|
|
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
|
-
|
|
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
|
|
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 =
|
|
340
|
-
input.record.scaling_primitive =
|
|
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;
|