sneakoscope 6.0.2 → 6.1.0

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 (242) hide show
  1. package/README.md +5 -3
  2. package/config/codex-releases/{rust-v0.142.0.json → rust-v0.144.1.json} +6 -6
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/cli/install-helpers.js +255 -440
  6. package/dist/cli/router.js +53 -4
  7. package/dist/commands/codex-app.js +8 -3
  8. package/dist/commands/codex-lb.js +169 -40
  9. package/dist/commands/codex.js +6 -5
  10. package/dist/commands/doctor.js +60 -26
  11. package/dist/commands/versioning.js +7 -0
  12. package/dist/config/skills-manifest.json +57 -57
  13. package/dist/core/agents/agent-central-ledger.js +9 -0
  14. package/dist/core/agents/agent-cleanup-executor.js +334 -41
  15. package/dist/core/agents/agent-cleanup.js +20 -1
  16. package/dist/core/agents/agent-command-surface.js +2 -1
  17. package/dist/core/agents/agent-effort-policy.js +46 -33
  18. package/dist/core/agents/agent-janitor.js +9 -10
  19. package/dist/core/agents/agent-namespace-safety.js +56 -0
  20. package/dist/core/agents/agent-orchestrator.js +26 -4
  21. package/dist/core/agents/agent-output-validator.js +1 -1
  22. package/dist/core/agents/agent-proof-evidence.js +16 -2
  23. package/dist/core/agents/agent-role-config.js +3 -6
  24. package/dist/core/agents/agent-roster.js +2 -2
  25. package/dist/core/agents/agent-runner-codex-exec.js +2 -0
  26. package/dist/core/agents/agent-runner-process.js +1 -0
  27. package/dist/core/agents/fast-mode-policy.js +3 -5
  28. package/dist/core/agents/native-cli-session-swarm.js +18 -1
  29. package/dist/core/agents/native-worker-backend-router.js +180 -108
  30. package/dist/core/agents/parallel-write-fixture.js +15 -10
  31. package/dist/core/agents/runtime-proof-summary.js +21 -3
  32. package/dist/core/agents/work-partition/repo-inventory.js +68 -7
  33. package/dist/core/code-structure.js +5 -4
  34. package/dist/core/codex/codex-config-guard.js +31 -9
  35. package/dist/core/codex-app/codex-app-fast-ui-repair.js +51 -20
  36. package/dist/core/codex-app/codex-app-restart.js +38 -8
  37. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +11 -3
  38. package/dist/core/codex-app/sks-menubar.js +100 -40
  39. package/dist/core/codex-app.js +60 -17
  40. package/dist/core/codex-compat/codex-hook-warning-detector.js +10 -1
  41. package/dist/core/codex-compat/codex-release-manifest.js +6 -6
  42. package/dist/core/codex-control/codex-0139-doctor-real-probe.js +7 -1
  43. package/dist/core/codex-control/codex-0139-image-path-real-probe.js +14 -8
  44. package/dist/core/codex-control/codex-0139-probe-runner.js +103 -28
  45. package/dist/core/codex-control/codex-0139-real-probe-summary.js +7 -3
  46. package/dist/core/codex-control/codex-0139-real-probes.js +21 -6
  47. package/dist/core/codex-control/codex-0139-sandbox-real-probe.js +39 -13
  48. package/dist/core/codex-control/codex-0139-web-search-probe.js +11 -8
  49. package/dist/core/codex-control/{codex-0142-capability.js → codex-0144-capability.js} +22 -22
  50. package/dist/core/codex-control/codex-0144-collab-agent-real-probe.js +63 -0
  51. package/dist/core/codex-control/codex-model-metadata.js +8 -4
  52. package/dist/core/codex-control/codex-multi-agent-event-normalizer.js +5 -1
  53. package/dist/core/codex-control/codex-reliability-shield.js +4 -1
  54. package/dist/core/codex-control/codex-sdk-adapter.js +53 -6
  55. package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
  56. package/dist/core/codex-control/codex-sdk-sandbox-policy.js +6 -3
  57. package/dist/core/codex-lb/codex-lb-env.js +107 -0
  58. package/dist/core/codex-lb/codex-lb-tool-catalog.js +478 -0
  59. package/dist/core/codex-native/codex-native-feature-broker.js +22 -22
  60. package/dist/core/codex-native/codex-native-feature-matrix.js +2 -2
  61. package/dist/core/codex-native/native-capability-postcheck.js +16 -8
  62. package/dist/core/codex-native/native-capability-repair-matrix.js +76 -27
  63. package/dist/core/codex-plugins/codex-plugin-json.js +67 -21
  64. package/dist/core/codex-plugins/codex-plugin-repair.js +118 -0
  65. package/dist/core/codex-runtime/codex-desktop-config-policy.js +306 -0
  66. package/dist/core/commands/agent-command.js +19 -0
  67. package/dist/core/commands/basic-cli.js +45 -24
  68. package/dist/core/commands/gc-command.js +27 -4
  69. package/dist/core/commands/image-ux-review-command.js +55 -24
  70. package/dist/core/commands/mad-sks-command.js +152 -132
  71. package/dist/core/commands/naruto-command.js +41 -10
  72. package/dist/core/commands/pipeline-command.js +1 -0
  73. package/dist/core/commands/wiki-command.js +179 -83
  74. package/dist/core/computer-use-live-evidence.js +166 -3
  75. package/dist/core/computer-use-status.js +5 -2
  76. package/dist/core/daemon/sksd-hook-daemon-entrypoint.js +2 -2
  77. package/dist/core/daemon/sksd-hook-daemon.js +171 -28
  78. package/dist/core/daemon/sksd-hook-dispatch.js +2 -2
  79. package/dist/core/dfix/verification-selector.js +6 -4
  80. package/dist/core/doctor/browser-use-repair.js +54 -13
  81. package/dist/core/doctor/codex-0139-doctor.js +3 -2
  82. package/dist/core/doctor/computer-use-repair.js +28 -39
  83. package/dist/core/doctor/doctor-codex-startup-repair.js +19 -9
  84. package/dist/core/doctor/doctor-context7-repair.js +1 -1
  85. package/dist/core/doctor/doctor-dirty-planner.js +1 -1
  86. package/dist/core/doctor/doctor-native-capability-repair.js +74 -3
  87. package/dist/core/doctor/imagegen-repair.js +47 -12
  88. package/dist/core/doctor/legacy-global-hook-cleanup.js +179 -0
  89. package/dist/core/feature-registry.js +25 -31
  90. package/dist/core/fsx.js +54 -6
  91. package/dist/core/harness-conflicts.js +1 -1
  92. package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +5 -4
  93. package/dist/core/hooks-runtime/hook-invocation-dedupe.js +147 -0
  94. package/dist/core/hooks-runtime/hook-io.js +6 -0
  95. package/dist/core/hooks-runtime.js +17 -2
  96. package/dist/core/image/image-artifact-path-contract.js +8 -6
  97. package/dist/core/image/image-artifact-registry.js +5 -1
  98. package/dist/core/image-ux-review/imagegen-adapter.js +5 -2
  99. package/dist/core/imagegen/imagegen-capability.js +10 -13
  100. package/dist/core/imagegen/require-imagegen.js +37 -11
  101. package/dist/core/managed-assets/managed-assets-manifest.js +1 -5
  102. package/dist/core/naruto/naruto-work-graph.js +70 -4
  103. package/dist/core/naruto/naruto-write-e2e.js +3 -4
  104. package/dist/core/ops/reporting.js +3 -0
  105. package/dist/core/pipeline-internals/runtime-core.js +12 -7
  106. package/dist/core/pipeline-internals/runtime-gates.js +17 -1
  107. package/dist/core/ppt/style-tokens.js +1 -1
  108. package/dist/core/ppt-review/index.js +1 -1
  109. package/dist/core/ppt-review/slide-exporter.js +23 -17
  110. package/dist/core/ppt-review/slide-imagegen-review.js +1 -1
  111. package/dist/core/ppt-review/slide-issue-extraction.js +4 -2
  112. package/dist/core/product-design-plugin.js +2 -2
  113. package/dist/core/proof/route-finalizer.js +1 -1
  114. package/dist/core/proof-field.js +3 -3
  115. package/dist/core/provider/model-router.js +68 -3
  116. package/dist/core/release/gate-manifest.js +18 -12
  117. package/dist/core/release/gate-pack-manifest.js +1 -1
  118. package/dist/core/release/package-size-budget.js +2 -0
  119. package/dist/core/release/release-gate-affected-selector.js +1 -1
  120. package/dist/core/release/release-gate-dag.js +43 -3
  121. package/dist/core/release/release-gate-hermetic-env.js +28 -17
  122. package/dist/core/release/release-real-contract.js +416 -0
  123. package/dist/core/retention/retention-budget.js +25 -6
  124. package/dist/core/retention.js +980 -101
  125. package/dist/core/routes/constants.js +1 -1
  126. package/dist/core/routes/evidence.js +4 -4
  127. package/dist/core/routes/model-mode-router.js +3 -0
  128. package/dist/core/routes/ppt-policy.js +1 -1
  129. package/dist/core/routes.js +11 -12
  130. package/dist/core/secret-redaction.js +4 -0
  131. package/dist/core/triwiki/code-pack.js +8 -2
  132. package/dist/core/triwiki/triwiki-cache-key.js +108 -29
  133. package/dist/core/triwiki-attention.js +13 -6
  134. package/dist/core/triwiki-provenance.js +274 -0
  135. package/dist/core/triwiki-runtime.js +21 -7
  136. package/dist/core/triwiki-wrongness/wrongness-ledger.js +178 -59
  137. package/dist/core/triwiki-wrongness/wrongness-retrieval.js +11 -2
  138. package/dist/core/triwiki-wrongness/wrongness-trust-policy.js +2 -0
  139. package/dist/core/update/update-migration-state.js +1 -1
  140. package/dist/core/update/update-notice.js +23 -0
  141. package/dist/core/update-check.js +69 -25
  142. package/dist/core/version.js +1 -1
  143. package/dist/core/wiki-coordinate.js +128 -12
  144. package/dist/core/work-order-ledger.js +168 -9
  145. package/dist/core/zellij/zellij-command.js +12 -1
  146. package/dist/core/zellij/zellij-dashboard-pane.js +3 -3
  147. package/dist/core/zellij/zellij-launcher.js +15 -14
  148. package/dist/core/zellij/zellij-pane-proof.js +32 -6
  149. package/dist/core/zellij/zellij-worker-pane-manager.js +5 -3
  150. package/dist/scripts/agent-fast-mode-default-check.js +48 -29
  151. package/dist/scripts/agent-role-config-repair-check.js +25 -4
  152. package/dist/scripts/agent-wiki-context-proof-check.js +16 -2
  153. package/dist/scripts/all-feature-deep-completion-check.js +14 -4
  154. package/dist/scripts/build-dist.js +17 -5
  155. package/dist/scripts/canonical-test-runner.js +188 -0
  156. package/dist/scripts/check-command-module-budget.js +38 -16
  157. package/dist/scripts/check-legacy-free.js +1 -1
  158. package/dist/scripts/codex-0139-interrupt-agent-check.js +5 -1
  159. package/dist/scripts/{codex-0142-app-server-v2-check.js → codex-0144-app-server-v2-check.js} +11 -10
  160. package/dist/scripts/{codex-0142-binary-identity-check.js → codex-0144-binary-identity-check.js} +4 -4
  161. package/dist/scripts/codex-0144-capability-check.js +21 -0
  162. package/dist/scripts/{codex-0139-real-probes-check.js → codex-0144-core-real-probes-check.js} +19 -5
  163. package/dist/scripts/{codex-0142-doctor-wiring-check.js → codex-0144-doctor-wiring-check.js} +6 -6
  164. package/dist/scripts/{codex-0142-manifest-check.js → codex-0144-manifest-check.js} +11 -3
  165. package/dist/scripts/{codex-0142-policy-check.js → codex-0144-policy-check.js} +2 -2
  166. package/dist/scripts/{codex-0142-thread-store-check.js → codex-0144-thread-store-check.js} +3 -3
  167. package/dist/scripts/codex-app-provider-model-ui-check.js +57 -8
  168. package/dist/scripts/codex-app-ui-preservation-check.js +35 -4
  169. package/dist/scripts/codex-control-side-effect-scope-check.js +2 -2
  170. package/dist/scripts/codex-effort-auto-discovery-check.js +1 -1
  171. package/dist/scripts/codex-lb-fast-mode-truth-check.js +1 -0
  172. package/dist/scripts/{codex-lb-gpt55-fast-profile-check.js → codex-lb-gpt56-fast-profile-check.js} +56 -5
  173. package/dist/scripts/codex-model-metadata-check.js +1 -1
  174. package/dist/scripts/codex-sdk-sandbox-policy-check.js +5 -1
  175. package/dist/scripts/codex-sdk-version-compat-check.js +2 -1
  176. package/dist/scripts/dfix-fixture-check.js +1 -1
  177. package/dist/scripts/docs-truthfulness-check.js +1 -1
  178. package/dist/scripts/doctor-codex-startup-repair-check.js +35 -10
  179. package/dist/scripts/doctor-context7-repair-check.js +2 -1
  180. package/dist/scripts/doctor-fix-proves-codex-read-check.js +1 -1
  181. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +34 -7
  182. package/dist/scripts/doctor-imagegen-repair-check.js +14 -4
  183. package/dist/scripts/doctor-startup-config-repair-blackbox.js +1 -1
  184. package/dist/scripts/doctor-startup-config-repair-check.js +1 -1
  185. package/dist/scripts/gate-policy-audit-check.js +2 -2
  186. package/dist/scripts/install-update-preserves-config-check.js +1 -1
  187. package/dist/scripts/legacy-gate-inventory-check.js +7 -5
  188. package/dist/scripts/legacy-strong-inventory-check.js +7 -5
  189. package/dist/scripts/legacy-upgrade-matrix-check.js +5 -5
  190. package/dist/scripts/lib/native-cli-session-swarm-check-lib.js +175 -14
  191. package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +166 -6
  192. package/dist/scripts/mutation-callsite-coverage-check.js +0 -11
  193. package/dist/scripts/naruto-shadow-clone-swarm-check.js +88 -50
  194. package/dist/scripts/npm-publish-performance-check.js +2 -1
  195. package/dist/scripts/package-published-contract-check.js +9 -0
  196. package/dist/scripts/packlist-performance-check.js +5 -2
  197. package/dist/scripts/postinstall-safe-side-effects-check.js +8 -3
  198. package/dist/scripts/ppt-no-mock-as-real-check.js +3 -1
  199. package/dist/scripts/product-design-plugin-routing-check.js +1 -1
  200. package/dist/scripts/release-check-stamp.js +182 -2
  201. package/dist/scripts/release-dag-full-coverage-check.js +7 -7
  202. package/dist/scripts/release-dynamic-presets-check.js +8 -0
  203. package/dist/scripts/release-gate-dag-runner-check.js +3 -2
  204. package/dist/scripts/release-gate-dag-runner.js +24 -11
  205. package/dist/scripts/release-gate-existence-audit.js +8 -9
  206. package/dist/scripts/release-gate-script-parity-check.js +1 -1
  207. package/dist/scripts/release-real-check.js +368 -157
  208. package/dist/scripts/release-runtime-truth-matrix-check.js +22 -0
  209. package/dist/scripts/route-proof-artifact-structure-check.js +1 -0
  210. package/dist/scripts/scheduler-batch-dispatch-check.js +1 -1
  211. package/dist/scripts/search-visibility-gate-lib.js +1 -1
  212. package/dist/scripts/seo-geo-route-identity-check.js +30 -4
  213. package/dist/scripts/sizecheck.js +7 -2
  214. package/dist/scripts/sks-1-11-gate-lib.js +53 -6
  215. package/dist/scripts/sks-menubar-install-check.js +7 -0
  216. package/dist/scripts/sks-uninstall-regression-check.js +1 -1
  217. package/dist/scripts/sksd-daemon-check.js +16 -6
  218. package/dist/scripts/update-default-command-check.js +4 -2
  219. package/dist/scripts/write-build-manifest.js +2 -1
  220. package/dist/scripts/zellij-layout-valid-check.js +31 -6
  221. package/dist/scripts/zellij-pane-proof-check.js +33 -2
  222. package/dist/scripts/zellij-real-session-cleanup-check.js +122 -2
  223. package/dist/scripts/zellij-real-session-launch-check.js +76 -5
  224. package/dist/scripts/zellij-slot-pane-renderer-check.js +4 -4
  225. package/package.json +27 -30
  226. package/schemas/codex/{app-server-0.142 → app-server-0.144}/codex_app_server_protocol.v2.schemas.json +1146 -781
  227. package/schemas/codex/codex-0139-real-probe-result.schema.json +39 -5
  228. package/schemas/codex/ppt-slide-issue-ledger.schema.json +2 -1
  229. package/dist/core/codex-control/codex-0139-multi-agent-real-probe.js +0 -107
  230. package/dist/scripts/agent-native-release-gate.js +0 -274
  231. package/dist/scripts/codex-0142-capability-check.js +0 -21
  232. package/dist/scripts/command-performance-scorecard-check.js +0 -204
  233. package/dist/scripts/config-managed-merge-callsite-coverage-check.js +0 -212
  234. package/dist/scripts/dollar-performance-scorecard-check.js +0 -257
  235. package/dist/scripts/gate-timing-check.js +0 -16
  236. package/dist/scripts/ops-maturity-scorecard-check.js +0 -12
  237. package/dist/scripts/performance-baseline-check.js +0 -12
  238. package/dist/scripts/performance-improvement-report-check.js +0 -58
  239. package/dist/scripts/release-parallel-check.js +0 -389
  240. package/dist/scripts/release-runner-efficiency-check.js +0 -15
  241. package/dist/scripts/retention-long-run-smoke-check.js +0 -299
  242. package/docs/assets/sneakoscope-architecture-pipeline.jpg +0 -0
