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.
Files changed (74) hide show
  1. package/README.md +8 -4
  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 +37 -8
  8. package/dist/cli/command-registry.js +2 -0
  9. package/dist/cli/install-helpers.js +8 -20
  10. package/dist/commands/doctor.js +23 -10
  11. package/dist/commands/zellij-slot-column-anchor.js +23 -0
  12. package/dist/commands/zellij-slot-pane.js +26 -0
  13. package/dist/core/agents/agent-orchestrator.js +255 -16
  14. package/dist/core/agents/agent-patch-schema.js +8 -1
  15. package/dist/core/agents/agent-role-config.js +92 -0
  16. package/dist/core/agents/native-cli-session-swarm.js +186 -71
  17. package/dist/core/commands/naruto-command.js +165 -11
  18. package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
  19. package/dist/core/fsx.js +1 -1
  20. package/dist/core/git/git-worktree-checkpoint.js +52 -0
  21. package/dist/core/git/git-worktree-cross-rebase.js +54 -0
  22. package/dist/core/git/git-worktree-merge-queue.js +69 -0
  23. package/dist/core/git/git-worktree-patch-envelope.js +8 -1
  24. package/dist/core/hooks-runtime.js +4 -0
  25. package/dist/core/init.js +3 -2
  26. package/dist/core/naruto/naruto-active-pool.js +35 -2
  27. package/dist/core/naruto/naruto-allocation-policy.js +99 -0
  28. package/dist/core/naruto/naruto-concurrency-governor.js +1 -1
  29. package/dist/core/naruto/naruto-real-worker-child.js +134 -0
  30. package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
  31. package/dist/core/naruto/naruto-rebalance-policy.js +36 -0
  32. package/dist/core/naruto/naruto-task-hints.js +71 -0
  33. package/dist/core/pipeline/finalize-pipeline-result.js +3 -1
  34. package/dist/core/pipeline/gpt-final-required.js +22 -2
  35. package/dist/core/version.js +1 -1
  36. package/dist/core/zellij/zellij-right-column-manager.js +111 -9
  37. package/dist/core/zellij/zellij-slot-column-anchor.js +59 -0
  38. package/dist/core/zellij/zellij-slot-pane-renderer.js +82 -0
  39. package/dist/core/zellij/zellij-ui-mode.js +16 -0
  40. package/dist/core/zellij/zellij-worker-pane-manager.js +104 -13
  41. package/dist/scripts/agent-role-config-repair-check.js +33 -0
  42. package/dist/scripts/git-worktree-checkpoint-check.js +20 -0
  43. package/dist/scripts/git-worktree-cross-rebase-check.js +27 -0
  44. package/dist/scripts/git-worktree-integration-primary-check.js +4 -2
  45. package/dist/scripts/git-worktree-integration-primary-runtime-check.js +20 -0
  46. package/dist/scripts/mutation-callsite-coverage-check.js +2 -1
  47. package/dist/scripts/naruto-actual-worker-control-plane-check.js +29 -0
  48. package/dist/scripts/naruto-allocation-policy-check.js +33 -0
  49. package/dist/scripts/naruto-extreme-parallelism-check.js +1 -1
  50. package/dist/scripts/naruto-extreme-parallelism-real-check.js +43 -0
  51. package/dist/scripts/naruto-orchestrator-runtime-source-check.js +11 -0
  52. package/dist/scripts/naruto-real-active-pool-check.js +3 -2
  53. package/dist/scripts/naruto-real-active-pool-runtime-check.js +55 -0
  54. package/dist/scripts/naruto-rebalance-policy-check.js +28 -0
  55. package/dist/scripts/naruto-shadow-clone-swarm-check.js +7 -3
  56. package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +29 -2
  57. package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
  58. package/dist/scripts/release-check-dynamic-execute.js +27 -1
  59. package/dist/scripts/release-check-dynamic.js +38 -11
  60. package/dist/scripts/release-check-stamp.js +7 -2
  61. package/dist/scripts/release-dag-full-coverage-check.js +15 -1
  62. package/dist/scripts/release-dynamic-performance-check.js +31 -1
  63. package/dist/scripts/release-gate-existence-audit.js +29 -33
  64. package/dist/scripts/release-readiness-report.js +14 -3
  65. package/dist/scripts/zellij-first-slot-down-stack-check.js +20 -0
  66. package/dist/scripts/zellij-first-slot-down-stack-real-check.js +16 -0
  67. package/dist/scripts/zellij-right-column-geometry-proof.js +155 -22
  68. package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
  69. package/dist/scripts/zellij-right-column-manager-check.js +9 -4
  70. package/dist/scripts/zellij-slot-column-anchor-check.js +24 -0
  71. package/dist/scripts/zellij-slot-only-ui-check.js +24 -0
  72. package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
  73. package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +11 -4
  74. 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 { closeWorkerInRightColumn, prepareWorkerInRightColumn, recordWorkerPaneInRightColumn } from './zellij-right-column-manager.js';
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: input.directionRequested || 'right',
64
- direction_applied: input.directionApplied || 'not_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 = rightColumn?.focusPaneId
110
- ? await focusZellijPaneById(input.sessionName, rightColumn.focusPaneId, cwd)
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, ...(rightColumn ? ['--near-current-pane'] : []), '--name', paneName, '--', 'sh', '-lc', input.workerCommand];
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
- rightColumn: rightColumn ? { mode: 'spawn-on-first-worker', focus_pane_id: rightColumn.focusPaneId, y_order: rightColumn.yOrder } : null,
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
- command: '<native-cli-worker-command>',
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
- assertGate(report.ok === true && report.applied_count === 1, 'git-worktree-diff must apply through merge queue', report);
21
- emitGate('git:worktree-integration-primary', { applied_count: report.applied_count });
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 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;
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 ceiling lifted) all complete, but live
72
- // concurrency is throttled to the host-safe cap (never the full 24 unless the host allows).
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: 240000, maxBuffer: 8 * 1024 * 1024 });
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,