sneakoscope 2.0.9 → 2.0.11
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 +8 -4
- 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 +37 -8
- package/dist/cli/command-registry.js +2 -0
- package/dist/cli/install-helpers.js +8 -20
- package/dist/commands/doctor.js +23 -10
- package/dist/commands/zellij-slot-column-anchor.js +23 -0
- package/dist/commands/zellij-slot-pane.js +26 -0
- package/dist/core/agents/agent-orchestrator.js +255 -16
- package/dist/core/agents/agent-patch-schema.js +8 -1
- package/dist/core/agents/agent-role-config.js +92 -0
- package/dist/core/agents/native-cli-session-swarm.js +186 -71
- package/dist/core/commands/naruto-command.js +165 -11
- package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
- package/dist/core/fsx.js +1 -1
- package/dist/core/git/git-worktree-checkpoint.js +52 -0
- package/dist/core/git/git-worktree-cross-rebase.js +54 -0
- package/dist/core/git/git-worktree-merge-queue.js +69 -0
- package/dist/core/git/git-worktree-patch-envelope.js +8 -1
- package/dist/core/hooks-runtime.js +4 -0
- package/dist/core/init.js +3 -2
- package/dist/core/naruto/naruto-active-pool.js +35 -2
- package/dist/core/naruto/naruto-allocation-policy.js +99 -0
- package/dist/core/naruto/naruto-concurrency-governor.js +1 -1
- package/dist/core/naruto/naruto-real-worker-child.js +134 -0
- package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
- package/dist/core/naruto/naruto-rebalance-policy.js +36 -0
- package/dist/core/naruto/naruto-task-hints.js +71 -0
- package/dist/core/pipeline/finalize-pipeline-result.js +3 -1
- package/dist/core/pipeline/gpt-final-required.js +22 -2
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-right-column-manager.js +111 -9
- package/dist/core/zellij/zellij-slot-column-anchor.js +59 -0
- package/dist/core/zellij/zellij-slot-pane-renderer.js +82 -0
- package/dist/core/zellij/zellij-ui-mode.js +16 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +104 -13
- package/dist/scripts/agent-role-config-repair-check.js +33 -0
- package/dist/scripts/git-worktree-checkpoint-check.js +20 -0
- package/dist/scripts/git-worktree-cross-rebase-check.js +27 -0
- package/dist/scripts/git-worktree-integration-primary-check.js +4 -2
- package/dist/scripts/git-worktree-integration-primary-runtime-check.js +20 -0
- package/dist/scripts/mutation-callsite-coverage-check.js +2 -1
- package/dist/scripts/naruto-actual-worker-control-plane-check.js +29 -0
- package/dist/scripts/naruto-allocation-policy-check.js +33 -0
- package/dist/scripts/naruto-extreme-parallelism-check.js +1 -1
- package/dist/scripts/naruto-extreme-parallelism-real-check.js +43 -0
- package/dist/scripts/naruto-orchestrator-runtime-source-check.js +11 -0
- package/dist/scripts/naruto-real-active-pool-check.js +3 -2
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +55 -0
- package/dist/scripts/naruto-rebalance-policy-check.js +28 -0
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +7 -3
- package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +29 -2
- package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
- package/dist/scripts/release-check-dynamic-execute.js +27 -1
- package/dist/scripts/release-check-dynamic.js +38 -11
- package/dist/scripts/release-check-stamp.js +7 -2
- package/dist/scripts/release-dag-full-coverage-check.js +15 -1
- package/dist/scripts/release-dynamic-performance-check.js +31 -1
- package/dist/scripts/release-gate-existence-audit.js +29 -33
- package/dist/scripts/release-readiness-report.js +14 -3
- package/dist/scripts/zellij-first-slot-down-stack-check.js +20 -0
- package/dist/scripts/zellij-first-slot-down-stack-real-check.js +16 -0
- package/dist/scripts/zellij-right-column-geometry-proof.js +155 -22
- package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
- package/dist/scripts/zellij-right-column-manager-check.js +9 -4
- package/dist/scripts/zellij-slot-column-anchor-check.js +24 -0
- package/dist/scripts/zellij-slot-only-ui-check.js +24 -0
- package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
- package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +11 -4
- package/package.json +22 -5
|
@@ -4,7 +4,8 @@ import { providerPaneLabel } from '../provider/provider-badge.js';
|
|
|
4
4
|
import { resolveProviderContext } from '../provider/provider-context.js';
|
|
5
5
|
import { runZellij } from './zellij-command.js';
|
|
6
6
|
import { extractZellijPaneIdFromOutput } from './zellij-lane-runtime.js';
|
|
7
|
-
import {
|
|
7
|
+
import { buildZellijSlotColumnAnchorCommand } from './zellij-slot-column-anchor.js';
|
|
8
|
+
import { closeWorkerInRightColumn, prepareWorkerInRightColumn, recordSlotColumnAnchorInRightColumn, recordWorkerPaneInRightColumn } from './zellij-right-column-manager.js';
|
|
8
9
|
export const ZELLIJ_WORKER_PANE_SCHEMA = 'sks.zellij-worker-pane.v1';
|
|
9
10
|
export const ZELLIJ_WORKER_PANE_EVENT_SCHEMA = 'sks.zellij-worker-pane-event.v1';
|
|
10
11
|
export function buildWorkerPaneName(slotId, generationIndex) {
|
|
@@ -25,11 +26,13 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
25
26
|
const blockers = input.blockers || [];
|
|
26
27
|
const providerContext = normalizePaneProviderContext(input.providerContext, input.serviceTier);
|
|
27
28
|
const paneTitle = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.statusLabel || input.status, input.worktree || null);
|
|
29
|
+
const directionRequested = input.directionRequested || 'right';
|
|
30
|
+
const directionApplied = input.directionApplied || 'not_applied';
|
|
28
31
|
return {
|
|
29
32
|
schema: ZELLIJ_WORKER_PANE_SCHEMA,
|
|
30
33
|
generated_at: now,
|
|
31
34
|
updated_at: now,
|
|
32
|
-
ok: blockers.length === 0 && isRealZellijWorkerPaneIdSource(paneIdSource) && Boolean(input.paneId),
|
|
35
|
+
ok: blockers.length === 0 && (paneIdSource === 'zellij_worker_headless_overflow' || (isRealZellijWorkerPaneIdSource(paneIdSource) && Boolean(input.paneId))),
|
|
33
36
|
status: input.status || 'launching',
|
|
34
37
|
mission_id: input.missionId,
|
|
35
38
|
session_name: input.sessionName,
|
|
@@ -52,16 +55,21 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
52
55
|
stdout_log: input.stdoutLog,
|
|
53
56
|
stderr_log: input.stderrLog,
|
|
54
57
|
parent_child_transport: 'worker-result-json-and-heartbeat',
|
|
55
|
-
scaling_primitive: 'native_cli_process_in_zellij_worker_pane',
|
|
56
|
-
command: '<native-cli-worker-command>',
|
|
58
|
+
scaling_primitive: input.scalingPrimitive || 'native_cli_process_in_zellij_worker_pane',
|
|
59
|
+
command: String(input.workerCommand || '').includes('zellij-slot-pane') ? '<zellij-slot-pane-renderer-command>' : '<native-cli-worker-command>',
|
|
57
60
|
create_session: input.createSession || null,
|
|
58
61
|
launch: input.launch || null,
|
|
59
62
|
pane_reconciliation: input.paneReconciliation || null,
|
|
60
63
|
opened_at: now,
|
|
61
64
|
closed_at: null,
|
|
62
65
|
close: null,
|
|
63
|
-
direction_requested:
|
|
64
|
-
direction_applied:
|
|
66
|
+
direction_requested: directionRequested,
|
|
67
|
+
direction_applied: directionApplied,
|
|
68
|
+
column_creation_direction_requested: input.columnCreationDirectionRequested ?? null,
|
|
69
|
+
column_creation_direction_applied: input.columnCreationDirectionApplied ?? null,
|
|
70
|
+
worker_direction_requested: input.workerDirectionRequested || 'down',
|
|
71
|
+
worker_direction_applied: input.workerDirectionApplied || (directionApplied === 'down' ? 'down' : directionApplied === 'unknown' ? 'unknown' : 'not_applied'),
|
|
72
|
+
slot_column_anchor_pane_id: input.slotColumnAnchorPaneId || null,
|
|
65
73
|
right_column: input.rightColumn || null,
|
|
66
74
|
sdk_thread_id: input.sdkThreadId || null,
|
|
67
75
|
sdk_run_id: input.sdkRunId || null,
|
|
@@ -96,6 +104,7 @@ export async function openWorkerPane(input) {
|
|
|
96
104
|
cwd,
|
|
97
105
|
worker: { slotId: input.slotId, generationIndex: input.generationIndex },
|
|
98
106
|
visiblePaneCap: input.visiblePaneCap || 1,
|
|
107
|
+
uiMode: input.uiMode || 'compact-slots',
|
|
99
108
|
dashboardSnapshot: {
|
|
100
109
|
...(input.dashboardSnapshot || {}),
|
|
101
110
|
mode: String(input.dashboardSnapshot?.mode || 'naruto'),
|
|
@@ -104,12 +113,80 @@ export async function openWorkerPane(input) {
|
|
|
104
113
|
}
|
|
105
114
|
})
|
|
106
115
|
: null;
|
|
116
|
+
if (rightColumn?.placement === 'headless') {
|
|
117
|
+
const record = buildWorkerPaneArtifact({
|
|
118
|
+
...input,
|
|
119
|
+
paneId: null,
|
|
120
|
+
paneIdSource: 'zellij_worker_headless_overflow',
|
|
121
|
+
createSession,
|
|
122
|
+
launch: null,
|
|
123
|
+
paneReconciliation: null,
|
|
124
|
+
directionRequested: 'down',
|
|
125
|
+
directionApplied: 'not_applied',
|
|
126
|
+
columnCreationDirectionRequested: null,
|
|
127
|
+
columnCreationDirectionApplied: 'not_applied',
|
|
128
|
+
workerDirectionRequested: 'down',
|
|
129
|
+
workerDirectionApplied: 'not_applied',
|
|
130
|
+
slotColumnAnchorPaneId: rightColumn.state.slot_column_anchor_pane_id || null,
|
|
131
|
+
rightColumn: {
|
|
132
|
+
mode: 'spawn-on-first-worker',
|
|
133
|
+
focus_pane_id: null,
|
|
134
|
+
y_order: null,
|
|
135
|
+
slot_column_anchor_pane_id: rightColumn.state.slot_column_anchor_pane_id || null
|
|
136
|
+
},
|
|
137
|
+
status: 'running',
|
|
138
|
+
providerContext,
|
|
139
|
+
serviceTier: input.serviceTier || providerContext.service_tier,
|
|
140
|
+
scalingPrimitive: 'native_cli_process_headless_with_slot_dashboard',
|
|
141
|
+
blockers: []
|
|
142
|
+
});
|
|
143
|
+
await writeWorkerPaneArtifact(root, record);
|
|
144
|
+
await appendWorkerPaneEvent(root, 'worker_headless_overflow', input, {
|
|
145
|
+
slot_id: input.slotId,
|
|
146
|
+
generation_index: input.generationIndex,
|
|
147
|
+
reason: `visible_pane_cap:${input.visiblePaneCap || 1}`
|
|
148
|
+
});
|
|
149
|
+
return record;
|
|
150
|
+
}
|
|
107
151
|
const paneName = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.statusLabel || 'running', input.worktree || null);
|
|
152
|
+
let slotColumnAnchorPaneId = rightColumn?.state.slot_column_anchor_pane_id || null;
|
|
153
|
+
let anchorLaunch = null;
|
|
154
|
+
let columnCreationDirectionRequested = null;
|
|
155
|
+
let columnCreationDirectionApplied = null;
|
|
156
|
+
if (rightColumn && !rightColumn.focusPaneId && !slotColumnAnchorPaneId) {
|
|
157
|
+
columnCreationDirectionRequested = 'right';
|
|
158
|
+
const anchorCommand = buildZellijSlotColumnAnchorCommand({
|
|
159
|
+
cliPath: path.join(packageRoot(), 'dist', 'bin', 'sks.js'),
|
|
160
|
+
missionId: input.missionId,
|
|
161
|
+
mode: input.uiMode || 'compact-slots',
|
|
162
|
+
artifactRoot: root,
|
|
163
|
+
watch: true
|
|
164
|
+
});
|
|
165
|
+
anchorLaunch = createSession.ok
|
|
166
|
+
? await runZellij(['--session', input.sessionName, 'action', 'new-pane', '--direction', 'right', '--name', 'SLOTS', '--', 'sh', '-lc', anchorCommand], {
|
|
167
|
+
cwd,
|
|
168
|
+
timeoutMs: 5000,
|
|
169
|
+
optional: false
|
|
170
|
+
})
|
|
171
|
+
: null;
|
|
172
|
+
slotColumnAnchorPaneId = anchorLaunch?.ok ? extractZellijPaneIdFromOutput(anchorLaunch.stdout_tail) : null;
|
|
173
|
+
columnCreationDirectionApplied = anchorLaunch?.ok ? (slotColumnAnchorPaneId ? 'right' : 'unknown') : 'not_applied';
|
|
174
|
+
if (slotColumnAnchorPaneId) {
|
|
175
|
+
await recordSlotColumnAnchorInRightColumn({
|
|
176
|
+
root,
|
|
177
|
+
...(input.projectRoot ? { projectRoot: input.projectRoot } : {}),
|
|
178
|
+
missionId: input.missionId,
|
|
179
|
+
sessionName: input.sessionName,
|
|
180
|
+
paneId: slotColumnAnchorPaneId
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const focusPaneId = rightColumn?.focusPaneId || slotColumnAnchorPaneId || null;
|
|
108
185
|
const directionRequested = rightColumn ? 'down' : 'right';
|
|
109
|
-
const focus =
|
|
110
|
-
? await focusZellijPaneById(input.sessionName,
|
|
186
|
+
const focus = focusPaneId
|
|
187
|
+
? await focusZellijPaneById(input.sessionName, focusPaneId, cwd)
|
|
111
188
|
: null;
|
|
112
|
-
const newPaneArgs = ['--session', input.sessionName, 'action', 'new-pane', '--direction', directionRequested, ...(
|
|
189
|
+
const newPaneArgs = ['--session', input.sessionName, 'action', 'new-pane', '--direction', directionRequested, ...(directionRequested === 'down' ? ['--near-current-pane'] : []), '--name', paneName, '--', 'sh', '-lc', input.workerCommand];
|
|
113
190
|
let launch = createSession.ok
|
|
114
191
|
? await runZellij(newPaneArgs, {
|
|
115
192
|
cwd,
|
|
@@ -119,9 +196,9 @@ export async function openWorkerPane(input) {
|
|
|
119
196
|
: null;
|
|
120
197
|
let directionApplied = launch?.ok ? directionRequested : 'not_applied';
|
|
121
198
|
if (createSession.ok && launch && !launch.ok) {
|
|
122
|
-
const fallbackArgs = rightColumn
|
|
199
|
+
const fallbackArgs = rightColumn && directionRequested === 'down'
|
|
123
200
|
? ['--session', input.sessionName, 'action', 'new-pane', '--direction', 'down', '--name', paneName, '--', 'sh', '-lc', input.workerCommand]
|
|
124
|
-
: ['--session', input.sessionName, 'action', 'new-pane', '--name', paneName, '--', 'sh', '-lc', input.workerCommand];
|
|
201
|
+
: ['--session', input.sessionName, 'action', 'new-pane', '--direction', directionRequested, '--name', paneName, '--', 'sh', '-lc', input.workerCommand];
|
|
125
202
|
const fallback = await runZellij(fallbackArgs, {
|
|
126
203
|
cwd,
|
|
127
204
|
timeoutMs: 5000,
|
|
@@ -146,6 +223,8 @@ export async function openWorkerPane(input) {
|
|
|
146
223
|
const blockers = [
|
|
147
224
|
...(createSession.ok ? [] : createSession.blockers.map((blocker) => `zellij_worker_session_${blocker}`)),
|
|
148
225
|
...(rightColumn && rightColumn.placement !== 'zellij-pane' ? [`zellij_worker_right_column_${rightColumn.placement}`] : []),
|
|
226
|
+
...(rightColumn && columnCreationDirectionRequested === 'right' && columnCreationDirectionApplied !== 'right' ? ['zellij_worker_slot_column_anchor_not_created'] : []),
|
|
227
|
+
...(anchorLaunch && !anchorLaunch.ok ? anchorLaunch.blockers.map((blocker) => `zellij_worker_slot_column_anchor_${blocker}`) : []),
|
|
149
228
|
...(launch && !launch.ok ? launch.blockers.map((blocker) => `zellij_worker_pane_${blocker}`) : []),
|
|
150
229
|
...(launch?.ok && !isRealZellijWorkerPaneIdSource(paneIdSource) ? ['zellij_worker_pane_id_real_source_missing'] : [])
|
|
151
230
|
];
|
|
@@ -159,11 +238,18 @@ export async function openWorkerPane(input) {
|
|
|
159
238
|
...(reconciledPane || {}),
|
|
160
239
|
focus_pane: focus,
|
|
161
240
|
focus_degraded: focus ? focus.ok !== true : false,
|
|
241
|
+
slot_column_anchor_pane_id: slotColumnAnchorPaneId,
|
|
242
|
+
slot_column_anchor_launch: anchorLaunch,
|
|
162
243
|
rename_pane: renamePane
|
|
163
244
|
},
|
|
164
245
|
directionRequested,
|
|
165
246
|
directionApplied,
|
|
166
|
-
|
|
247
|
+
columnCreationDirectionRequested,
|
|
248
|
+
columnCreationDirectionApplied,
|
|
249
|
+
workerDirectionRequested: 'down',
|
|
250
|
+
workerDirectionApplied: directionApplied === 'down' ? 'down' : directionApplied === 'unknown' ? 'unknown' : 'not_applied',
|
|
251
|
+
slotColumnAnchorPaneId,
|
|
252
|
+
rightColumn: rightColumn ? { mode: 'spawn-on-first-worker', focus_pane_id: focusPaneId, y_order: rightColumn.yOrder, slot_column_anchor_pane_id: slotColumnAnchorPaneId } : null,
|
|
167
253
|
status: blockers.length ? 'failed' : 'running',
|
|
168
254
|
providerContext,
|
|
169
255
|
serviceTier: input.serviceTier || providerContext.service_tier,
|
|
@@ -204,7 +290,12 @@ export async function openWorkerPane(input) {
|
|
|
204
290
|
provider_context: record.provider_context,
|
|
205
291
|
direction_requested: record.direction_requested,
|
|
206
292
|
direction_applied: record.direction_applied,
|
|
207
|
-
|
|
293
|
+
column_creation_direction_requested: record.column_creation_direction_requested || null,
|
|
294
|
+
column_creation_direction_applied: record.column_creation_direction_applied || null,
|
|
295
|
+
worker_direction_requested: record.worker_direction_requested,
|
|
296
|
+
worker_direction_applied: record.worker_direction_applied,
|
|
297
|
+
slot_column_anchor_pane_id: record.slot_column_anchor_pane_id || null,
|
|
298
|
+
command: record.command,
|
|
208
299
|
worker_artifact_dir: input.workerArtifactDir,
|
|
209
300
|
worker_result_path: input.resultPath,
|
|
210
301
|
heartbeat_path: input.heartbeatPath,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { assertGate, emitGate, importDist } from './sks-1-18-gate-lib.js';
|
|
7
|
+
const mod = await importDist('core/agents/agent-role-config.js');
|
|
8
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-role-repair-'));
|
|
9
|
+
fs.mkdirSync(path.join(root, '.sneakoscope', 'reports'), { recursive: true });
|
|
10
|
+
const plan = await mod.repairAgentRoleConfigs({ root, apply: false, codexHome: path.join(root, 'codex-home') });
|
|
11
|
+
const repair = await mod.repairAgentRoleConfigs({ root, apply: true, codexHome: path.join(root, 'codex-home'), reportPath: path.join(root, '.sneakoscope', 'reports', 'agent-role-config-repair.json') });
|
|
12
|
+
const analysisScout = path.join(root, '.codex', 'agents', 'analysis-scout.toml');
|
|
13
|
+
const staleRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-role-stale-'));
|
|
14
|
+
fs.mkdirSync(path.join(staleRoot, '.codex', 'agents'), { recursive: true });
|
|
15
|
+
fs.writeFileSync(path.join(staleRoot, '.codex', 'agents', 'analysis-scout.toml'), 'model = "gpt-5-codex"\nsandbox_mode = "read-only"\n');
|
|
16
|
+
const stalePlan = await mod.repairAgentRoleConfigs({ root: staleRoot, apply: false, codexHome: path.join(staleRoot, 'codex-home') });
|
|
17
|
+
const staleRepair = await mod.repairAgentRoleConfigs({ root: staleRoot, apply: true, codexHome: path.join(staleRoot, 'codex-home') });
|
|
18
|
+
const repairedText = fs.readFileSync(path.join(staleRoot, '.codex', 'agents', 'analysis-scout.toml'), 'utf8');
|
|
19
|
+
const report = {
|
|
20
|
+
schema: 'sks.agent-role-config-repair-check.v1',
|
|
21
|
+
plan_ok: plan.ok === true && plan.missing.includes('analysis-scout.toml'),
|
|
22
|
+
repair_ok: repair.ok === true,
|
|
23
|
+
analysis_scout_created: fs.existsSync(analysisScout),
|
|
24
|
+
created_matches_model: fs.readFileSync(analysisScout, 'utf8').includes('model = "gpt-5.5"'),
|
|
25
|
+
stale_detected: stalePlan.stale.includes('analysis-scout.toml'),
|
|
26
|
+
stale_repaired: staleRepair.repaired.includes('.codex/agents/analysis-scout.toml') && repairedText.includes('name = "analysis_scout"') && repairedText.includes('model = "gpt-5.5"'),
|
|
27
|
+
warnings_suppressed: repair.warnings_suppressed === true,
|
|
28
|
+
artifact_written: fs.existsSync(path.join(root, '.sneakoscope', 'reports', 'agent-role-config-repair.json'))
|
|
29
|
+
};
|
|
30
|
+
const ok = report.plan_ok && report.repair_ok && report.analysis_scout_created && report.created_matches_model && report.stale_detected && report.stale_repaired && report.warnings_suppressed && report.artifact_written;
|
|
31
|
+
assertGate(ok, 'doctor --fix must repair missing SKS-owned agent role configs', report);
|
|
32
|
+
emitGate('agent:role-config-repair', report);
|
|
33
|
+
//# sourceMappingURL=agent-role-config-repair-check.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
6
|
+
import { checkpointWorkerWorktree } from '../core/git/git-worktree-checkpoint.js';
|
|
7
|
+
import { runGitCommand } from '../core/git/git-worktree-runner.js';
|
|
8
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-worktree-checkpoint-'));
|
|
9
|
+
await runGitCommand(root, ['init']);
|
|
10
|
+
await runGitCommand(root, ['config', 'user.email', 'sks@example.test']);
|
|
11
|
+
await runGitCommand(root, ['config', 'user.name', 'SKS Test']);
|
|
12
|
+
fs.writeFileSync(path.join(root, 'a.txt'), 'a\n');
|
|
13
|
+
await runGitCommand(root, ['add', 'a.txt']);
|
|
14
|
+
await runGitCommand(root, ['commit', '-m', 'base']);
|
|
15
|
+
fs.writeFileSync(path.join(root, 'a.txt'), 'a2\n');
|
|
16
|
+
fs.writeFileSync(path.join(root, 'b.txt'), 'b\n');
|
|
17
|
+
const report = await checkpointWorkerWorktree({ worktreePath: root, repoRoot: root, workerId: 'W1', taskId: 'T1', mode: 'auto' });
|
|
18
|
+
assertGate(report.ok && report.mode_applied === 'checkpoint-commit' && Boolean(report.commit_hash), 'Git worktree checkpoint must create checkpoint commits for multi-file changes', report);
|
|
19
|
+
emitGate('git:worktree-checkpoint', report);
|
|
20
|
+
//# sourceMappingURL=git-worktree-checkpoint-check.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
6
|
+
import { crossRebaseIdleWorktrees } from '../core/git/git-worktree-cross-rebase.js';
|
|
7
|
+
import { runGitCommand, gitOutputLine } from '../core/git/git-worktree-runner.js';
|
|
8
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-worktree-cross-rebase-'));
|
|
9
|
+
await runGitCommand(root, ['init']);
|
|
10
|
+
await runGitCommand(root, ['config', 'user.email', 'sks@example.test']);
|
|
11
|
+
await runGitCommand(root, ['config', 'user.name', 'SKS Test']);
|
|
12
|
+
fs.writeFileSync(path.join(root, 'base.txt'), 'base\n');
|
|
13
|
+
await runGitCommand(root, ['add', 'base.txt']);
|
|
14
|
+
await runGitCommand(root, ['commit', '-m', 'base']);
|
|
15
|
+
const workerPath = path.join(root, '..', `worker-${process.pid}`);
|
|
16
|
+
await runGitCommand(root, ['worktree', 'add', workerPath, 'HEAD']);
|
|
17
|
+
fs.writeFileSync(path.join(root, 'integration.txt'), 'integration\n');
|
|
18
|
+
await runGitCommand(root, ['add', 'integration.txt']);
|
|
19
|
+
await runGitCommand(root, ['commit', '-m', 'integration']);
|
|
20
|
+
const head = gitOutputLine(await runGitCommand(root, ['rev-parse', 'HEAD']));
|
|
21
|
+
const report = await crossRebaseIdleWorktrees({
|
|
22
|
+
integrationHead: head,
|
|
23
|
+
workers: [{ worker_id: 'W1', worktree_path: workerPath, state: 'idle' }]
|
|
24
|
+
});
|
|
25
|
+
assertGate(report.ok && report.applied_count === 1, 'Idle worktrees must cross-rebase to the integration head', report);
|
|
26
|
+
emitGate('git:worktree-cross-rebase', report);
|
|
27
|
+
//# sourceMappingURL=git-worktree-cross-rebase-check.js.map
|
|
@@ -17,6 +17,8 @@ const integrationPath = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-integration-'
|
|
|
17
17
|
fs.rmSync(integrationPath, { recursive: true, force: true });
|
|
18
18
|
const integration = await managerMod.allocateWorkerWorktree({ repoRoot: repo, missionId: 'M-integrate', workerId: 'integration', slotId: 'integration' });
|
|
19
19
|
const report = await mergeMod.applyGitWorktreeMergeQueue({ integrationWorktreePath: integration.worktree_path, diffs: [diff] });
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const mainReport = await mergeMod.applyGitWorktreeMergeQueue({ integrationWorktreePath: repo, diffs: [diff] });
|
|
21
|
+
const mainContent = fs.readFileSync(path.join(repo, 'a.txt'), 'utf8');
|
|
22
|
+
assertGate(report.ok === true && report.applied_count === 1 && mainReport.ok === true && mainReport.applied_count === 1 && mainContent.includes('integrated'), 'git-worktree-diff must prevalidate in integration worktree and apply to main repo', { report, mainReport, mainContent });
|
|
23
|
+
emitGate('git:worktree-integration-primary', { applied_count: report.applied_count, main_applied_count: mainReport.applied_count });
|
|
22
24
|
//# sourceMappingURL=git-worktree-integration-primary-check.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
|
|
6
|
+
const orchestrator = fs.readFileSync(path.join(root, 'src/core/agents/agent-orchestrator.ts'), 'utf8');
|
|
7
|
+
const report = {
|
|
8
|
+
schema: 'sks.git-worktree-integration-primary-runtime-check.v1',
|
|
9
|
+
splits_worktree_entries: orchestrator.includes("entry.envelope?.source === 'git-worktree-diff'"),
|
|
10
|
+
uses_integration_worktree: orchestrator.includes('createGitIntegrationWorktree'),
|
|
11
|
+
uses_merge_queue: orchestrator.includes('applyGitWorktreeMergeQueue'),
|
|
12
|
+
applies_to_main_repo: orchestrator.includes('main_repo_apply') && orchestrator.includes('integrationWorktreePath: repoRoot'),
|
|
13
|
+
rollback_evidence: orchestrator.includes('rollback_evidence') && orchestrator.includes('captureGitWorktreeRollbackPlan') && orchestrator.includes('completeGitWorktreeRollbackPlan'),
|
|
14
|
+
bypasses_normal_apply: orchestrator.includes('const normalEntries') && orchestrator.includes('applyAgentPatchQueueEntry(root, entry') && orchestrator.includes('parallelEntries = disjointEntries'),
|
|
15
|
+
writes_report: orchestrator.includes('git-worktree-merge-queue-report.json')
|
|
16
|
+
};
|
|
17
|
+
const ok = report.splits_worktree_entries && report.uses_integration_worktree && report.uses_merge_queue && report.applies_to_main_repo && report.rollback_evidence && report.bypasses_normal_apply && report.writes_report;
|
|
18
|
+
assertGate(ok, 'git-worktree-diff entries must use integration merge queue primary path', report);
|
|
19
|
+
emitGate('git:worktree-integration-primary-runtime', report);
|
|
20
|
+
//# sourceMappingURL=git-worktree-integration-primary-runtime-check.js.map
|
|
@@ -17,6 +17,7 @@ const uncovered = [];
|
|
|
17
17
|
const GUARD_CALL = /\bguarded(WriteFile|Rm|Rename|Chmod|Xattr|Chflags|GlobalCodexConfigWrite|ProcessKill|PackageInstall|SkillSnapshotPromotion|Apply)\(/;
|
|
18
18
|
const RISKY = [
|
|
19
19
|
{ kind: 'write_file', token: 'fs.writeFile', re: /\bfs\.writeFile\(/ },
|
|
20
|
+
{ kind: 'write_file', token: 'fs.promises.writeFile', re: /\bfs\.promises\.writeFile\(/ },
|
|
20
21
|
{ kind: 'write_file', token: 'fsp.writeFile', re: /\bfsp\.writeFile\(/ },
|
|
21
22
|
{ kind: 'write_file', token: 'writeFileSync', re: /\b(?:fs\.)?writeFileSync\(/ },
|
|
22
23
|
{ kind: 'rm', token: 'fs.rm', re: /\bfs\.rm\(/ },
|
|
@@ -167,7 +168,7 @@ function processKillIsLivenessProbe(line) {
|
|
|
167
168
|
return /\bprocess\.kill\([^,\n]+,\s*0\s*\)/.test(line);
|
|
168
169
|
}
|
|
169
170
|
function codexHomeMutationOnLine(line) {
|
|
170
|
-
return /\b(?:writeTextAtomic|writeJsonAtomic|writeFileSync|fs\.writeFile|fsp\.writeFile|fs\.rm|fsp\.rm|fs\.rename|fsp\.rename|fs\.chmod|fsp\.chmod|copyFile|open)\b/.test(line)
|
|
171
|
+
return /\b(?:writeTextAtomic|writeJsonAtomic|writeFileSync|fs\.writeFile|fs\.promises\.writeFile|fsp\.writeFile|fs\.rm|fsp\.rm|fs\.rename|fsp\.rename|fs\.chmod|fsp\.chmod|copyFile|open)\b/.test(line)
|
|
171
172
|
&& /(?:~\/\.codex|CODEX_HOME|codexHome|codexLbHome|auth\.json|config\.toml)/.test(line);
|
|
172
173
|
}
|
|
173
174
|
function snippet(line) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
7
|
+
import { buildNarutoWorkGraph } from '../core/naruto/naruto-work-graph.js';
|
|
8
|
+
import { collectActualNarutoWorker, spawnActualNarutoWorker } from '../core/naruto/naruto-real-worker-runtime.js';
|
|
9
|
+
process.env.SKS_CODEX_SDK_FAKE = '1';
|
|
10
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-naruto-actual-worker-'));
|
|
11
|
+
const graph = buildNarutoWorkGraph({ requestedClones: 1, totalWorkItems: 1, readonly: true, writeCapable: false });
|
|
12
|
+
const item = graph.work_items[0];
|
|
13
|
+
const handle = await spawnActualNarutoWorker({
|
|
14
|
+
root,
|
|
15
|
+
missionId: `M-naruto-actual-worker-${process.pid}`,
|
|
16
|
+
item,
|
|
17
|
+
placement: { placement: 'headless', visible_index: null, reason: 'check' },
|
|
18
|
+
backend: 'fake',
|
|
19
|
+
visiblePaneCap: 0
|
|
20
|
+
});
|
|
21
|
+
const collected = await collectActualNarutoWorker(handle);
|
|
22
|
+
const result = JSON.parse(fs.readFileSync(path.join(handle.worker_artifact_dir, 'worker-result.json'), 'utf8'));
|
|
23
|
+
const ok = collected.ok === true
|
|
24
|
+
&& result.ok === true
|
|
25
|
+
&& result.control_plane_result?.worker_result_path
|
|
26
|
+
&& result.control_plane_result?.structured_output_valid === true;
|
|
27
|
+
assertGate(ok, 'Naruto actual worker must call Codex Control Plane and write structured result evidence', { collected, result });
|
|
28
|
+
emitGate('naruto:actual-worker-control-plane', { collected, result });
|
|
29
|
+
//# sourceMappingURL=naruto-actual-worker-control-plane-check.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
3
|
+
import { allocateNarutoTasksToWorkers, chooseNarutoTaskOwner } from '../core/naruto/naruto-allocation-policy.js';
|
|
4
|
+
const base = {
|
|
5
|
+
kind: 'implementation',
|
|
6
|
+
title: 'impl',
|
|
7
|
+
target_paths: ['src/core/naruto/runtime.ts'],
|
|
8
|
+
readonly_paths: [],
|
|
9
|
+
write_paths: ['src/core/naruto/runtime.ts'],
|
|
10
|
+
required_role: 'implementer',
|
|
11
|
+
write_allowed: true,
|
|
12
|
+
verification_required: true,
|
|
13
|
+
dependencies: [],
|
|
14
|
+
can_run_in_parallel_with: [],
|
|
15
|
+
conflicts_with: [],
|
|
16
|
+
estimated_cost: { tokens: 1, latency_ms: 1, cpu_weight: 1, memory_mb: 1, gpu_weight: 0 },
|
|
17
|
+
lease_requirements: [{ path: 'src/core/naruto/runtime.ts', kind: 'write' }],
|
|
18
|
+
acceptance: { requires_patch_envelope: true, requires_verification: true, requires_gpt_final: true }
|
|
19
|
+
};
|
|
20
|
+
const workers = [
|
|
21
|
+
{ id: 'w1', role: 'implementer', lane: 'src/core' },
|
|
22
|
+
{ id: 'w2', role: 'verifier', lane: 'src/scripts' }
|
|
23
|
+
];
|
|
24
|
+
const decision = chooseNarutoTaskOwner({ ...base, id: 'T1' }, workers);
|
|
25
|
+
const blocked = chooseNarutoTaskOwner({ ...base, id: 'T2', dependencies: ['T0'] }, workers);
|
|
26
|
+
const assignments = allocateNarutoTasksToWorkers([{ ...base, id: 'T1' }, { ...base, id: 'T2', required_role: 'verifier' }], workers);
|
|
27
|
+
const ok = decision.owner === 'w1'
|
|
28
|
+
&& decision.score >= 24
|
|
29
|
+
&& blocked.score === Number.NEGATIVE_INFINITY
|
|
30
|
+
&& assignments.length === 2;
|
|
31
|
+
assertGate(ok, 'Naruto allocation policy must score role/lane overlap and block incomplete dependencies with -Infinity', { decision, blocked, assignments });
|
|
32
|
+
emitGate('naruto:allocation-policy', { decision, blocked, assignments });
|
|
33
|
+
//# sourceMappingURL=naruto-allocation-policy-check.js.map
|
|
@@ -13,7 +13,7 @@ const governor = decideNarutoConcurrency({
|
|
|
13
13
|
});
|
|
14
14
|
const report = {
|
|
15
15
|
schema: 'sks.naruto-extreme-parallelism-check.v1',
|
|
16
|
-
ok: graph.total_work_items >= 200 && governor.safe_active_workers >= 16 && governor.safe_zellij_visible_panes <= governor.safe_active_workers && graph.mixed_work_kinds.length >= 6,
|
|
16
|
+
ok: graph.total_work_items >= 200 && governor.safe_active_workers >= 16 && governor.safe_zellij_visible_panes <= governor.safe_active_workers && governor.safe_zellij_visible_panes <= 8 && graph.mixed_work_kinds.length >= 6,
|
|
17
17
|
graph: { total_work_items: graph.total_work_items, mixed_work_kinds: graph.mixed_work_kinds, write_allowed_count: graph.write_allowed_count },
|
|
18
18
|
governor
|
|
19
19
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
7
|
+
import { buildNarutoWorkGraph } from '../core/naruto/naruto-work-graph.js';
|
|
8
|
+
import { decideNarutoConcurrency } from '../core/naruto/naruto-concurrency-governor.js';
|
|
9
|
+
import { runNarutoRealActivePool } from '../core/naruto/naruto-active-pool.js';
|
|
10
|
+
import { collectActualNarutoWorker, spawnActualNarutoWorker } from '../core/naruto/naruto-real-worker-runtime.js';
|
|
11
|
+
process.env.SKS_CODEX_SDK_FAKE = '1';
|
|
12
|
+
const graph = buildNarutoWorkGraph({ requestedClones: 100, totalWorkItems: 48, writeCapable: true, maxActiveWorkers: 12 });
|
|
13
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-naruto-extreme-real-'));
|
|
14
|
+
const missionId = `M-naruto-extreme-real-${process.pid}`;
|
|
15
|
+
const governor = decideNarutoConcurrency({
|
|
16
|
+
requestedClones: 100,
|
|
17
|
+
totalWorkItems: graph.total_work_items,
|
|
18
|
+
pendingWorkQueueSize: graph.total_work_items,
|
|
19
|
+
backend: 'fake',
|
|
20
|
+
hardware: { cores: 16, loadAverage: [1, 1, 1], freeMemoryBytes: 64 * 1024 * 1024 * 1024, totalMemoryBytes: 128 * 1024 * 1024 * 1024, fileDescriptorLimit: 8192, processCount: 100, terminalRows: 48, remoteApiRateLimitBudget: 32, localLlmMaxParallelRequests: 8 }
|
|
21
|
+
});
|
|
22
|
+
const target = { ...governor, safe_active_workers: Math.min(12, governor.safe_active_workers), safe_zellij_visible_panes: Math.min(4, governor.safe_zellij_visible_panes) };
|
|
23
|
+
const report = await runNarutoRealActivePool({
|
|
24
|
+
graph,
|
|
25
|
+
governor: target,
|
|
26
|
+
spawnWorker: async (item, placement) => spawnActualNarutoWorker({
|
|
27
|
+
root: tempRoot,
|
|
28
|
+
missionId,
|
|
29
|
+
item,
|
|
30
|
+
placement,
|
|
31
|
+
backend: 'fake',
|
|
32
|
+
visiblePaneCap: target.safe_zellij_visible_panes,
|
|
33
|
+
zellijSessionName: `sks-${missionId}`
|
|
34
|
+
}),
|
|
35
|
+
collectWorker: async (handle) => collectActualNarutoWorker(handle),
|
|
36
|
+
enqueueVerification: async () => undefined,
|
|
37
|
+
updateDashboard: async () => undefined
|
|
38
|
+
});
|
|
39
|
+
const actualArtifacts = report.worker_lifecycle.every((row) => row.pid && row.worker_artifact_dir && fs.existsSync(path.join(row.worker_artifact_dir, 'worker-result.json')));
|
|
40
|
+
const ok = report.ok && report.max_observed_active_workers >= Math.ceil(target.safe_active_workers * 0.8) && report.active_pool_utilization >= 0.8 && report.headless_workers > 0 && report.visible_workers <= graph.total_work_items && actualArtifacts;
|
|
41
|
+
assertGate(ok, 'Naruto extreme parallelism must use actual child process active-pool lifecycle near cap with headless overflow', { report, target, actualArtifacts, tempRoot });
|
|
42
|
+
emitGate('naruto:extreme-parallelism-real', report);
|
|
43
|
+
//# sourceMappingURL=naruto-extreme-parallelism-real-check.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
5
|
+
const source = fs.readFileSync(path.join(process.cwd(), 'src/core/commands/naruto-command.ts'), 'utf8');
|
|
6
|
+
const ok = source.includes("runtime_source_of_truth: 'agent-orchestrator-scheduler'")
|
|
7
|
+
&& source.includes("production_runtime_source_of_truth: 'agent-orchestrator-scheduler'")
|
|
8
|
+
&& source.includes('pre_run_smoke_never_owns_production_runtime');
|
|
9
|
+
assertGate(ok, 'Naruto production runtime source of truth must be the native agent orchestrator scheduler, not pre-run active-pool smoke', { ok });
|
|
10
|
+
emitGate('naruto:orchestrator-runtime-source', { ok });
|
|
11
|
+
//# sourceMappingURL=naruto-orchestrator-runtime-source-check.js.map
|
|
@@ -32,7 +32,8 @@ const report = await runNarutoRealActivePool({
|
|
|
32
32
|
dashboardEvents += 1;
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
|
-
const
|
|
35
|
+
const processEvidence = report.worker_lifecycle.every((row) => row.pid == null || row.worker_artifact_dir != null);
|
|
36
|
+
const ok = report.ok && spawned === graph.total_work_items && collected === graph.total_work_items && report.max_observed_active_workers >= target.safe_active_workers && dashboardEvents > graph.total_work_items && report.active_cap === target.safe_active_workers && processEvidence;
|
|
36
37
|
assertGate(ok, 'Naruto real active pool must run spawn/collect lifecycle and refill to cap', { report, spawned, collected, dashboardEvents, target });
|
|
37
|
-
emitGate('naruto:real-active-pool', { spawned, collected, max_observed_active_workers: report.max_observed_active_workers, refill_latency_ms_p95: report.refill_latency_ms_p95 });
|
|
38
|
+
emitGate('naruto:real-active-pool', { spawned, collected, active_cap: report.active_cap, max_observed_active_workers: report.max_observed_active_workers, refill_latency_ms_p95: report.refill_latency_ms_p95, active_pool_utilization: report.active_pool_utilization });
|
|
38
39
|
//# sourceMappingURL=naruto-real-active-pool-check.js.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
7
|
+
import { buildNarutoWorkGraph } from '../core/naruto/naruto-work-graph.js';
|
|
8
|
+
import { decideNarutoConcurrency } from '../core/naruto/naruto-concurrency-governor.js';
|
|
9
|
+
import { runNarutoRealActivePool } from '../core/naruto/naruto-active-pool.js';
|
|
10
|
+
import { collectActualNarutoWorker, spawnActualNarutoWorker } from '../core/naruto/naruto-real-worker-runtime.js';
|
|
11
|
+
process.env.SKS_CODEX_SDK_FAKE = '1';
|
|
12
|
+
const graph = buildNarutoWorkGraph({ requestedClones: 12, totalWorkItems: 24, writeCapable: false, maxActiveWorkers: 6 });
|
|
13
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-naruto-real-runtime-'));
|
|
14
|
+
const missionId = `M-naruto-real-runtime-${process.pid}`;
|
|
15
|
+
const governor = decideNarutoConcurrency({
|
|
16
|
+
requestedClones: 12,
|
|
17
|
+
totalWorkItems: graph.total_work_items,
|
|
18
|
+
pendingWorkQueueSize: graph.total_work_items,
|
|
19
|
+
backend: 'codex-sdk',
|
|
20
|
+
hardware: { cores: 8, freeMemoryBytes: 32 * 1024 * 1024 * 1024, totalMemoryBytes: 64 * 1024 * 1024 * 1024, fileDescriptorLimit: 4096, processCount: 100, terminalRows: 40, remoteApiRateLimitBudget: 8 }
|
|
21
|
+
});
|
|
22
|
+
let spawned = 0;
|
|
23
|
+
let collected = 0;
|
|
24
|
+
const target = { ...governor, safe_active_workers: Math.min(6, governor.safe_active_workers), safe_zellij_visible_panes: 3 };
|
|
25
|
+
const report = await runNarutoRealActivePool({
|
|
26
|
+
graph,
|
|
27
|
+
governor: target,
|
|
28
|
+
spawnWorker: async (item, placement) => {
|
|
29
|
+
spawned += 1;
|
|
30
|
+
return spawnActualNarutoWorker({
|
|
31
|
+
root: tempRoot,
|
|
32
|
+
missionId,
|
|
33
|
+
item,
|
|
34
|
+
placement,
|
|
35
|
+
backend: 'fake',
|
|
36
|
+
visiblePaneCap: target.safe_zellij_visible_panes,
|
|
37
|
+
zellijSessionName: `sks-${missionId}`
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
collectWorker: async (handle) => {
|
|
41
|
+
collected += 1;
|
|
42
|
+
return collectActualNarutoWorker(handle);
|
|
43
|
+
},
|
|
44
|
+
enqueueVerification: async () => undefined,
|
|
45
|
+
updateDashboard: async () => undefined
|
|
46
|
+
});
|
|
47
|
+
const processEvidence = report.worker_lifecycle.every((row) => row.pid && row.worker_artifact_dir);
|
|
48
|
+
const artifactEvidence = report.worker_lifecycle.every((row) => row.worker_artifact_dir
|
|
49
|
+
&& fs.existsSync(path.join(row.worker_artifact_dir, 'worker-heartbeat.jsonl'))
|
|
50
|
+
&& fs.existsSync(path.join(row.worker_artifact_dir, 'worker-result.json'))
|
|
51
|
+
&& fs.existsSync(path.join(row.worker_artifact_dir, 'codex-control', 'codex-control-proof.json')));
|
|
52
|
+
const ok = report.ok && spawned === graph.total_work_items && collected === graph.total_work_items && report.max_observed_active_workers >= target.safe_active_workers && report.active_pool_utilization >= 0.8 && processEvidence && artifactEvidence;
|
|
53
|
+
assertGate(ok, 'Naruto real active pool runtime must include actual child process, heartbeat, and result evidence', { report, spawned, collected, processEvidence, artifactEvidence, tempRoot });
|
|
54
|
+
emitGate('naruto:real-active-pool-runtime', report);
|
|
55
|
+
//# sourceMappingURL=naruto-real-active-pool-runtime-check.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
3
|
+
import { rebalanceNarutoReadyWork } from '../core/naruto/naruto-rebalance-policy.js';
|
|
4
|
+
const item = (id, dependencies = []) => ({
|
|
5
|
+
id,
|
|
6
|
+
kind: 'verification',
|
|
7
|
+
title: id,
|
|
8
|
+
target_paths: ['src/core/naruto/runtime.ts'],
|
|
9
|
+
readonly_paths: ['src/core/naruto/runtime.ts'],
|
|
10
|
+
write_paths: [],
|
|
11
|
+
required_role: 'verifier',
|
|
12
|
+
write_allowed: false,
|
|
13
|
+
verification_required: true,
|
|
14
|
+
dependencies,
|
|
15
|
+
can_run_in_parallel_with: [],
|
|
16
|
+
conflicts_with: [],
|
|
17
|
+
estimated_cost: { tokens: 1, latency_ms: 1, cpu_weight: 1, memory_mb: 1, gpu_weight: 0 },
|
|
18
|
+
lease_requirements: [],
|
|
19
|
+
acceptance: { requires_patch_envelope: false, requires_verification: true, requires_gpt_final: false }
|
|
20
|
+
});
|
|
21
|
+
const decisions = rebalanceNarutoReadyWork({
|
|
22
|
+
tasks: [item('A'), item('B', ['A'])],
|
|
23
|
+
workers: [{ id: 'idle-1', role: 'verifier', lane: 'src/core', alive: true, state: 'idle' }],
|
|
24
|
+
completedTaskIds: []
|
|
25
|
+
});
|
|
26
|
+
assertGate(decisions.length === 1 && decisions[0]?.task_id === 'A', 'Naruto rebalance must assign only dependency-ready pending work to idle workers', { decisions });
|
|
27
|
+
emitGate('naruto:rebalance-policy', { decisions });
|
|
28
|
+
//# sourceMappingURL=naruto-rebalance-policy-check.js.map
|
|
@@ -68,9 +68,10 @@ assertGate(lowFreeButCapable.cap >= 4, 'capable hosts must not collapse Naruto c
|
|
|
68
68
|
// heavy backend scales well past the old 16-core-derived ceiling toward 100.
|
|
69
69
|
const bigMemoryHost = roster.systemSafeNarutoConcurrency({ backend: 'codex-sdk', cores: 4, freeBytes: 48 * 1024 * 1024 * 1024, totalBytes: 64 * 1024 * 1024 * 1024 });
|
|
70
70
|
assertGate(bigMemoryHost.cap >= 64, 'a 64 GB host must allow >= 64 parallel codex-sdk workers regardless of core count (network-bound, memory-budgeted)', { bigMemoryHost });
|
|
71
|
-
// 6) End-to-end run: 24 clones (> standard 20
|
|
72
|
-
//
|
|
71
|
+
// 6) End-to-end run: 24 clones (> standard 20 -> ceiling lifted) all complete, while
|
|
72
|
+
// release verification keeps live slots bounded so the gate stays hermetic under DAG load.
|
|
73
73
|
const proofClones = 24;
|
|
74
|
+
const proofConcurrency = 6;
|
|
74
75
|
const cli = path.join(root, 'dist', 'bin', 'sks.js');
|
|
75
76
|
const isolatedWorktreeRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-naruto-shadow-wt-'));
|
|
76
77
|
const childEnv = { ...process.env, SKS_WORKTREE_ROOT: isolatedWorktreeRoot };
|
|
@@ -83,8 +84,9 @@ const run = spawnSync(process.execPath, [
|
|
|
83
84
|
'--clones', String(proofClones),
|
|
84
85
|
'--backend', 'fake',
|
|
85
86
|
'--work-items', String(proofClones),
|
|
87
|
+
'--concurrency', String(proofConcurrency),
|
|
86
88
|
'--json'
|
|
87
|
-
], { cwd: root, env: childEnv, encoding: 'utf8', timeout:
|
|
89
|
+
], { cwd: root, env: childEnv, encoding: 'utf8', timeout: 300000, maxBuffer: 8 * 1024 * 1024 });
|
|
88
90
|
assertGate(run.status === 0, 'sks naruto run must exit 0', { status: run.status, stderr: tail(run.stderr) });
|
|
89
91
|
const parsed = parseJson(run.stdout);
|
|
90
92
|
assertGate(parsed !== null, 'sks naruto run must emit JSON', { stdout: tail(run.stdout) });
|
|
@@ -96,6 +98,7 @@ assertGate(parsed.proof === 'passed', 'naruto run proof must pass', { proof: par
|
|
|
96
98
|
// Throttle invariant: active concurrency never exceeds the requested count nor the host cap.
|
|
97
99
|
assertGate(parsed.target_active_slots >= 1 && parsed.target_active_slots <= proofClones, 'active slots must be in [1, clones]', { target_active_slots: parsed.target_active_slots });
|
|
98
100
|
assertGate(parsed.target_active_slots <= fakeSafe.cap, 'active slots must be throttled to the system-safe cap', { target_active_slots: parsed.target_active_slots, cap: fakeSafe.cap });
|
|
101
|
+
assertGate(parsed.target_active_slots === proofConcurrency, 'release proof must keep Naruto live slots bounded while fan-out stays >20', { target_active_slots: parsed.target_active_slots, proofConcurrency });
|
|
99
102
|
// Task 9.1: fan-out (clones) and live concurrency (target_active_slots) are reported
|
|
100
103
|
// distinctly, and concurrency_capped truthfully reflects "N clones, running M at a time".
|
|
101
104
|
assertGate(typeof parsed.concurrency_capped === 'boolean', 'naruto run must report concurrency_capped', { concurrency_capped: parsed.concurrency_capped });
|
|
@@ -125,6 +128,7 @@ emitGate('naruto:shadow-clone-swarm', {
|
|
|
125
128
|
default_clamp: defaultSlots,
|
|
126
129
|
naruto_slots_at_100: narutoSlots,
|
|
127
130
|
proof_clones: proofClones,
|
|
131
|
+
proof_concurrency: proofConcurrency,
|
|
128
132
|
target_active_slots: parsed.target_active_slots,
|
|
129
133
|
fake_safe_cap: fakeSafe.cap,
|
|
130
134
|
heavy_safe_cap: heavySafe.cap,
|