@@ -29,31 +29,30 @@ assertGate(fullRoster.max_agents === 100, 'clone roster max_agents must be 100',
29
29
  // 4) Over-cap is clamped, not crashed.
30
30
  const overCap = roster.buildNarutoCloneRoster({ clones: 500, maxAgentCount: schema.MAX_NARUTO_AGENT_COUNT });
31
31
  assertGate(overCap.agent_count === 100, 'clones above the ceiling clamp to 100', { agent_count: overCap.agent_count });
32
- // 4b) Dynamic per-clone effort policy (like team mode), capped + always fast.
33
- // A neutral/no-tool prompt yields a low/medium MIX: read-only personas -> low, writers -> medium.
32
+ // 4b) Naruto-only GPT-5.6 family policy. The old low/medium cap is gone.
34
33
  const effortRoster = roster.buildNarutoCloneRoster({ clones: 24, prompt: 'review and summarize the current findings', maxAgentCount: schema.MAX_NARUTO_AGENT_COUNT });
35
34
  const efforts = new Set(effortRoster.roster.map((row) => row.reasoning_effort));
36
35
  const modelTiers = new Set(effortRoster.roster.map((row) => row.model_tier));
37
36
  const modelEfforts = new Set(effortRoster.roster.map((row) => row.model_reasoning_effort));
38
37
  const tiers = new Set(effortRoster.roster.map((row) => row.service_tier));
39
38
  const fastFlags = new Set(effortRoster.roster.map((row) => row.fast_mode));
40
- assertGate([...efforts].every((e) => e === 'low' || e === 'medium'), 'naruto clone efforts must be only low/medium (never high/xhigh)', { efforts: [...efforts] });
41
- assertGate(efforts.has('low') && efforts.has('medium'), 'naruto effort must be dynamic: a no-tool prompt must yield both low and medium clones', { efforts: [...efforts] });
42
- assertGate([...modelTiers].every((tier) => tier === 'codex-selected-low' || tier === 'codex-selected-medium'), 'Naruto must inherit the Codex-selected model and vary only reasoning effort', { modelTiers: [...modelTiers] });
43
- assertGate(modelTiers.has('codex-selected-low') && modelTiers.has('codex-selected-medium'), 'Naruto effort allocation must dynamically mix low and medium without changing model IDs', { modelTiers: [...modelTiers] });
44
- assertGate([...modelEfforts].every((effort) => effort === 'low' || effort === 'medium'), 'ordinary Naruto clone model reasoning must stay low/medium', { modelEfforts: [...modelEfforts] });
39
+ assertGate([...efforts].every((effort) => effort === 'xhigh' || effort === 'max'), 'Naruto clone efforts must use only xhigh/max', { efforts: [...efforts] });
40
+ assertGate([...effortRoster.roster].every((row) => ['gpt-5.6-luna', 'gpt-5.6-terra', 'gpt-5.6-sol'].includes(row.model)), 'Naruto workers must use only the GPT-5.6 trio', { models: [...new Set(effortRoster.roster.map((row) => row.model))] });
41
+ assertGate([...modelTiers].every((tier) => /gpt-5\.6-(?:luna|terra|sol)-(?:xhigh|max)/.test(tier)), 'Naruto model tiers must record exact GPT-5.6 model and effort', { modelTiers: [...modelTiers] });
42
+ assertGate([...modelEfforts].every((effort) => effort === 'xhigh' || effort === 'max'), 'Naruto model reasoning must use xhigh/max', { modelEfforts: [...modelEfforts] });
45
43
  assertGate([...tiers].length === 1 && tiers.has('fast'), 'every naruto clone must be fast service tier', { tiers: [...tiers] });
46
44
  assertGate([...fastFlags].length === 1 && fastFlags.has(true), 'every naruto clone must have fast_mode=true', { fastFlags: [...fastFlags] });
47
- // 4c) Unit rule: no tool use -> low; any tool use -> medium; always fast.
48
- const simple = effortPolicy.decideNarutoCloneEffort({ readonly: true, prompt: 'simple docs overview' });
49
- const toolWrite = effortPolicy.decideNarutoCloneEffort({ readonly: false, prompt: 'add a feature' });
50
- const toolReadCmd = effortPolicy.decideNarutoCloneEffort({ readonly: true, prompt: 'run the build and apply the migration' });
51
- const simpleWrite = effortPolicy.decideNarutoCloneEffort({ readonly: false, prompt: 'simple one-line typo fix' });
52
- assertGate(simple.reasoning_effort === 'low' && simple.service_tier === 'fast', 'no-tool read-only work must be low + fast', { simple });
53
- assertGate(simple.model === '' && simple.model_reasoning_effort === 'low', 'no-tool read-only work must inherit the Codex model at low effort', { simple });
54
- assertGate(toolWrite.reasoning_effort === 'medium' && toolWrite.service_tier === 'fast' && toolWrite.model === '' && toolWrite.model_reasoning_effort === 'medium', 'writing clone must inherit the Codex model at medium effort', { toolWrite });
55
- assertGate(simpleWrite.model === '' && simpleWrite.model_reasoning_effort === 'low', 'simple write work must inherit the Codex model at low effort', { simpleWrite });
56
- assertGate(toolReadCmd.reasoning_effort === 'medium' && toolReadCmd.service_tier === 'fast' && toolReadCmd.model_reasoning_effort === 'high', 'risky read-only command/migration work must escalate model reasoning to high', { toolReadCmd });
45
+ // 4c) Deterministic work-kind matrix.
46
+ const coding = effortPolicy.decideNarutoCloneEffort({ persona: { role: 'implementer', naruto_role: 'implementer' }, prompt: 'implement a normal coding feature' });
47
+ const criticalCoding = effortPolicy.decideNarutoCloneEffort({ persona: { role: 'implementer', naruto_role: 'implementer' }, prompt: 'implement a critical security migration' });
48
+ const refactor = effortPolicy.decideNarutoCloneEffort({ persona: { role: 'integrator', naruto_role: 'integrator' }, prompt: 'refactor the architecture and integration plan' });
49
+ const e2e = effortPolicy.decideNarutoCloneEffort({ persona: { role: 'browser e2e verifier', naruto_role: 'verifier' }, prompt: 'run browser e2e tests' });
50
+ const forensicGui = effortPolicy.decideNarutoCloneEffort({ persona: { role: 'Computer Use GUI verifier', naruto_role: 'verifier' }, prompt: 'forensic cross-app failure verification' });
51
+ assertGate(coding.model === 'gpt-5.6-terra' && coding.model_reasoning_effort === 'xhigh', 'ordinary coding must use Terra xhigh', { coding });
52
+ assertGate(criticalCoding.model === 'gpt-5.6-terra' && criticalCoding.model_reasoning_effort === 'max', 'critical coding must use Terra max', { criticalCoding });
53
+ assertGate(refactor.model === 'gpt-5.6-sol' && refactor.model_reasoning_effort === 'max', 'refactor/architecture/integration must use Sol max', { refactor });
54
+ assertGate(e2e.model === 'gpt-5.6-luna' && e2e.model_reasoning_effort === 'xhigh', 'browser E2E must use Luna xhigh', { e2e });
55
+ assertGate(forensicGui.model === 'gpt-5.6-luna' && forensicGui.model_reasoning_effort === 'max', 'forensic Computer Use GUI verification must use Luna max', { forensicGui });
57
56
  // 5) System-safe concurrency: never spawn the whole count at once; throttle to host capacity.
58
57
  const fakeSafe = roster.systemSafeNarutoConcurrency({ backend: 'fake' });
59
58
  const heavySafe = roster.systemSafeNarutoConcurrency({ backend: 'codex-sdk' });
@@ -91,47 +90,60 @@ const run = spawnSync(process.execPath, [
91
90
  '--json',
92
91
  '--no-open-zellij'
93
92
  ], { cwd: root, env: childEnv, encoding: 'utf8', timeout: 780000, maxBuffer: 8 * 1024 * 1024 });
94
- assertGate(run.status === 0, 'sks naruto run must exit 0', { status: run.status, stderr: tail(run.stderr) });
95
93
  const parsed = parseJson(run.stdout);
96
- assertGate(parsed !== null, 'sks naruto run must emit JSON', { stdout: tail(run.stdout) });
97
- assertGate(parsed.ok === true, 'naruto run must be ok', { ok: parsed.ok });
98
- assertGate(parsed.mode === 'NARUTO' && parsed.jutsu === 'kage_bunshin_no_jutsu', 'naruto run must report NARUTO mode', { mode: parsed.mode, jutsu: parsed.jutsu });
99
- assertGate(parsed.clones === proofClones, 'clone fan-out must use the requested queued count', { clones: parsed.clones });
100
- assertGate(parsed.max_clones === 100, 'naruto run must advertise the 100 ceiling', { max_clones: parsed.max_clones });
101
- assertGate(parsed.proof === 'passed', 'naruto run proof must pass', { proof: parsed.proof });
102
- // Throttle invariant: active concurrency never exceeds the requested count nor the host cap.
103
- 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 });
104
- 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 });
105
- assertGate(parsed.target_active_slots <= proofConcurrency && parsed.target_active_slots <= 4, 'release proof must keep Naruto live slots desktop-safe while queued fan-out remains larger', { target_active_slots: parsed.target_active_slots, proofConcurrency });
106
- // Task 9.1: fan-out (clones) and live concurrency (target_active_slots) are reported
107
- // distinctly, and concurrency_capped truthfully reflects "N clones, running M at a time".
108
- assertGate(typeof parsed.concurrency_capped === 'boolean', 'naruto run must report concurrency_capped', { concurrency_capped: parsed.concurrency_capped });
109
- assertGate(parsed.concurrency_capped === (parsed.clones > parsed.target_active_slots), 'concurrency_capped must reflect clones > live slots', { clones: parsed.clones, target_active_slots: parsed.target_active_slots, concurrency_capped: parsed.concurrency_capped });
110
- assertGate(parsed.system && Number(parsed.system.safe_concurrency) >= 1, 'naruto run must report system safe_concurrency (host-derived cap)', { system: parsed.system });
111
- assertGate(parsed.work_graph?.write_allowed_count > 0 && parsed.work_graph?.mixed_work_kinds?.length > 1, 'naruto run must report a mixed work graph with write-capable items', { work_graph: parsed.work_graph });
112
- assertGate(Number(parsed.work_graph?.parallel_write_wave_count || 0) > 0, 'naruto run must expose at least one parallel write-capable wave with non-overlapping leases', { work_graph: parsed.work_graph });
113
- assertGate(parsed.role_distribution?.verifier_only === false, 'naruto run proof/status must distinguish active worker roles beyond verifier-only', { role_distribution: parsed.role_distribution });
114
- assertGate(Number(parsed.role_distribution?.implementation_like_ratio || 0) >= 0.4, 'naruto run must include implementation-like role distribution', { role_distribution: parsed.role_distribution });
115
- const commandGraphPath = path.join(root, '.sneakoscope', 'missions', parsed.mission_id, 'agents', 'naruto-work-graph.json');
116
- const commandGraph = JSON.parse(fs.readFileSync(commandGraphPath, 'utf8'));
117
- const writePaths = commandGraph.work_items.filter((row) => row.write_allowed).flatMap((row) => row.write_paths);
118
- assertGate(new Set(writePaths).size > 1, 'naruto command default patch-envelope leases must be per work item, not one shared write path', { sample: writePaths.slice(0, 8), unique: new Set(writePaths).size });
119
- assertGate(commandGraph.active_waves.some((wave) => wave.write_paths.length > 1), 'naruto command graph must contain a parallel write wave when route-local patch envelopes do not overlap', { waves: commandGraph.active_waves.slice(0, 3) });
120
- const state = parsed.run?.scheduler?.state || parsed.run?.scheduler || {};
121
- assertGate(Number(state.completed_count) === Number(parsed.work_graph?.total_work_items || 0) && Number(state.completed_count) >= proofClones, 'all clone work items must complete despite throttling', { completed_count: state.completed_count, total_work_items: parsed.work_graph?.total_work_items, proofClones });
122
- assertGate(parsed.target_active_slots <= 4, 'explicit --concurrency cannot bypass the desktop-safe cap', { target_active_slots: parsed.target_active_slots });
94
+ assertGate(parsed !== null, 'sks naruto run must emit JSON', { stdout: tail(run.stdout), stderr: tail(run.stderr) });
95
+ let state = {};
96
+ withMissionRouteClose(parsed, childEnv, () => {
97
+ assertGate(run.status === 0, 'sks naruto run must exit 0', { status: run.status, stderr: tail(run.stderr) });
98
+ assertGate(parsed.ok === true, 'naruto run must be ok', { ok: parsed.ok });
99
+ assertGate(parsed.mode === 'NARUTO' && parsed.jutsu === 'kage_bunshin_no_jutsu', 'naruto run must report NARUTO mode', { mode: parsed.mode, jutsu: parsed.jutsu });
100
+ assertGate(parsed.clones === proofClones, 'clone fan-out must use the requested queued count', { clones: parsed.clones });
101
+ assertGate(parsed.max_clones === 100, 'naruto run must advertise the 100 ceiling', { max_clones: parsed.max_clones });
102
+ assertGate(parsed.proof === 'passed', 'naruto run proof must pass', { proof: parsed.proof });
103
+ // Throttle invariant: active concurrency never exceeds the requested count nor the host cap.
104
+ 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 });
105
+ 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 });
106
+ assertGate(parsed.target_active_slots <= proofConcurrency && parsed.target_active_slots <= 4, 'release proof must keep Naruto live slots desktop-safe while queued fan-out remains larger', { target_active_slots: parsed.target_active_slots, proofConcurrency });
107
+ // Task 9.1: fan-out (clones) and live concurrency (target_active_slots) are reported
108
+ // distinctly, and concurrency_capped truthfully reflects "N clones, running M at a time".
109
+ assertGate(typeof parsed.concurrency_capped === 'boolean', 'naruto run must report concurrency_capped', { concurrency_capped: parsed.concurrency_capped });
110
+ assertGate(parsed.concurrency_capped === (parsed.clones > parsed.target_active_slots), 'concurrency_capped must reflect clones > live slots', { clones: parsed.clones, target_active_slots: parsed.target_active_slots, concurrency_capped: parsed.concurrency_capped });
111
+ assertGate(parsed.system && Number(parsed.system.safe_concurrency) >= 1, 'naruto run must report system safe_concurrency (host-derived cap)', { system: parsed.system });
112
+ assertGate(parsed.work_graph?.write_allowed_count > 0 && parsed.work_graph?.mixed_work_kinds?.length > 1, 'naruto run must report a mixed work graph with write-capable items', { work_graph: parsed.work_graph });
113
+ assertGate(Number(parsed.work_graph?.parallel_write_wave_count || 0) > 0, 'naruto run must expose at least one parallel write-capable wave with non-overlapping leases', { work_graph: parsed.work_graph });
114
+ assertGate(parsed.role_distribution?.verifier_only === false, 'naruto run proof/status must distinguish active worker roles beyond verifier-only', { role_distribution: parsed.role_distribution });
115
+ assertGate(Number(parsed.role_distribution?.implementation_like_ratio || 0) >= 0.4, 'naruto run must include implementation-like role distribution', { role_distribution: parsed.role_distribution });
116
+ assertGate(parsed.local_worker?.auto_select_eligible === false, 'normal Naruto must never auto-select a local/Ollama backend', { local_worker: parsed.local_worker });
117
+ const commandGraphPath = path.join(root, '.sneakoscope', 'missions', parsed.mission_id, 'agents', 'naruto-work-graph.json');
118
+ const commandGraph = JSON.parse(fs.readFileSync(commandGraphPath, 'utf8'));
119
+ const writePaths = commandGraph.work_items.filter((row) => row.write_allowed).flatMap((row) => row.write_paths);
120
+ assertGate(new Set(writePaths).size > 1, 'naruto command default patch-envelope leases must be per work item, not one shared write path', { sample: writePaths.slice(0, 8), unique: new Set(writePaths).size });
121
+ assertGate(commandGraph.active_waves.some((wave) => wave.write_paths.length > 1), 'naruto command graph must contain a parallel write wave when route-local patch envelopes do not overlap', { waves: commandGraph.active_waves.slice(0, 3) });
122
+ state = parsed.run?.scheduler?.state || parsed.run?.scheduler || {};
123
+ assertGate(Number(state.completed_count) === Number(parsed.work_graph?.total_work_items || 0) && Number(state.completed_count) >= proofClones, 'all clone work items must complete despite throttling', { completed_count: state.completed_count, total_work_items: parsed.work_graph?.total_work_items, proofClones });
124
+ assertGate(parsed.target_active_slots <= 4, 'explicit --concurrency cannot bypass the desktop-safe cap', { target_active_slots: parsed.target_active_slots });
125
+ });
123
126
  // 7) A small request is never inflated; live pressure may still reduce it.
124
127
  const small = spawnSync(process.execPath, [cli, 'naruto', 'run', 'tiny', '--clones', '2', '--backend', 'fake', '--work-items', '2', '--json', '--no-open-zellij'], { cwd: root, env: childEnv, encoding: 'utf8', timeout: 600000, maxBuffer: 4 * 1024 * 1024 });
125
128
  const smallParsed = parseJson(small.stdout);
126
- assertGate(small.status === 0 && smallParsed?.target_active_slots >= 1 && smallParsed?.target_active_slots <= 2, 'a 2-clone run must stay within [1, 2] active workers', { status: small.status, target_active_slots: smallParsed?.target_active_slots });
129
+ withMissionRouteClose(smallParsed, childEnv, () => {
130
+ assertGate(small.status === 0 && smallParsed?.target_active_slots >= 1 && smallParsed?.target_active_slots <= 2, 'a 2-clone run must stay within [1, 2] active workers', {
131
+ status: small.status,
132
+ target_active_slots: smallParsed?.target_active_slots,
133
+ stdout: tail(small.stdout),
134
+ stderr: tail(small.stderr)
135
+ });
136
+ });
127
137
  // 8) Naruto clones always run fast. Per-route --no-fast / standard-tier requests
128
138
  // are intentionally not honored for shadow clones.
129
139
  const standardOptOut = spawnSync(process.execPath, [cli, 'naruto', 'run', 'fast opt-out ignored', '--clones', '2', '--backend', 'fake', '--work-items', '2', '--no-fast', '--service-tier', 'standard', '--json', '--no-open-zellij'], { cwd: root, env: childEnv, encoding: 'utf8', timeout: 600000, maxBuffer: 4 * 1024 * 1024 });
130
140
  const standardOptOutParsed = parseJson(standardOptOut.stdout);
131
- assertGate(standardOptOut.status === 0 && standardOptOutParsed?.fast_mode_policy?.fast_mode === true && standardOptOutParsed?.fast_mode_policy?.service_tier === 'fast', 'naruto --no-fast / --service-tier standard must still run clones in fast mode', {
132
- status: standardOptOut.status,
133
- fast_mode_policy: standardOptOutParsed?.fast_mode_policy,
134
- stderr: tail(standardOptOut.stderr)
141
+ withMissionRouteClose(standardOptOutParsed, childEnv, () => {
142
+ assertGate(standardOptOut.status === 0 && standardOptOutParsed?.fast_mode_policy?.fast_mode === true && standardOptOutParsed?.fast_mode_policy?.service_tier === 'fast', 'naruto --no-fast / --service-tier standard must still run clones in fast mode', {
143
+ status: standardOptOut.status,
144
+ fast_mode_policy: standardOptOutParsed?.fast_mode_policy,
145
+ stderr: tail(standardOptOut.stderr)
146
+ });
135
147
  });
136
148
  emitGate('naruto:shadow-clone-swarm', {
137
149
  max_naruto_agent_count: schema.MAX_NARUTO_AGENT_COUNT,
@@ -162,4 +174,30 @@ function tail(value, limit = 2000) {
162
174
  const text = String(value || '');
163
175
  return text.length <= limit ? text : text.slice(-limit);
164
176
  }
177
+ function closeMission(missionId, env) {
178
+ assertGate(Boolean(missionId), 'naruto proof mission id missing before route close', { missionId });
179
+ const closed = spawnSync(process.execPath, [cli, 'route', 'close', '--mission', String(missionId), '--json'], {
180
+ cwd: root,
181
+ env,
182
+ encoding: 'utf8',
183
+ timeout: 30000,
184
+ maxBuffer: 1024 * 1024
185
+ });
186
+ const parsedClose = parseJson(closed.stdout);
187
+ assertGate(closed.status === 0 && parsedClose?.ok === true, 'naruto proof mission route close must succeed', {
188
+ missionId,
189
+ status: closed.status,
190
+ stdout: tail(closed.stdout),
191
+ stderr: tail(closed.stderr)
192
+ });
193
+ }
194
+ function withMissionRouteClose(parsedResult, env, verify) {
195
+ try {
196
+ return verify();
197
+ }
198
+ finally {
199
+ if (parsedResult?.mission_id)
200
+ closeMission(parsedResult.mission_id, env);
201
+ }
202
+ }
165
203
  //# sourceMappingURL=naruto-shadow-clone-swarm-check.js.map
@@ -3,9 +3,10 @@
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { spawnSync } from 'node:child_process';
6
+ import { DEFAULT_MAX_PACK_BYTES } from '../core/release/package-size-budget.js';
6
7
  import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
7
8
  const MAX_FILES = Number(process.env.SKS_MAX_PACK_FILES || 2100);
8
- const MAX_PACKED = Number(process.env.SKS_MAX_PACK_BYTES || 2410 * 1024);
9
+ const MAX_PACKED = Number(process.env.SKS_MAX_PACK_BYTES || DEFAULT_MAX_PACK_BYTES);
9
10
  const BUDGET_MS = Number(process.env.SKS_PACK_BUDGET_MS || 30000);
10
11
  function runNpmPack() {
11
12
  const npmCli = process.env.npm_execpath; // set when invoked via `npm run`
@@ -7,6 +7,14 @@ import { assertGate, emitGate, readJson, root } from './sks-1-18-gate-lib.js';
7
7
  const pkg = readJson('package.json');
8
8
  const scripts = pkg.scripts || {};
9
9
  const cacheRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-package-published-contract-'));
10
+ let cacheCleaned = false;
11
+ const cleanupCacheRoot = () => {
12
+ if (cacheCleaned)
13
+ return;
14
+ cacheCleaned = true;
15
+ fs.rmSync(cacheRoot, { recursive: true, force: true });
16
+ };
17
+ process.once('exit', cleanupCacheRoot);
10
18
  const dry = spawnSync('npm', ['pack', '--dry-run', '--json', '--ignore-scripts'], {
11
19
  cwd: root,
12
20
  encoding: 'utf8',
@@ -34,6 +42,7 @@ assertGate(missingTargets.length === 0, 'published package scripts must not refe
34
42
  missingTargets: missingTargets.slice(0, 50),
35
43
  missing_count: missingTargets.length
36
44
  });
45
+ cleanupCacheRoot();
37
46
  emitGate('package:published-contract', {
38
47
  files: files.size,
39
48
  script_count: Object.keys(scripts).length,
@@ -4,6 +4,7 @@ import fs from 'node:fs';
4
4
  import os from 'node:os';
5
5
  import path from 'node:path';
6
6
  import { spawnSync } from 'node:child_process';
7
+ import { DEFAULT_MAX_PACK_BYTES } from '../core/release/package-size-budget.js';
7
8
  import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
8
9
  const MAX_FILES = Number(process.env.SKS_MAX_PACK_FILES || 2100);
9
10
  const MAX_UNPACKED = Number(process.env.SKS_MAX_UNPACKED_BYTES || 10 * 1024 * 1024);
@@ -22,8 +23,10 @@ const MAX_UNPACKED = Number(process.env.SKS_MAX_UNPACKED_BYTES || 10 * 1024 * 10
22
23
  // checks; keep those scripts publishable because package contract validation
23
24
  // rejects scripts that point at files absent from the tarball. 5.12.0 adds ops
24
25
  // maturity diagnostics, migration/recovery smokes, and their package-referenced
25
- // gates, pushing the packed tarball to ~2400 KiB.
26
- const MAX_PACKED = Number(process.env.SKS_MAX_PACK_BYTES || 2410 * 1024);
26
+ // gates, pushing the packed tarball to ~2400 KiB. 6.0.3 adds the menu restart
27
+ // lifecycle and Naruto GPT-5.6 routing enforcement, bringing the measured
28
+ // packed size to ~2411 KiB; keep the next 1 KiB boundary as the narrow cap.
29
+ const MAX_PACKED = Number(process.env.SKS_MAX_PACK_BYTES || DEFAULT_MAX_PACK_BYTES);
27
30
  const SURFACE_MAX_PACKED = Number(process.env.SKS_PACKAGE_SURFACE_MAX_PACK_BYTES || 25_000_000);
28
31
  const SURFACE_MAX_FILES = Number(process.env.SKS_PACKAGE_SURFACE_MAX_FILES || 2500);
29
32
  function runNpmPack() {
@@ -7,6 +7,8 @@ import { root, assertGate, emitGate, readText } from './sks-1-18-gate-lib.js';
7
7
  // side-effects by default. This is STATIC source analysis only — we never execute
8
8
  // `postinstall`, because doing so would mutate the global Codex App / shell environment.
9
9
  const helpers = readText('src/cli/install-helpers.ts');
10
+ const desktopConfigPolicy = readText('src/core/codex-runtime/codex-desktop-config-policy.ts');
11
+ const codexConfigGuard = readText('src/core/codex/codex-config-guard.ts');
10
12
  // Heavy CLI tool installs (brew / npm globals) are opt-in only.
11
13
  assertGate(helpers.includes('SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS'), 'postinstall cli tool install must be gated behind SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS');
12
14
  // Killing a third-party app's processes is opt-in only.
@@ -15,9 +17,12 @@ assertGate(helpers.includes('runPostinstallProjectRetentionCleanup') && helpers.
15
17
  // Config writes are gated (unparseable preserved / unsafe rewrite skipped) and backed up.
16
18
  assertGate(helpers.includes('unparseable_config_preserved'), 'postinstall must preserve unparseable config');
17
19
  assertGate(helpers.includes('skipped_unsafe_rewrite'), 'postinstall must skip unsafe config rewrites');
18
- assertGate(helpers.includes('backupCodexConfig'), 'postinstall config writes must back up the existing config');
19
- // User model / service_tier are set-if-absent, never overwritten.
20
- assertGate(helpers.includes('upsertTopLevelTomlStringIfAbsent'), 'postinstall must set user model/service_tier only when absent');
20
+ assertGate(desktopConfigPolicy.includes('backupCodexConfig'), 'postinstall config writes must back up the existing config');
21
+ // Host-owned feature choices are set-if-absent, and model/reasoning keys are
22
+ // changed only when bounded SKS provenance proves SKS created them.
23
+ assertGate(desktopConfigPolicy.includes('upsertTomlTableKeyIfAbsent')
24
+ && desktopConfigPolicy.includes('removeLegacyTopLevelCodexModeLocks')
25
+ && codexConfigGuard.includes('hasSksModeLockProvenance'), 'postinstall must preserve host-owned feature/model choices');
21
26
  // The postinstall() body must be wrapped in try/catch/finally so it never fails `npm install`.
22
27
  const postinstallStart = helpers.indexOf('export async function postinstall');
23
28
  assertGate(postinstallStart !== -1, 'postinstall function not found in install-helpers.ts');
@@ -3,6 +3,8 @@
3
3
  import { assertGate, emitGate, readMissionJson, runPptReview } from './sks-1-11-gate-lib.js';
4
4
  const result = runPptReview('review');
5
5
  const proof = readMissionJson(result.mission_id, 'completion-proof.json');
6
- assertGate(proof.status !== 'verified' && result.proof_evidence.status === 'verified_partial', 'ppt mock fixture was allowed to claim fully real evidence', { proof_status: proof.status, evidence_status: result.proof_evidence.status });
6
+ assertGate(proof.status === 'mock_only'
7
+ && result.proof_evidence.status === 'blocked'
8
+ && (result.proof_evidence.blockers || []).some((blocker) => String(blocker).includes('mock_fixture')), 'ppt mock fixture was allowed to claim fully real evidence', { proof_status: proof.status, evidence_status: result.proof_evidence.status, blockers: result.proof_evidence.blockers || [] });
7
9
  emitGate('ppt:no-mock-as-real', { mission_id: result.mission_id, proof_status: proof.status });
8
10
  //# sourceMappingURL=ppt-no-mock-as-real-check.js.map
@@ -25,7 +25,7 @@ assertGate(PRODUCT_DESIGN_PLUGIN.app_server.install_params.remoteMarketplaceName
25
25
  assertGate(PRODUCT_DESIGN_PLUGIN.app_server.read_params.pluginName === PRODUCT_DESIGN_PLUGIN.remote_plugin_id, 'plugin/read must use Product Design remote plugin id');
26
26
  assertGate(PRODUCT_DESIGN_PLUGIN.app_server.install_params.pluginName === PRODUCT_DESIGN_PLUGIN.remote_plugin_id, 'plugin/install must use Product Design remote plugin id');
27
27
  assertGate(PRODUCT_DESIGN_PLUGIN.app_server.list_params.marketplaceKinds.includes('vertical'), 'plugin/list must query vertical marketplaces');
28
- for (const skill of ['audit', 'design-qa', 'get-context', 'ideate', 'image-to-code', 'prototype', 'research', 'share', 'url-to-code', 'user-context']) {
28
+ for (const skill of ['audit', 'design-qa', 'get-context', 'ideate', 'image-to-code', 'index', 'research', 'share', 'url-to-code', 'user-context']) {
29
29
  assertGate(PRODUCT_DESIGN_REQUIRED_SKILLS.includes(skill), `Product Design required skill missing: ${skill}`);
30
30
  }
31
31
  assertGate(PRODUCT_DESIGN_PIPELINE_STAGES.length >= 5, 'Product Design pipeline stage map too small');
@@ -8,6 +8,7 @@ import { fileURLToPath } from 'node:url';
8
8
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
9
9
  const stampPath = process.env.SKS_RELEASE_STAMP_PATH || path.join(root, '.sneakoscope', 'reports', 'release-check-stamp.json');
10
10
  const command = process.argv[2] || 'verify';
11
+ const commandArgs = process.argv.slice(3);
11
12
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
12
13
  function fail(message, detail = '') {
13
14
  console.error(`Release check stamp failed: ${message}`);
@@ -270,7 +271,7 @@ function currentStampPayload() {
270
271
  include: (rel) => packageFileIncluded(`dist/${rel}`, packageEntries)
271
272
  });
272
273
  return {
273
- schema: 'sks.release-check-stamp.v1',
274
+ schema: 'sks.release-check-stamp.v2',
274
275
  package_name: pkg.name,
275
276
  package_version: pkg.version,
276
277
  git_commit: gitCommit(),
@@ -285,8 +286,10 @@ function currentStampPayload() {
285
286
  };
286
287
  }
287
288
  function writeStamp() {
289
+ const releaseGateProof = fullReleaseGateProofForWrite();
288
290
  const payload = {
289
291
  ...currentStampPayload(),
292
+ release_gate_proof: releaseGateProof,
290
293
  generated_at: new Date().toISOString()
291
294
  };
292
295
  fs.mkdirSync(path.dirname(stampPath), { recursive: true });
@@ -318,6 +321,9 @@ function inspectStamp() {
318
321
  if (stamp[key] !== current[key])
319
322
  mismatches.push(`${key}: stamp=${stamp[key] || 'missing'} current=${current[key] || 'missing'}`);
320
323
  }
324
+ const proofInspection = inspectFullReleaseGateProof(stamp.release_gate_proof);
325
+ if (!proofInspection.ok)
326
+ mismatches.push(...proofInspection.blockers.map((blocker) => `release_gate_proof:${blocker}`));
321
327
  if (mismatches.length) {
322
328
  return {
323
329
  ok: false,
@@ -328,6 +334,180 @@ function inspectStamp() {
328
334
  }
329
335
  return { ok: true, current };
330
336
  }
337
+ function fullReleaseGateProofForWrite() {
338
+ const preset = argValue('--preset');
339
+ const full = commandArgs.includes('--full');
340
+ if (preset !== 'release' || !full) {
341
+ fail('full release proof required to write publish stamp', 'Use `npm run release:check:full`; affected/fast/confidence checks cannot authorize publish.');
342
+ }
343
+ const explicit = argValue('--summary');
344
+ const summaryPath = explicit ? path.resolve(root, explicit) : latestFullReleaseSummaryPath();
345
+ if (!summaryPath)
346
+ fail('full release DAG summary missing', 'Run `npm run release:check:full` before writing the publish stamp.');
347
+ const reportRoot = path.resolve(root, '.sneakoscope', 'reports', 'release-gates');
348
+ const relative = path.relative(reportRoot, summaryPath);
349
+ if (relative.startsWith('..') || path.isAbsolute(relative))
350
+ fail('release DAG summary is outside the managed report root');
351
+ let summary;
352
+ try {
353
+ summary = JSON.parse(fs.readFileSync(summaryPath, 'utf8'));
354
+ }
355
+ catch (error) {
356
+ fail('unable to read full release DAG summary', error?.message || String(error));
357
+ }
358
+ const validation = validateFullReleaseSummary(summary);
359
+ if (validation.length)
360
+ fail('release DAG summary is not full publish proof', validation.join('\n'));
361
+ const explicitRealSummary = argValue('--real-summary');
362
+ const realSummaryPath = explicitRealSummary
363
+ ? path.resolve(root, explicitRealSummary)
364
+ : path.join(root, '.sneakoscope', 'reports', 'release-real-check.json');
365
+ const managedReports = path.resolve(root, '.sneakoscope', 'reports');
366
+ const realRelative = path.relative(managedReports, realSummaryPath);
367
+ if (realRelative.startsWith('..') || path.isAbsolute(realRelative))
368
+ fail('release real-check summary is outside the managed report root');
369
+ let realSummary;
370
+ try {
371
+ realSummary = JSON.parse(fs.readFileSync(realSummaryPath, 'utf8'));
372
+ }
373
+ catch (error) {
374
+ fail('unable to read release real-check summary', error?.message || String(error));
375
+ }
376
+ const realValidation = validateReleaseRealSummary(realSummary);
377
+ if (realValidation.length)
378
+ fail('release real-check summary is not publish proof', realValidation.join('\n'));
379
+ if (fs.statSync(realSummaryPath).mtimeMs < fs.statSync(summaryPath).mtimeMs)
380
+ fail('release real-check predates the full release DAG summary');
381
+ return {
382
+ schema: 'sks.release-check-full-proof.v1',
383
+ preset: 'release',
384
+ full: true,
385
+ run_id: summary.run_id,
386
+ summary_path: path.relative(root, summaryPath).split(path.sep).join('/'),
387
+ summary_sha256: sha256(fs.readFileSync(summaryPath)),
388
+ selected_gates: summary.selected_gates,
389
+ completed: summary.completed,
390
+ failed: summary.failed,
391
+ affected_mode: summary.affected_selection?.mode,
392
+ confidence: summary.completion_certificate?.confidence || null,
393
+ real_check_path: path.relative(root, realSummaryPath).split(path.sep).join('/'),
394
+ real_check_sha256: sha256(fs.readFileSync(realSummaryPath)),
395
+ real_check_count: realSummary.all_checks.length
396
+ };
397
+ }
398
+ function latestFullReleaseSummaryPath() {
399
+ const reportRoot = path.join(root, '.sneakoscope', 'reports', 'release-gates');
400
+ if (!fs.existsSync(reportRoot))
401
+ return null;
402
+ return fs.readdirSync(reportRoot, { withFileTypes: true })
403
+ .filter((entry) => entry.isDirectory())
404
+ .map((entry) => path.join(reportRoot, entry.name, 'summary.json'))
405
+ .filter((file) => fs.existsSync(file))
406
+ .map((file) => ({ file, stat: fs.statSync(file) }))
407
+ .sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs)
408
+ .map((row) => row.file)
409
+ .find((file) => {
410
+ try {
411
+ return validateFullReleaseSummary(JSON.parse(fs.readFileSync(file, 'utf8'))).length === 0;
412
+ }
413
+ catch {
414
+ return false;
415
+ }
416
+ }) || null;
417
+ }
418
+ function validateFullReleaseSummary(summary) {
419
+ const blockers = [];
420
+ if (summary?.schema !== 'sks.release-gate-dag-run.v1')
421
+ blockers.push('summary_schema_invalid');
422
+ if (summary?.ok !== true)
423
+ blockers.push('summary_not_ok');
424
+ if (summary?.selected_preset !== 'release')
425
+ blockers.push('preset_not_release');
426
+ if (summary?.affected_selection?.mode !== 'full')
427
+ blockers.push('affected_mode_not_full');
428
+ if (!Number.isInteger(summary?.selected_gates) || summary.selected_gates <= 0)
429
+ blockers.push('selected_gates_empty');
430
+ if (summary?.failed !== 0)
431
+ blockers.push('failed_gates_present');
432
+ if (summary?.completed !== summary?.selected_gates)
433
+ blockers.push('not_all_selected_gates_completed');
434
+ if (!Array.isArray(summary?.selected_gate_ids) || summary.selected_gate_ids.length !== summary.selected_gates)
435
+ blockers.push('selected_gate_ids_incomplete');
436
+ if (summary?.completion_certificate?.confidence !== 'full-release-proof')
437
+ blockers.push('completion_confidence_not_full');
438
+ if (summary?.completion_certificate?.full_release_proof !== 'current_run')
439
+ blockers.push('full_release_proof_not_current_run');
440
+ return blockers;
441
+ }
442
+ function validateReleaseRealSummary(summary) {
443
+ const blockers = [];
444
+ if (summary?.schema !== 'sks.release-real-check.v1')
445
+ blockers.push('real_check_schema_invalid');
446
+ if (summary?.ok !== true)
447
+ blockers.push('real_check_not_ok');
448
+ if (!Array.isArray(summary?.all_checks) || summary.all_checks.length === 0)
449
+ blockers.push('real_check_empty');
450
+ else if (summary.all_checks.some((row) => row?.ok !== true))
451
+ blockers.push('real_check_failures_present');
452
+ return blockers;
453
+ }
454
+ function inspectFullReleaseGateProof(proof) {
455
+ const blockers = [];
456
+ if (proof?.schema !== 'sks.release-check-full-proof.v1')
457
+ blockers.push('proof_schema_invalid');
458
+ if (proof?.preset !== 'release' || proof?.full !== true)
459
+ blockers.push('proof_not_full_release');
460
+ const summaryPath = proof?.summary_path ? path.resolve(root, proof.summary_path) : null;
461
+ const reportRoot = path.resolve(root, '.sneakoscope', 'reports', 'release-gates');
462
+ if (!summaryPath || !fs.existsSync(summaryPath))
463
+ blockers.push('summary_missing');
464
+ else {
465
+ const relative = path.relative(reportRoot, summaryPath);
466
+ if (relative.startsWith('..') || path.isAbsolute(relative))
467
+ blockers.push('summary_outside_managed_reports');
468
+ else {
469
+ const bytes = fs.readFileSync(summaryPath);
470
+ if (sha256(bytes) !== proof.summary_sha256)
471
+ blockers.push('summary_hash_mismatch');
472
+ try {
473
+ const summary = JSON.parse(bytes);
474
+ blockers.push(...validateFullReleaseSummary(summary));
475
+ if (summary.run_id !== proof.run_id || summary.selected_gates !== proof.selected_gates || summary.completed !== proof.completed || summary.failed !== proof.failed)
476
+ blockers.push('summary_identity_mismatch');
477
+ }
478
+ catch {
479
+ blockers.push('summary_parse_failed');
480
+ }
481
+ }
482
+ }
483
+ const realCheckPath = proof?.real_check_path ? path.resolve(root, proof.real_check_path) : null;
484
+ if (!realCheckPath || !fs.existsSync(realCheckPath))
485
+ blockers.push('real_check_summary_missing');
486
+ else {
487
+ const relative = path.relative(path.resolve(root, '.sneakoscope', 'reports'), realCheckPath);
488
+ if (relative.startsWith('..') || path.isAbsolute(relative))
489
+ blockers.push('real_check_summary_outside_managed_reports');
490
+ else {
491
+ const bytes = fs.readFileSync(realCheckPath);
492
+ if (sha256(bytes) !== proof.real_check_sha256)
493
+ blockers.push('real_check_summary_hash_mismatch');
494
+ try {
495
+ const realSummary = JSON.parse(bytes);
496
+ blockers.push(...validateReleaseRealSummary(realSummary));
497
+ if (realSummary.all_checks?.length !== proof.real_check_count)
498
+ blockers.push('real_check_identity_mismatch');
499
+ }
500
+ catch {
501
+ blockers.push('real_check_summary_parse_failed');
502
+ }
503
+ }
504
+ }
505
+ return { ok: blockers.length === 0, blockers: [...new Set(blockers)] };
506
+ }
507
+ function argValue(name) {
508
+ const index = commandArgs.indexOf(name);
509
+ return index >= 0 ? commandArgs[index + 1] || null : null;
510
+ }
331
511
  function verifyStamp() {
332
512
  const result = inspectStamp();
333
513
  if (!result.ok)
@@ -359,5 +539,5 @@ else if (command === 'verify')
359
539
  else if (command === 'ensure')
360
540
  ensureStamp();
361
541
  else
362
- fail(`unknown command ${command}`, 'Usage: node ./dist/scripts/release-check-stamp.js <write|verify|ensure>');
542
+ fail(`unknown command ${command}`, 'Usage: node ./dist/scripts/release-check-stamp.js <write --preset release --full [--summary path]|verify|ensure>');
363
543
  //# sourceMappingURL=release-check-stamp.js.map
@@ -14,14 +14,14 @@ const requiredReleasePresetIds = [
14
14
  'qa-loop:comprehensive-verification',
15
15
  'loop-integration-finalizer-check',
16
16
  'naruto:canonical-stop-gate',
17
- 'agent:native-cli-session-swarm',
18
- 'agent:native-cli-session-proof',
19
- 'agent:fast-mode-worker-propagation',
20
- 'release:dag-full-coverage',
17
+ 'agent:native-cli-session-swarm-scaling',
18
+ 'agent:fast-mode-policy',
19
+ 'codex-control:event-stream-ledger',
20
+ 'release:dag-runner',
21
21
  'release:gate-budget',
22
- 'release:gate-planner',
22
+ 'release:gate-selection-comprehensive',
23
23
  'policy:gate-audit',
24
- 'runtime:no-tmux',
24
+ 'runtime:proof-summary',
25
25
  'typecheck'
26
26
  ];
27
27
  const requiredHarnessPresetIds = [
@@ -42,7 +42,7 @@ const schemaComplete = [...releaseManifest.gates, ...harnessManifest.gates].ever
42
42
  const report = {
43
43
  schema: 'sks.release-dag-full-coverage-check.v2',
44
44
  ok: schemaComplete
45
- && releasePreset.length <= 220
45
+ && releasePreset.length <= 200
46
46
  && missingRequiredReleasePreset.length === 0
47
47
  && missingRequiredHarnessPreset.length === 0
48
48
  && duplicateAcrossManifests.length === 0
@@ -15,6 +15,14 @@ assertGate(String(scripts['release:check:affected']).includes('build:incremental
15
15
  assertGate(dag.includes('selectAffectedReleaseGates'), 'release DAG must use affected selector');
16
16
  assertGate(dagMod.selectReleaseGatePreset(manifest, 'affected').length === releaseCount, 'affected preset must select the release gate universe before affected filtering');
17
17
  assertGate(dagMod.selectReleaseGatePreset(manifest, 'fast').length === releaseCount, 'fast preset must select the release gate universe before affected filtering');
18
+ let unknownPresetBlocked = false;
19
+ try {
20
+ dagMod.selectReleaseGatePreset(manifest, 'unknown-preset');
21
+ }
22
+ catch (error) {
23
+ unknownPresetBlocked = /release_gate_preset_empty_or_unknown/.test(String(error?.message || error));
24
+ }
25
+ assertGate(unknownPresetBlocked, 'unknown or empty release presets must fail closed');
18
26
  assertGate(runner.includes('--changed-since') && runner.includes('--full') && runner.includes('--sla'), 'release DAG runner must parse changed-since/full/sla');
19
27
  emitGate('release:dynamic-presets', { presets: 4 });
20
28
  //# sourceMappingURL=release-dynamic-presets-check.js.map
@@ -17,7 +17,8 @@ const effectiveReleaseCheck = delegatedReleaseCheck ? String(pkg.scripts[delegat
17
17
  assertGate(effectiveReleaseCheck.includes('release-gate-dag-runner.js'), 'release:check must execute DAG runner', { release_check: releaseCheck, delegated_release_check: delegatedReleaseCheck || null, effective_release_check: effectiveReleaseCheck });
18
18
  assertGate(!/&&\s*npm run\s+\w/.test(releaseCheck.replace('npm run build --silent &&', '')), 'release:check must not be a giant npm-run chain', releaseCheck);
19
19
  assertGate(!/&&\s*npm run\s+\w/.test(effectiveReleaseCheck.replace('npm run build:incremental --silent &&', '').replace('npm run build --silent &&', '')), 'effective release:check must not be a giant npm-run chain', effectiveReleaseCheck);
20
- assertGate(pkg.scripts['release:check:legacy'], 'release:check:legacy must exist for explicit debugging');
20
+ assertGate(!pkg.scripts['release:check:legacy'], 'retired release:check:legacy alias must stay removed');
21
+ assertGate(pkg.scripts['release:real-check'] === 'node ./dist/scripts/release-real-check.js', 'release:real-check must expose the canonical environment-dependent proof runner');
21
22
  assertGate(manifest.schema === 'sks.release-gates.v2' && manifest.gates.length >= 10, 'release-gates.v2 manifest must exist with nodes', manifest);
22
23
  for (const gateId of [
23
24
  'scheduler:comprehensive',
@@ -37,7 +38,7 @@ assertGate(runner.includes('detached: process.platform') && runner.includes('kil
37
38
  assertGate(runner.includes('pruneOldReleaseGateRunDirs') && runner.includes('SKS_RELEASE_GATE_RUN_RETENTION'), 'DAG runner must prune stale release-gate run reports before they exhaust local disk');
38
39
  assertGate(runnerCli.includes('ensureCurrentMigrationBeforeCommand') && runnerCli.includes('release-gate-runner-preflight'), 'DAG runner CLI must self-heal project migration before hermetic gates run');
39
40
  assertGate(hermeticEnv.includes('SKS_UPDATE_MIGRATION_GATE_DISABLED'), 'hermetic release gates must not rewrite project migration receipts from temporary HOME roots');
40
- assertGate(hermeticEnv.includes('legacy:update-e2e') && hermeticEnv.includes('migrationGateDisabled'), 'legacy:update-e2e must keep migration gate enabled while testing migration retry/repair behavior');
41
+ assertGate(hermeticEnv.includes("input.gate.id === 'legacy:update-e2e'") && hermeticEnv.includes('delete gateEnv.SKS_UPDATE_MIGRATION_GATE_DISABLED'), 'legacy:update-e2e must explicitly remove an inherited disable flag while testing migration retry/repair behavior');
41
42
  const dag = await importDist('core/release/release-gate-dag.js');
42
43
  const fsx = await importDist('core/fsx.js');
43
44
  const fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-release-dag-timeout-'));