sneakoscope 4.8.7 → 5.1.2

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 (288) hide show
  1. package/README.md +51 -726
  2. package/bench/tasks/t01-off-by-one/repo/package.json +9 -0
  3. package/bench/tasks/t01-off-by-one/repo/src/pagination.js +5 -0
  4. package/bench/tasks/t01-off-by-one/repo/test.js +5 -0
  5. package/bench/tasks/t01-off-by-one/task.json +13 -0
  6. package/bench/tasks/t02-signature-cochange/repo/package.json +9 -0
  7. package/bench/tasks/t02-signature-cochange/repo/src/admin.js +5 -0
  8. package/bench/tasks/t02-signature-cochange/repo/src/audit.js +5 -0
  9. package/bench/tasks/t02-signature-cochange/repo/src/labels.js +3 -0
  10. package/bench/tasks/t02-signature-cochange/repo/src/profile.js +5 -0
  11. package/bench/tasks/t02-signature-cochange/repo/test.js +9 -0
  12. package/bench/tasks/t02-signature-cochange/task.json +12 -0
  13. package/bench/tasks/t03-type-puzzle/repo/package.json +9 -0
  14. package/bench/tasks/t03-type-puzzle/repo/src/config.js +4 -0
  15. package/bench/tasks/t03-type-puzzle/repo/test.js +6 -0
  16. package/bench/tasks/t03-type-puzzle/task.json +13 -0
  17. package/bench/tasks/t04-refactor-preserve/repo/package.json +9 -0
  18. package/bench/tasks/t04-refactor-preserve/repo/src/cart.js +8 -0
  19. package/bench/tasks/t04-refactor-preserve/repo/test.js +4 -0
  20. package/bench/tasks/t04-refactor-preserve/task.json +12 -0
  21. package/bench/tasks/t05-performance/repo/package.json +9 -0
  22. package/bench/tasks/t05-performance/repo/src/pairs.js +9 -0
  23. package/bench/tasks/t05-performance/repo/test.js +11 -0
  24. package/bench/tasks/t05-performance/task.json +12 -0
  25. package/bench/tasks/t06-mistake-rule/repo/package.json +9 -0
  26. package/bench/tasks/t06-mistake-rule/repo/src/loader.js +6 -0
  27. package/bench/tasks/t06-mistake-rule/repo/test.js +7 -0
  28. package/bench/tasks/t06-mistake-rule/task.json +12 -0
  29. package/config/bench-baseline.json +7 -0
  30. package/crates/sks-core/Cargo.lock +1 -1
  31. package/crates/sks-core/Cargo.toml +1 -1
  32. package/crates/sks-core/src/main.rs +1 -1
  33. package/dist/bin/install.js +35 -0
  34. package/dist/bin/sks.js +1 -1
  35. package/dist/cli/cli-theme.js +51 -0
  36. package/dist/cli/command-registry.js +15 -4
  37. package/dist/cli/help-fast.js +18 -8
  38. package/dist/cli/insane-search-command.js +36 -8
  39. package/dist/cli/install-helpers.js +32 -0
  40. package/dist/commands/codex-lb.js +2 -0
  41. package/dist/commands/doctor.js +62 -6
  42. package/dist/commands/proof.js +6 -3
  43. package/dist/config/skills-manifest.json +82 -54
  44. package/dist/core/agents/agent-conflict-graph.js +5 -0
  45. package/dist/core/agents/agent-lease.js +5 -0
  46. package/dist/core/agents/agent-ledger-schemas.js +1 -0
  47. package/dist/core/agents/agent-orchestrator.js +268 -62
  48. package/dist/core/agents/agent-output-validator.js +14 -3
  49. package/dist/core/agents/agent-patch-queue-store.js +95 -2
  50. package/dist/core/agents/agent-patch-queue.js +6 -3
  51. package/dist/core/agents/agent-patch-schema.js +13 -0
  52. package/dist/core/agents/agent-proof-evidence.js +6 -1
  53. package/dist/core/agents/agent-runner-fake.js +40 -0
  54. package/dist/core/agents/agent-worker-pipeline.js +36 -2
  55. package/dist/core/agents/codex-exec-worker-adapter.js +2 -0
  56. package/dist/core/agents/native-worker-backend-router.js +58 -1
  57. package/dist/core/codex-app/sks-menubar.js +18 -5
  58. package/dist/core/codex-app.js +1 -0
  59. package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
  60. package/dist/core/codex-control/codex-sdk-env-policy.js +1 -1
  61. package/dist/core/codex-control/schemas/agent-worker-result.schema.js +12 -3
  62. package/dist/core/codex-hooks/codex-hook-managed-install.js +5 -0
  63. package/dist/core/codex-hooks/codex-hook-state-writer.js +70 -11
  64. package/dist/core/codex-hooks/codex-hook-trust-doctor.js +2 -2
  65. package/dist/core/codex-lb/codex-lb-env.js +20 -1
  66. package/dist/core/commands/basic-cli.js +21 -2
  67. package/dist/core/commands/check-command.js +37 -5
  68. package/dist/core/commands/computer-use-command.js +62 -7
  69. package/dist/core/commands/db-command.js +31 -5
  70. package/dist/core/commands/fast-mode-command.js +3 -0
  71. package/dist/core/commands/gate-result-contract.js +43 -0
  72. package/dist/core/commands/gates-command.js +6 -1
  73. package/dist/core/commands/gc-command.js +29 -2
  74. package/dist/core/commands/goal-command.js +9 -2
  75. package/dist/core/commands/gx-command.js +79 -7
  76. package/dist/core/commands/image-ux-review-command.js +188 -13
  77. package/dist/core/commands/mad-db-command.js +85 -176
  78. package/dist/core/commands/mad-sks-command.js +230 -29
  79. package/dist/core/commands/menubar-command.js +22 -1
  80. package/dist/core/commands/naruto-command.js +64 -10
  81. package/dist/core/commands/plan-command.js +76 -0
  82. package/dist/core/commands/ppt-command.js +159 -24
  83. package/dist/core/commands/qa-loop-command.js +6 -2
  84. package/dist/core/commands/release-command.js +55 -2
  85. package/dist/core/commands/research-command.js +1 -1
  86. package/dist/core/commands/review-command.js +217 -0
  87. package/dist/core/commands/route-success-helpers.js +59 -0
  88. package/dist/core/commands/run-command.js +19 -7
  89. package/dist/core/commands/seo-command.js +49 -1
  90. package/dist/core/commands/ui-command.js +161 -0
  91. package/dist/core/commands/uninstall-command.js +15 -1
  92. package/dist/core/db-safety.js +2 -2
  93. package/dist/core/doctor/doctor-transaction.js +8 -0
  94. package/dist/core/doctor/doctor-zellij-repair.js +1 -0
  95. package/dist/core/doctor/imagegen-repair.js +161 -0
  96. package/dist/core/feature-fixture-runner.js +2 -2
  97. package/dist/core/feature-fixtures.js +58 -37
  98. package/dist/core/feature-registry.js +102 -2
  99. package/dist/core/fsx.js +39 -6
  100. package/dist/core/image-ux-review/imagegen-adapter.js +48 -11
  101. package/dist/core/image-ux-review.js +16 -0
  102. package/dist/core/imagegen/imagegen-capability.js +11 -5
  103. package/dist/core/imagegen/require-imagegen.js +57 -0
  104. package/dist/core/init/skills.js +10 -5
  105. package/dist/core/mad-db/mad-db-coordinator.js +94 -18
  106. package/dist/core/mad-db/mad-db-policy.js +12 -10
  107. package/dist/core/mad-sks/executors/executor-base.js +8 -2
  108. package/dist/core/mad-sks/executors/index.js +4 -0
  109. package/dist/core/mad-sks/executors/sql-plane-executor.js +194 -0
  110. package/dist/core/naruto/naruto-active-pool.js +15 -4
  111. package/dist/core/naruto/naruto-real-worker-child.js +10 -0
  112. package/dist/core/naruto/naruto-role-policy.js +3 -0
  113. package/dist/core/naruto/naruto-task-hints.js +10 -0
  114. package/dist/core/naruto/naruto-work-graph.js +8 -2
  115. package/dist/core/naruto/naruto-work-item.js +6 -0
  116. package/dist/core/naruto/solution-tournament.js +101 -0
  117. package/dist/core/permission-gates.js +30 -0
  118. package/dist/core/pipeline-internals/runtime-core.js +11 -3
  119. package/dist/core/pipeline-internals/runtime-gates.js +27 -0
  120. package/dist/core/ppt-review/index.js +6 -1
  121. package/dist/core/ppt-review/slide-imagegen-review.js +75 -10
  122. package/dist/core/ppt.js +70 -2
  123. package/dist/core/proof/auto-finalize.js +70 -11
  124. package/dist/core/proof/proof-schema.js +2 -0
  125. package/dist/core/proof/route-adapter.js +5 -1
  126. package/dist/core/proof/route-finalizer.js +8 -5
  127. package/dist/core/proof/selftest-proof-fixtures.js +18 -5
  128. package/dist/core/proof/validation.js +2 -0
  129. package/dist/core/provider/model-router.js +53 -0
  130. package/dist/core/release/release-gate-node.js +3 -0
  131. package/dist/core/release/release-gate-resource-governor.js +1 -0
  132. package/dist/core/routes/constants.js +1 -1
  133. package/dist/core/routes.js +65 -18
  134. package/dist/core/safety/mutation-guard.js +5 -1
  135. package/dist/core/stop-gate/gate-evaluator.js +102 -0
  136. package/dist/core/stop-gate/stop-gate-check.js +16 -1
  137. package/dist/core/stop-gate/stop-gate-writer.js +4 -0
  138. package/dist/core/triwiki/agents-md-projector.js +184 -0
  139. package/dist/core/triwiki-wrongness/wrongness-schema.js +3 -1
  140. package/dist/core/trust-kernel/trust-kernel-schema.js +1 -0
  141. package/dist/core/trust-kernel/trust-report.js +1 -1
  142. package/dist/core/trust-kernel/trust-status.js +2 -0
  143. package/dist/core/ui/dashboard-html.js +111 -0
  144. package/dist/core/update/update-migration-state.js +366 -15
  145. package/dist/core/update-check.js +178 -81
  146. package/dist/core/verification/diff-quality.js +100 -0
  147. package/dist/core/verification/impact-scan.js +164 -0
  148. package/dist/core/verification/machine-feedback.js +146 -0
  149. package/dist/core/verification/mistake-rule-compiler.js +195 -0
  150. package/dist/core/version.js +1 -1
  151. package/dist/core/zellij/zellij-self-heal.js +9 -6
  152. package/dist/scripts/check-feature-quality.js +2 -2
  153. package/dist/scripts/cli-output-consistency-check.js +57 -0
  154. package/dist/scripts/coding-bench-check.js +136 -0
  155. package/dist/scripts/doctor-imagegen-repair-check.js +62 -0
  156. package/dist/scripts/ensure-bin-executable.js +11 -3
  157. package/dist/scripts/harness-benchmark-check.js +104 -0
  158. package/dist/scripts/legacy-update-e2e-check.js +228 -0
  159. package/dist/scripts/mad-db-command-check.js +11 -8
  160. package/dist/scripts/mad-db-route-identity-check.js +8 -6
  161. package/dist/scripts/mad-db-safety-conflict-matrix-check.js +31 -8
  162. package/dist/scripts/mad-db-skill-policy-snapshot-check.js +4 -5
  163. package/dist/scripts/ppt-real-imagegen-wiring-check.js +5 -1
  164. package/dist/scripts/proof-root-cause-policy-check.js +2 -0
  165. package/dist/scripts/release-dag-full-coverage-check.js +13 -4
  166. package/dist/scripts/release-gate-dag-runner.js +14 -0
  167. package/dist/scripts/release-gate-existence-audit.js +2 -1
  168. package/dist/scripts/release-gate-planner.js +2 -1
  169. package/dist/scripts/release-gate-script-parity-check.js +1 -1
  170. package/dist/scripts/release-metadata-1-19-check.js +2 -1
  171. package/dist/scripts/seo-geo-feature-fixture-quality-check.js +1 -1
  172. package/dist/scripts/sks-1-11-gate-lib.js +8 -6
  173. package/dist/scripts/ux-review-real-loop-fixture-check.js +9 -4
  174. package/dist/scripts/ux-review-run-wires-imagegen-check.js +4 -0
  175. package/docs/assets/sneakoscope-architecture-pipeline.jpg +0 -0
  176. package/docs/demo.tape +28 -0
  177. package/package.json +67 -3
  178. package/schemas/codex/completion-proof.schema.json +3 -2
  179. package/schemas/release/release-gate-node.schema.json +2 -1
  180. package/dist/scripts/agent-backfill-route-blackbox.js +0 -5
  181. package/dist/scripts/agent-dynamic-pool-route-blackbox.js +0 -5
  182. package/dist/scripts/agent-parallel-write-blackbox.js +0 -56
  183. package/dist/scripts/agent-patch-swarm-route-blackbox.js +0 -10
  184. package/dist/scripts/agent-route-blackbox-lib.js +0 -132
  185. package/dist/scripts/blackbox-command-import-smoke.js +0 -143
  186. package/dist/scripts/blackbox-global-shim.js +0 -77
  187. package/dist/scripts/blackbox-matrix.js +0 -70
  188. package/dist/scripts/blackbox-npx-one-shot.js +0 -69
  189. package/dist/scripts/blackbox-pack-install.js +0 -174
  190. package/dist/scripts/brand-neutrality-zero-leakage-blackbox.js +0 -4
  191. package/dist/scripts/build-once-runner-blackbox.js +0 -34
  192. package/dist/scripts/codex-0140-integration-blackbox.js +0 -13
  193. package/dist/scripts/codex-agent-type-blackbox.js +0 -4
  194. package/dist/scripts/codex-app-harness-blackbox.js +0 -4
  195. package/dist/scripts/codex-app-skill-agent-blackbox.js +0 -4
  196. package/dist/scripts/codex-hook-approval-blackbox.js +0 -4
  197. package/dist/scripts/codex-init-deep-directory-local-blackbox.js +0 -4
  198. package/dist/scripts/codex-native-feature-broker-blackbox.js +0 -4
  199. package/dist/scripts/codex-native-pattern-analysis-blackbox.js +0 -4
  200. package/dist/scripts/codex-native-read-repair-split-blackbox.js +0 -55
  201. package/dist/scripts/codex-native-reference-cache-blackbox.js +0 -41
  202. package/dist/scripts/core-skill-integrity-blackbox.js +0 -32
  203. package/dist/scripts/dfix-fast-blackbox-check.js +0 -37
  204. package/dist/scripts/dfix-parallel-write-blackbox.js +0 -48
  205. package/dist/scripts/dfix-patch-swarm-route-blackbox.js +0 -10
  206. package/dist/scripts/doctor-context7-mcp-repair-blackbox.js +0 -16
  207. package/dist/scripts/doctor-dirty-repair-blackbox.js +0 -22
  208. package/dist/scripts/doctor-dirty-semantic-blackbox.js +0 -8
  209. package/dist/scripts/doctor-fix-production-blackbox.js +0 -26
  210. package/dist/scripts/doctor-native-capability-repair-blackbox.js +0 -39
  211. package/dist/scripts/doctor-startup-config-repair-blackbox.js +0 -13
  212. package/dist/scripts/doctor-supabase-mcp-repair-blackbox.js +0 -14
  213. package/dist/scripts/doctor-transaction-engine-blackbox.js +0 -28
  214. package/dist/scripts/doctor-zellij-fix-blackbox.js +0 -4
  215. package/dist/scripts/doctor-zellij-no-homebrew-blackbox.js +0 -4
  216. package/dist/scripts/doctor-zellij-upgrade-blackbox.js +0 -4
  217. package/dist/scripts/gate-pack-runner-blackbox.js +0 -27
  218. package/dist/scripts/gate-pack-v2-blackbox.js +0 -18
  219. package/dist/scripts/geo-cli-blackbox-check.js +0 -18
  220. package/dist/scripts/loop-collision-blackbox.js +0 -3
  221. package/dist/scripts/loop-concurrency-oversubscription-blackbox.js +0 -3
  222. package/dist/scripts/loop-fixture-production-misuse-blackbox.js +0 -3
  223. package/dist/scripts/loop-kill-interrupt-real-blackbox.js +0 -3
  224. package/dist/scripts/loop-merge-strategy-blackbox.js +0 -3
  225. package/dist/scripts/loop-mesh-production-e2e-blackbox.js +0 -3
  226. package/dist/scripts/loop-side-effect-blackbox.js +0 -3
  227. package/dist/scripts/mad-db-operation-lifecycle-blackbox.js +0 -29
  228. package/dist/scripts/mad-sks-actual-executor-blackbox.js +0 -5
  229. package/dist/scripts/mad-zellij-headless-fallback-blackbox.js +0 -4
  230. package/dist/scripts/mad-zellij-self-heal-blackbox.js +0 -4
  231. package/dist/scripts/naruto-loop-mesh-blackbox.js +0 -3
  232. package/dist/scripts/naruto-real-parallelism-blackbox.js +0 -307
  233. package/dist/scripts/naruto-worktree-coding-blackbox.js +0 -29
  234. package/dist/scripts/parallel-runtime-real-blackbox.js +0 -44
  235. package/dist/scripts/pipeline-codex-native-doctor-mad-routing-real-blackbox.js +0 -77
  236. package/dist/scripts/pipeline-codex-native-e2e-blackbox.js +0 -13
  237. package/dist/scripts/pipeline-codex-native-image-routing-real-blackbox.js +0 -50
  238. package/dist/scripts/pipeline-codex-native-loop-routing-real-blackbox.js +0 -74
  239. package/dist/scripts/pipeline-codex-native-qa-routing-real-blackbox.js +0 -51
  240. package/dist/scripts/pipeline-codex-native-research-routing-real-blackbox.js +0 -45
  241. package/dist/scripts/pipeline-execution-profile-routing-blackbox.js +0 -4
  242. package/dist/scripts/postinstall-global-doctor-blackbox.js +0 -12
  243. package/dist/scripts/ppt-full-e2e-blackbox-check.js +0 -109
  244. package/dist/scripts/ppt-imagegen-blackbox-check.js +0 -46
  245. package/dist/scripts/project-skill-dedupe-blackbox.js +0 -36
  246. package/dist/scripts/qa-backfill-route-blackbox.js +0 -5
  247. package/dist/scripts/qa-patch-swarm-route-blackbox.js +0 -10
  248. package/dist/scripts/release-full-parallelism-blackbox.js +0 -41
  249. package/dist/scripts/release-triwiki-first-runner-blackbox.js +0 -48
  250. package/dist/scripts/release-wiring-3110-blackbox.js +0 -27
  251. package/dist/scripts/release-wiring-3112-blackbox.js +0 -17
  252. package/dist/scripts/release-wiring-3113-blackbox.js +0 -17
  253. package/dist/scripts/research-backfill-route-blackbox.js +0 -5
  254. package/dist/scripts/research-final-reviewer-blackbox.js +0 -70
  255. package/dist/scripts/research-stage-cycle-runtime-blackbox.js +0 -40
  256. package/dist/scripts/research-synthesis-writer-blackbox.js +0 -24
  257. package/dist/scripts/route-blackbox-realism-check.js +0 -21
  258. package/dist/scripts/scheduler-resource-claim-blackbox.js +0 -24
  259. package/dist/scripts/seo-cli-blackbox-check.js +0 -18
  260. package/dist/scripts/sks-3110-all-feature-regression-blackbox.js +0 -116
  261. package/dist/scripts/sks-3112-all-feature-regression-blackbox.js +0 -29
  262. package/dist/scripts/sks-3113-all-feature-regression-blackbox.js +0 -17
  263. package/dist/scripts/sks-400-all-feature-regression-blackbox.js +0 -21
  264. package/dist/scripts/sks-400-extreme-parallel-blackbox.js +0 -8
  265. package/dist/scripts/sks-400-five-minute-blackbox.js +0 -9
  266. package/dist/scripts/sks-400-legacy-purge-blackbox.js +0 -8
  267. package/dist/scripts/sks-401-all-feature-regression-blackbox.js +0 -46
  268. package/dist/scripts/sks-401-five-minute-actual-blackbox.js +0 -23
  269. package/dist/scripts/sks-402-all-feature-regression-blackbox.js +0 -9
  270. package/dist/scripts/sks-402-five-minute-real-blackbox.js +0 -22
  271. package/dist/scripts/sksd-warm-cache-blackbox.js +0 -12
  272. package/dist/scripts/supabase-secret-preservation-blackbox.js +0 -29
  273. package/dist/scripts/team-backfill-route-blackbox.js +0 -5
  274. package/dist/scripts/team-parallel-write-blackbox.js +0 -55
  275. package/dist/scripts/team-patch-swarm-route-blackbox.js +0 -10
  276. package/dist/scripts/triwiki-affected-graph-blackbox.js +0 -28
  277. package/dist/scripts/triwiki-proof-bank-blackbox.js +0 -30
  278. package/dist/scripts/triwiki-proof-bank-lock-blackbox.js +0 -7
  279. package/dist/scripts/update-preserves-supabase-keys-blackbox.js +0 -27
  280. package/dist/scripts/ux-patch-swarm-route-blackbox.js +0 -10
  281. package/dist/scripts/ux-review-imagegen-blackbox-check.js +0 -67
  282. package/dist/scripts/zellij-initial-main-only-blackbox.js +0 -28
  283. package/dist/scripts/zellij-pane-lock-concurrency-blackbox.js +0 -80
  284. package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +0 -137
  285. package/dist/scripts/zellij-self-heal-typed-blackbox.js +0 -4
  286. package/dist/scripts/zellij-slot-telemetry-real-blackbox.js +0 -20
  287. package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +0 -81
  288. package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +0 -202
@@ -1,7 +1,11 @@
1
1
  import path from 'node:path';
2
- import { appendJsonl, appendJsonlMany, readJson, writeJsonAtomic } from '../fsx.js';
2
+ import { appendJsonl, appendJsonlMany, ensureDir, readJson, writeJsonAtomic } from '../fsx.js';
3
3
  import { AGENT_PATCH_QUEUE_SCHEMA, InMemoryAgentPatchQueue, buildAgentPatchOwnershipLedger } from './agent-patch-queue.js';
4
4
  import { AgentPatchTransactionJournal } from './agent-patch-transaction-journal.js';
5
+ import { normalizeAgentPatchEnvelope } from './agent-patch-schema.js';
6
+ import { scanImpact } from '../verification/impact-scan.js';
7
+ import { runMachineFeedback } from '../verification/machine-feedback.js';
8
+ import { analyzeDiffQuality } from '../verification/diff-quality.js';
5
9
  export const AGENT_PATCH_QUEUE_ARTIFACT = 'agent-patch-queue.json';
6
10
  export const AGENT_PATCH_QUEUE_EVENTS_ARTIFACT = 'agent-patch-queue-events.jsonl';
7
11
  export const AGENT_PATCH_OWNERSHIP_LEDGER_ARTIFACT = 'agent-patch-ownership-ledger.json';
@@ -15,7 +19,13 @@ export class PersistentAgentPatchQueueStore {
15
19
  this.journal = new AgentPatchTransactionJournal(artifactDir);
16
20
  }
17
21
  async enqueue(input, context = {}) {
18
- const entry = this.queue.enqueue(input, context);
22
+ const preflight = await this.runQualityPreflight(input, context);
23
+ const entry = this.queue.enqueue(input, {
24
+ ...(context.mission_id ? { mission_id: context.mission_id } : {}),
25
+ ...(context.route ? { route: context.route } : {}),
26
+ preflight_violations: preflight.violations,
27
+ preflight_reports: preflight.reports
28
+ });
19
29
  await this.persistSnapshot();
20
30
  await this.appendEvent(this.queue.events.at(-1));
21
31
  await this.journal.append({
@@ -29,6 +39,43 @@ export class PersistentAgentPatchQueueStore {
29
39
  });
30
40
  return entry;
31
41
  }
42
+ async runQualityPreflight(input, context = {}) {
43
+ const envelope = normalizeAgentPatchEnvelope(input);
44
+ const changedFiles = changedFilesForEnvelope(envelope);
45
+ const patchText = patchTextForEnvelope(envelope);
46
+ const root = envelope.git_worktree?.worktree_path || context.root || process.cwd();
47
+ const reportDir = path.join(this.artifactDir, 'patch-quality', safeName(`${envelope.agent_id}-${envelope.session_id}-${Date.now()}`));
48
+ await ensureDir(reportDir);
49
+ const [impact, diffQuality, feedback] = await Promise.all([
50
+ scanImpact(root, changedFiles, patchText).catch((err) => ({ schema: 'sks.impact-scan.v1', changed_symbols: [], references: [], cochange_required: [], tool: 'builtin', error: errorMessage(err) })),
51
+ analyzeDiffQuality({
52
+ root,
53
+ changedFiles,
54
+ patchText,
55
+ plannedFiles: envelope.allowed_paths || envelope.lease_proof?.allowed_paths || []
56
+ }).catch((err) => ({ schema: 'sks.diff-quality.v1', minimality: { plan_files: 0, touched_files: changedFiles.length, ratio: 1 }, dead_additions: [], comment_noise: 0, guard_bloat: 0, warnings: [], errors: [`diff_quality_failed:${errorMessage(err)}`] })),
57
+ runMachineFeedback(root, changedFiles, { timeoutMs: 60_000 }).catch((err) => ({ schema: 'sks.machine-feedback.v1', ok: false, typecheck: { ok: false, errors: [errorMessage(err)] }, lint: { ok: true, errors: [] }, tests: { ok: true, selected: [], failed: [], skipped_reason: 'machine_feedback_exception' }, duration_ms: 0 }))
58
+ ]);
59
+ await writeJsonAtomic(path.join(reportDir, 'impact-scan.json'), impact);
60
+ await writeJsonAtomic(path.join(reportDir, 'diff-quality.json'), diffQuality);
61
+ await writeJsonAtomic(path.join(reportDir, 'machine-feedback.json'), feedback);
62
+ const cochangeAck = envelope.cochange_acknowledged === true && String(envelope.cochange_acknowledged_reason || '').trim().length > 0;
63
+ const violations = [
64
+ ...(impact.cochange_required?.length && !cochangeAck ? [`impact_scan_cochange_missing:${impact.cochange_required.slice(0, 5).join(',')}`] : []),
65
+ ...((diffQuality.errors || []).map((issue) => `diff_quality:${issue}`)),
66
+ ...(feedback.ok === false ? ['machine_feedback_failed'] : []),
67
+ ...(isBugfixKind(context.work_item_kind, envelope.task_slice_id) && !validRegressionProof(envelope.regression_proof || context.regression_proof) ? ['tdd_evidence_missing'] : []),
68
+ ...(isRepairKind(context.work_item_kind, envelope.task_slice_id) && !(envelope.repair_hypothesis || context.repair_hypothesis) ? ['repair_without_hypothesis'] : [])
69
+ ];
70
+ return {
71
+ violations,
72
+ reports: {
73
+ impact_scan: path.relative(this.artifactDir, path.join(reportDir, 'impact-scan.json')),
74
+ diff_quality: path.relative(this.artifactDir, path.join(reportDir, 'diff-quality.json')),
75
+ machine_feedback: path.relative(this.artifactDir, path.join(reportDir, 'machine-feedback.json'))
76
+ }
77
+ };
78
+ }
32
79
  async markApplying(id) {
33
80
  await this.transition(id, () => this.queue.markApplying(id));
34
81
  }
@@ -98,4 +145,50 @@ export class PersistentAgentPatchQueueStore {
98
145
  await appendJsonlMany(path.join(this.artifactDir, AGENT_PATCH_QUEUE_EVENTS_ARTIFACT), events.filter(Boolean));
99
146
  }
100
147
  }
148
+ function isBugfixKind(kind, id) {
149
+ const text = `${String(kind || '')} ${String(id || '')}`.toLowerCase();
150
+ return /\b(bugfix|fix|bug|regression|broken|failure|crash|error)\b|버그|회귀/.test(text);
151
+ }
152
+ function isRepairKind(kind, id) {
153
+ const text = `${String(kind || '')} ${String(id || '')}`.toLowerCase();
154
+ return /\b(conflict_resolution|repair|conflict|rebase|rollback)\b|수리|충돌/.test(text);
155
+ }
156
+ function validRegressionProof(proof) {
157
+ return Boolean(proof && proof.failed_before === true && proof.passed_after === true && String(proof.test_file || '').trim());
158
+ }
159
+ function changedFilesForEnvelope(envelope) {
160
+ const files = envelope.git_worktree?.changed_files?.length
161
+ ? envelope.git_worktree.changed_files
162
+ : envelope.operations.map((operation) => operation.path);
163
+ return [...new Set(files.map(normalizePath).filter(Boolean))];
164
+ }
165
+ function patchTextForEnvelope(envelope) {
166
+ return envelope.operations.map((operation) => {
167
+ if (operation.diff)
168
+ return operation.diff;
169
+ if (operation.op === 'replace')
170
+ return [
171
+ `--- a/${operation.path}`,
172
+ `+++ b/${operation.path}`,
173
+ `-${operation.search || ''}`,
174
+ `+${operation.replace || ''}`
175
+ ].join('\n');
176
+ if (operation.op === 'write')
177
+ return [
178
+ `--- /dev/null`,
179
+ `+++ b/${operation.path}`,
180
+ ...String(operation.content || '').split(/\r?\n/).map((line) => `+${line}`)
181
+ ].join('\n');
182
+ return '';
183
+ }).join('\n');
184
+ }
185
+ function normalizePath(value) {
186
+ return String(value || '').replace(/\\/g, '/').replace(/^\.\/+/, '');
187
+ }
188
+ function safeName(value) {
189
+ return String(value || 'patch').replace(/[^A-Za-z0-9_.-]+/g, '-').slice(0, 160);
190
+ }
191
+ function errorMessage(err) {
192
+ return err instanceof Error ? err.message : String(err);
193
+ }
101
194
  //# sourceMappingURL=agent-patch-queue-store.js.map
@@ -6,6 +6,7 @@ export class InMemoryAgentPatchQueue {
6
6
  enqueue(input, context = {}) {
7
7
  const envelope = normalizeAgentPatchEnvelope(input);
8
8
  const validation = validateAgentPatchEnvelope(envelope);
9
+ const preflightViolations = Array.isArray(context.preflight_violations) ? context.preflight_violations.map(String) : [];
9
10
  const now = new Date().toISOString();
10
11
  const leaseId = envelope.lease_id || envelope.lease_proof?.lease_id;
11
12
  const entry = {
@@ -19,8 +20,9 @@ export class InMemoryAgentPatchQueue {
19
20
  ...(leaseId ? { lease_id: leaseId } : {}),
20
21
  write_paths: envelope.operations.map((operation) => operation.path),
21
22
  envelope,
22
- status: validation.ok ? 'pending' : 'rejected',
23
- violations: validation.violations,
23
+ status: validation.ok && preflightViolations.length === 0 ? 'pending' : 'rejected',
24
+ violations: [...validation.violations, ...preflightViolations],
25
+ ...(context.preflight_reports ? { quality_reports: context.preflight_reports } : {}),
24
26
  created_at: now,
25
27
  updated_at: now
26
28
  };
@@ -97,7 +99,8 @@ export function buildAgentPatchOwnershipLedger(entries) {
97
99
  status: entry.status,
98
100
  created_at: entry.created_at,
99
101
  updated_at: entry.updated_at,
100
- violations: [...entry.violations]
102
+ violations: [...entry.violations],
103
+ quality_reports: entry.quality_reports || null
101
104
  }));
102
105
  }
103
106
  //# sourceMappingURL=agent-patch-queue.js.map
@@ -31,6 +31,11 @@ export function normalizeAgentPatchEnvelope(input) {
31
31
  ...(input?.rationale ? { rationale: String(input.rationale) } : {}),
32
32
  ...(input?.verification_hint ? { verification_hint: normalizeHint(input.verification_hint) } : {}),
33
33
  ...(input?.rollback_hint ? { rollback_hint: normalizeHint(input.rollback_hint) } : {}),
34
+ ...(input?.cochange_acknowledged === undefined ? {} : { cochange_acknowledged: Boolean(input.cochange_acknowledged) }),
35
+ ...(input?.cochange_acknowledged_reason === undefined ? {} : { cochange_acknowledged_reason: String(input.cochange_acknowledged_reason) }),
36
+ ...(input?.regression_proof ? { regression_proof: normalizeRegressionProof(input.regression_proof) } : {}),
37
+ ...(input?.repair_hypothesis && typeof input.repair_hypothesis === 'object' ? { repair_hypothesis: input.repair_hypothesis } : {}),
38
+ ...(input?.tournament && typeof input.tournament === 'object' ? { tournament: input.tournament } : {}),
34
39
  operations: Array.isArray(input?.operations) ? input.operations.map(normalizeOperation) : []
35
40
  };
36
41
  }
@@ -135,6 +140,14 @@ function normalizeHint(input) {
135
140
  ...(input?.notes === undefined ? {} : { notes: String(input.notes) })
136
141
  };
137
142
  }
143
+ function normalizeRegressionProof(input) {
144
+ return {
145
+ ...(input?.test_file === undefined ? {} : { test_file: String(input.test_file) }),
146
+ ...(input?.failed_before === undefined ? {} : { failed_before: Boolean(input.failed_before) }),
147
+ ...(input?.passed_after === undefined ? {} : { passed_after: Boolean(input.passed_after) }),
148
+ ...(input?.output_digest === undefined ? {} : { output_digest: String(input.output_digest) })
149
+ };
150
+ }
138
151
  function pathAllowedByLease(operationPath, allowedPaths) {
139
152
  const rel = normalizePatchPath(operationPath);
140
153
  return allowedPaths.map(normalizePatchPath).some((allowed) => rel === allowed || rel.startsWith(`${allowed}/`));
@@ -129,6 +129,11 @@ export async function writeAgentProofEvidence(root, input) {
129
129
  narutoWorkGraph
130
130
  });
131
131
  const changedFileLeaseBlockers = readOnlyNoWriteLeaseMode ? [] : agentChangedFileLeaseViolations(input.results || [], input.partition?.leases || []);
132
+ const schedulerBackfillSatisfied = !scheduler
133
+ || Number(scheduler.expected_backfill_count || 0) <= Number(scheduler.backfill_count || 0)
134
+ || (scheduler.pending_queue_drained === true
135
+ && Number(scheduler.active_slot_count || 0) === 0
136
+ && Number(scheduler.max_observed_active_slots || 0) >= Number(scheduler.target_active_slots || 0));
132
137
  const blockers = [
133
138
  ...(lifecycle.ok ? [] : ['agent_lifecycle_not_all_closed']),
134
139
  ...(lifecycle.ok ? [] : lifecycle.open_sessions.map((id) => 'session_open:' + id)),
@@ -144,7 +149,7 @@ export async function writeAgentProofEvidence(root, input) {
144
149
  ...(scheduler && scheduler.pending_count > 0 && scheduler.active_slot_count === 0 ? ['scheduler_pending_queue_without_active_sessions'] : []),
145
150
  ...(scheduler && scheduler.pending_queue_drained !== true ? ['scheduler_pending_queue_not_drained'] : []),
146
151
  ...(scheduler && Number(scheduler.active_slot_count || 0) !== 0 ? ['scheduler_active_slots_not_zero_at_finalization'] : []),
147
- ...(scheduler && Number(scheduler.expected_backfill_count || 0) > Number(scheduler.backfill_count || 0) ? ['scheduler_backfill_count_below_expected'] : []),
152
+ ...(schedulerBackfillSatisfied ? [] : ['scheduler_backfill_count_below_expected']),
148
153
  ...(scheduler && Number(scheduler.total_work_items || 0) >= Number(scheduler.target_active_slots || 0) && Number(scheduler.max_observed_active_slots || 0) !== Number(scheduler.target_active_slots || 0) ? ['scheduler_max_observed_active_slots_mismatch'] : []),
149
154
  ...(taskGraph && !taskGraphMatchesCliOptions ? ['task_graph_cli_options_mismatch'] : []),
150
155
  ...(workQueue && taskGraph && !workQueueMatchesTaskGraph ? ['work_queue_task_graph_mismatch'] : []),
@@ -23,6 +23,10 @@ export async function runFakeAgent(agent, slice, opts = {}) {
23
23
  unverified: ['fake backend does not prove real parallel execution'],
24
24
  writes: [],
25
25
  ...(patchEnvelopes.length ? { patch_envelopes: patchEnvelopes } : {}),
26
+ ...(isBugfixSlice(slice) && patchEnvelopes.length ? { regression_proof: fixtureRegressionProof(slice) } : {}),
27
+ ...(isRepairSlice(slice) && patchEnvelopes.length ? { repair_hypothesis: fixtureRepairHypothesis(slice) } : {}),
28
+ ...(slice?.work_item_kind ? { work_item_kind: String(slice.work_item_kind) } : {}),
29
+ ...(slice?.tournament_group_id ? { tournament: fixtureTournament(slice) } : {}),
26
30
  source_intelligence_refs: agent.source_intelligence_refs || null,
27
31
  goal_mode_ref: agent.goal_mode_ref || null,
28
32
  ...(opts.emitFollowUpWorkItems ? { follow_up_work_items: [buildFixtureFollowUp(agent, slice)] } : {}),
@@ -94,10 +98,46 @@ export function buildFixturePatchEnvelopes(agent, slice, opts = {}) {
94
98
  path: file,
95
99
  content: `patched by ${String(agent.id)} for ${String(slice?.id || 'fixture')}\n`
96
100
  }],
101
+ ...(isBugfixSlice(slice) ? { regression_proof: fixtureRegressionProof(slice) } : {}),
102
+ ...(isRepairSlice(slice) ? { repair_hypothesis: fixtureRepairHypothesis(slice) } : {}),
103
+ ...(slice?.tournament_group_id ? { tournament: fixtureTournament(slice) } : {}),
97
104
  rationale: 'Fixture patch envelope emitted by fake backend for a leased write task.',
98
105
  verification_hint: { node_id: verificationNodeId, expected_status: 'applied_hashes_recorded' },
99
106
  rollback_hint: { node_id: rollbackNodeId, strategy: 'restore content_before or delete newly created file' }
100
107
  };
101
108
  });
102
109
  }
110
+ function isBugfixSlice(slice) {
111
+ const text = `${String(slice?.work_item_kind || '')} ${String(slice?.title || '')}`.toLowerCase();
112
+ return /\b(bugfix|fix|bug|regression|broken|failure|crash|error)\b|버그|회귀/.test(text);
113
+ }
114
+ function isRepairSlice(slice) {
115
+ const text = `${String(slice?.work_item_kind || '')} ${String(slice?.title || '')}`.toLowerCase();
116
+ return /\b(conflict_resolution|repair|conflict|rebase|rollback)\b|수리|충돌/.test(text);
117
+ }
118
+ function fixtureRegressionProof(slice) {
119
+ return {
120
+ test_file: String(slice?.target_paths?.[0] || slice?.write_paths?.[0] || 'fixture.test.js'),
121
+ failed_before: true,
122
+ passed_after: true,
123
+ output_digest: 'fixture-regression-proof'
124
+ };
125
+ }
126
+ function fixtureRepairHypothesis(slice) {
127
+ return {
128
+ failure: 'fixture repair target',
129
+ hypotheses: [{ cause: 'fixture conflict', evidence_for: 'simulated failed worker', evidence_against: 'none' }],
130
+ chosen: 'fixture conflict',
131
+ minimal_probe: String(slice?.id || 'fixture')
132
+ };
133
+ }
134
+ function fixtureTournament(slice) {
135
+ return {
136
+ schema: 'sks.solution-tournament-candidate.v1',
137
+ group_id: String(slice.tournament_group_id),
138
+ candidate_index: Number(slice.tournament_candidate_index || 1),
139
+ candidate_count: Number(slice.tournament_candidate_count || 1),
140
+ approach: String(slice.approach_directive || '')
141
+ };
142
+ }
103
143
  //# sourceMappingURL=agent-runner-fake.js.map
@@ -27,6 +27,7 @@ export function validateAgentWorkerResult(result) {
27
27
  session_id: String(result?.session_id || 'unknown'),
28
28
  persona_id: String(result?.persona_id || result?.agent_id || 'unknown'),
29
29
  task_slice_id: String(result?.task_slice_id || 'unknown'),
30
+ ...(result?.work_item_kind === undefined ? {} : { work_item_kind: String(result.work_item_kind) }),
30
31
  status: guard.ok ? (result?.status === undefined ? 'done' : String(result.status)) : 'blocked',
31
32
  backend: result?.backend || 'fake',
32
33
  summary: String(result?.summary || ''),
@@ -52,6 +53,10 @@ export function validateAgentWorkerResult(result) {
52
53
  ...(result?.model_authored_patch_envelopes === undefined ? {} : { model_authored_patch_envelopes: Boolean(result.model_authored_patch_envelopes) }),
53
54
  ...(result?.fixture_patch_envelopes === undefined ? {} : { fixture_patch_envelopes: Boolean(result.fixture_patch_envelopes) }),
54
55
  ...(result?.no_patch_reason === undefined ? {} : { no_patch_reason: result.no_patch_reason }),
56
+ ...(result?.machine_feedback === undefined ? {} : { machine_feedback: result.machine_feedback }),
57
+ ...(result?.regression_proof === undefined ? {} : { regression_proof: result.regression_proof }),
58
+ ...(result?.repair_hypothesis === undefined ? {} : { repair_hypothesis: result.repair_hypothesis }),
59
+ ...(result?.tournament === undefined ? {} : { tournament: result.tournament }),
55
60
  ...(result?.source_intelligence_refs === undefined ? {} : { source_intelligence_refs: result.source_intelligence_refs }),
56
61
  ...(result?.goal_mode_ref === undefined ? {} : { goal_mode_ref: result.goal_mode_ref }),
57
62
  ...(result?.follow_up_work_items === undefined ? {} : { follow_up_work_items: followUps.accepted }),
@@ -69,6 +74,12 @@ export function validateAgentWorkerResult(result) {
69
74
  normalized.blockers.push(...patchEnvelopeValidation.blockers.map((issue) => 'patch_envelope_invalid:' + issue));
70
75
  normalized.verification = { status: 'failed', checks: [...normalized.verification.checks, 'agent-patch-envelope-schema'] };
71
76
  }
77
+ const protocolBlockers = qualityProtocolBlockers(normalized);
78
+ if (protocolBlockers.length) {
79
+ normalized.status = 'blocked';
80
+ normalized.blockers.push(...protocolBlockers);
81
+ normalized.verification = { status: 'failed', checks: [...normalized.verification.checks, 'agent-worker-quality-protocol'] };
82
+ }
72
83
  const readOnlyOrNoopWithoutPatch = acceptsNoPatchReadOnlyOrNoop(result?.no_patch_reason);
73
84
  if (patchEnvelopeValidation.envelopes.length === 0 && (normalized.writes.length > 0 || (!readOnlyOrNoopWithoutPatch && normalized.changed_files.length > 0))) {
74
85
  normalized.status = 'blocked';
@@ -83,6 +94,24 @@ export function validateAgentWorkerResult(result) {
83
94
  }
84
95
  return normalized;
85
96
  }
97
+ function qualityProtocolBlockers(result) {
98
+ const writesPatch = result.writes.length > 0 || result.changed_files.length > 0 || Boolean(result.patch_envelopes?.length);
99
+ if (!writesPatch)
100
+ return [];
101
+ const kind = String(result.work_item_kind || result.naruto_runtime?.work_item_kind || '').toLowerCase();
102
+ const text = [kind, result.task_slice_id].join(' ').toLowerCase();
103
+ const proof = result.regression_proof || result.patch_envelopes?.find((envelope) => envelope.regression_proof)?.regression_proof || null;
104
+ const repair = result.repair_hypothesis || result.patch_envelopes?.find((envelope) => envelope.repair_hypothesis)?.repair_hypothesis || null;
105
+ const blockers = [];
106
+ if ((kind === 'bugfix' || /\b(fix|bug|regression|broken|failure|crash|error)\b|버그|회귀/.test(text)) && !validRegressionProof(proof))
107
+ blockers.push('tdd_evidence_missing');
108
+ if ((kind === 'conflict_resolution' || /\b(repair|conflict|rebase|rollback)\b|수리|충돌/.test(text)) && !repair)
109
+ blockers.push('repair_without_hypothesis');
110
+ return blockers;
111
+ }
112
+ function validRegressionProof(proof) {
113
+ return Boolean(proof && proof.failed_before === true && proof.passed_after === true && String(proof.test_file || '').trim());
114
+ }
86
115
  export function agentWorkerPipelineContract() {
87
116
  return {
88
117
  schema: 'sks.agent-worker-pipeline.v1',
@@ -97,7 +126,7 @@ export function agentWorkerPipelineContract() {
97
126
  required_for_write_tasks: true,
98
127
  envelope_schema: 'sks.agent-patch-envelope.v1',
99
128
  metadata: ['agent_id', 'session_id', 'slot_id', 'generation_index', 'lease_id_or_lease_proof'],
100
- optional_hints: ['rationale', 'verification_hint', 'rollback_hint']
129
+ optional_hints: ['rationale', 'verification_hint', 'rollback_hint', 'cochange_acknowledged_reason', 'regression_proof', 'repair_hypothesis']
101
130
  }
102
131
  };
103
132
  }
@@ -111,7 +140,12 @@ function normalizePatchEnvelopes(value) {
111
140
  ...(raw?.generation_index === undefined ? {} : { generation_index: Number(raw.generation_index) }),
112
141
  ...(raw?.task_slice_id === undefined ? {} : { task_slice_id: String(raw.task_slice_id) }),
113
142
  ...(raw?.verification_hint === undefined ? {} : { verification_hint: raw.verification_hint }),
114
- ...(raw?.rollback_hint === undefined ? {} : { rollback_hint: raw.rollback_hint })
143
+ ...(raw?.rollback_hint === undefined ? {} : { rollback_hint: raw.rollback_hint }),
144
+ ...(raw?.cochange_acknowledged === undefined ? {} : { cochange_acknowledged: Boolean(raw.cochange_acknowledged) }),
145
+ ...(raw?.cochange_acknowledged_reason === undefined ? {} : { cochange_acknowledged_reason: String(raw.cochange_acknowledged_reason) }),
146
+ ...(raw?.regression_proof === undefined ? {} : { regression_proof: raw.regression_proof }),
147
+ ...(raw?.repair_hypothesis === undefined ? {} : { repair_hypothesis: raw.repair_hypothesis }),
148
+ ...(raw?.tournament === undefined ? {} : { tournament: raw.tournament })
115
149
  })) : [];
116
150
  const blockers = envelopes.flatMap((envelope, index) => {
117
151
  const validation = validateAgentPatchEnvelope(envelope);
@@ -112,6 +112,8 @@ function buildWorkerPrompt(slice) {
112
112
  `Write-capable slice. write_paths=${JSON.stringify(writePaths)}.`,
113
113
  'Return at least one patch_envelopes item with source "model_authored".',
114
114
  `Use a write operation for ${JSON.stringify(writePaths[0])}, allowed_paths equal to write_paths, lease_proof.protected_path_check "passed", and non-empty verification_hint and rollback_hint.`,
115
+ 'Impact-scan, machine-feedback, diff-quality, and compiled mistake rules run before queue acceptance; exported signature changes must include cochanged callers or a concrete cochange_acknowledged_reason.',
116
+ 'For bugfix work, add a regression test first and include regression_proof with failed_before true and passed_after true. For repair work, include repair_hypothesis before patching.',
115
117
  'For patch envelope runtime ids you cannot know yet, use numeric 0 or empty strings; SKS will bind actual worker and Codex child process ids from the process report.',
116
118
  'Set changed_files and writes consistently with the patch envelope operation.'
117
119
  ].join('\n')
@@ -10,6 +10,8 @@ import { normalizeAgentPatchEnvelope } from './agent-patch-schema.js';
10
10
  import { runCodexTask } from '../codex-control/codex-control-plane.js';
11
11
  import { CODEX_AGENT_WORKER_RESULT_SCHEMA_ID, codexAgentWorkerResultSchema } from '../codex-control/schemas/agent-worker-result.schema.js';
12
12
  import { leanEngineeringCompactText, leanPolicyReference } from '../lean-engineering-policy.js';
13
+ import { readLbHealth } from '../codex-lb/codex-lb-env.js';
14
+ import { categoryForWorkerRole, modelRouteReason, routeModel } from '../provider/model-router.js';
13
15
  export const NATIVE_WORKER_BACKEND_ROUTER_SCHEMA = 'sks.native-worker-backend-router.v1';
14
16
  export async function runNativeWorkerBackendRouter(input) {
15
17
  const root = path.resolve(input.agentRoot);
@@ -23,6 +25,7 @@ export async function runNativeWorkerBackendRouter(input) {
23
25
  let patchEnvelopes = [];
24
26
  let proofLevel = 'blocked';
25
27
  let outputLastMessagePath = null;
28
+ let modelRouting = null;
26
29
  if (!input.guard?.ok) {
27
30
  result = validateAgentWorkerResult(blockedResult(input, ['native_cli_worker_recursion_guard_missing']));
28
31
  }
@@ -91,6 +94,7 @@ export async function runNativeWorkerBackendRouter(input) {
91
94
  }
92
95
  else if (backend === 'codex-sdk' || backend === 'zellij' || backend === 'local-llm') {
93
96
  const localPreferred = backend === 'local-llm';
97
+ modelRouting = await resolveWorkerModelRouting(input);
94
98
  const sdkTask = await runCodexTask({
95
99
  route: String(input.intake.route || '$Agent'),
96
100
  tier: 'worker',
@@ -101,6 +105,10 @@ export async function runNativeWorkerBackendRouter(input) {
101
105
  sessionId: String(input.agent.session_id || ''),
102
106
  cwd: String(input.intake.cwd || root),
103
107
  prompt: buildWorkerPrompt(input.slice),
108
+ model: modelRouting.choice.model,
109
+ reasoningEffort: modelRouting.choice.reasoning,
110
+ modelReasoningEffort: modelRouting.choice.reasoning,
111
+ serviceTier: modelRouting.choice.serviceTier,
104
112
  inputFiles: input.intake.input_files || [],
105
113
  inputImages: input.intake.input_images || [],
106
114
  outputSchemaId: CODEX_AGENT_WORKER_RESULT_SCHEMA_ID,
@@ -112,6 +120,8 @@ export async function runNativeWorkerBackendRouter(input) {
112
120
  read_only: !hasWriteLease(input.slice, input.intake),
113
121
  allowed_paths: writePaths(input.slice, input.intake),
114
122
  write_paths: writePaths(input.slice, input.intake),
123
+ model_route_reason: modelRouting.reason,
124
+ service_tier: modelRouting.choice.serviceTier,
115
125
  user_confirmed_full_access: false,
116
126
  mad_sks_authorized: input.intake.mad_sks_authorized === true || process.env.SKS_MAD_SKS_ACTIVE === '1'
117
127
  },
@@ -143,6 +153,10 @@ export async function runNativeWorkerBackendRouter(input) {
143
153
  structured_output_valid: sdkTask.structuredOutputValid,
144
154
  worker_result_path: sdkTask.workerResultPath,
145
155
  patch_envelope_path: sdkTask.patchEnvelopePath || null,
156
+ model: modelRouting.choice.model,
157
+ model_reasoning_effort: modelRouting.choice.reasoning,
158
+ service_tier: modelRouting.choice.serviceTier,
159
+ model_route_reason: modelRouting.reason,
146
160
  blockers: sdkTask.blockers
147
161
  };
148
162
  childReports = [sdkReport];
@@ -219,7 +233,11 @@ export async function runNativeWorkerBackendRouter(input) {
219
233
  proof_level: proofLevel,
220
234
  lean_engineering_policy: leanPolicyReference(),
221
235
  fast_mode: input.fastModePolicy.fast_mode,
222
- service_tier: input.fastModePolicy.service_tier,
236
+ service_tier: modelRouting?.choice.serviceTier || input.fastModePolicy.service_tier,
237
+ model: modelRouting?.choice.model || input.agent.model || null,
238
+ model_reasoning_effort: modelRouting?.choice.reasoning || input.agent.model_reasoning_effort || null,
239
+ model_route_reason: modelRouting?.reason || null,
240
+ model_route_category: modelRouting?.category || null,
223
241
  sdk_thread_id: childReports.find((report) => report?.sdk_thread_id)?.sdk_thread_id || null,
224
242
  sdk_run_id: childReports.find((report) => report?.sdk_run_id)?.sdk_run_id || null,
225
243
  stream_event_count: Number(childReports.find((report) => report?.stream_event_count)?.stream_event_count || 0),
@@ -239,6 +257,39 @@ export async function runNativeWorkerBackendRouter(input) {
239
257
  patchEnvelopes
240
258
  };
241
259
  }
260
+ async function resolveWorkerModelRouting(input) {
261
+ const category = categoryForWorkerRole(String(input.agent?.role || input.slice?.role || input.slice?.type || input.agent?.persona_id || 'executor'));
262
+ const lbHealth = await readLbHealth().catch(() => null);
263
+ const explicitModel = String(process.env.SKS_WORKER_MODEL || process.env.SKS_AGENT_MODEL || '').trim();
264
+ const explicitReasoning = normalizeModelReasoning(process.env.SKS_WORKER_REASONING || process.env.SKS_WORKER_MODEL_REASONING || '');
265
+ const explicitTier = normalizeServiceTier(process.env.SKS_WORKER_SERVICE_TIER || process.env.SKS_SERVICE_TIER || '');
266
+ const routed = explicitModel
267
+ ? {
268
+ model: explicitModel,
269
+ reasoning: explicitReasoning || normalizeModelReasoning(input.agent?.model_reasoning_effort) || 'medium',
270
+ serviceTier: explicitTier || input.fastModePolicy.service_tier || 'fast'
271
+ }
272
+ : await routeModel(category, { lbHealth });
273
+ return {
274
+ category,
275
+ choice: routed,
276
+ explicit: Boolean(explicitModel),
277
+ lb_health: lbHealth,
278
+ reason: modelRouteReason(category, routed, {
279
+ explicit: Boolean(explicitModel),
280
+ quotaLow: lbHealth?.quota_low === true,
281
+ degraded: lbHealth?.degraded_models || []
282
+ })
283
+ };
284
+ }
285
+ function normalizeModelReasoning(value) {
286
+ const text = String(value || '').toLowerCase();
287
+ return text === 'low' || text === 'medium' || text === 'high' || text === 'xhigh' ? text : null;
288
+ }
289
+ function normalizeServiceTier(value) {
290
+ const text = String(value || '').toLowerCase();
291
+ return text === 'standard' ? 'standard' : text === 'fast' || text === 'priority' ? 'fast' : null;
292
+ }
242
293
  async function maybeAutoSelectOllamaBackend(backend, input) {
243
294
  if (backend !== 'codex-sdk')
244
295
  return backend;
@@ -286,6 +337,12 @@ function buildWorkerPrompt(slice) {
286
337
  write.length
287
338
  ? `Write-capable slice. Return JSON matching ${CODEX_AGENT_WORKER_RESULT_SCHEMA_ID}; include patch_envelopes for write_paths=${JSON.stringify(write)}.`
288
339
  : `Read-only slice. Return JSON matching ${CODEX_AGENT_WORKER_RESULT_SCHEMA_ID}; do not report pre-existing repository dirtiness as changed_files.`,
340
+ write.length
341
+ ? 'Quality gates run before queue acceptance: impact-scan requires cochanged callers for exported signature changes, machine-feedback runs type/lint/related tests, diff-quality blocks dead exports, and compiled mistake rules block repeated mistakes.'
342
+ : '',
343
+ write.length
344
+ ? 'If this is a bugfix, create a regression test first and include regression_proof with failed_before true and passed_after true. For repair work, include repair_hypothesis before patching.'
345
+ : '',
289
346
  leanEngineeringCompactText(),
290
347
  'Required JSON fields: status, summary, findings, changed_files, patch_envelopes, verification, rollback_notes, blockers.'
291
348
  ].join('\n');
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import { ensureDir, exists, PACKAGE_VERSION, readJson, readText, runProcess, sha256, which, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
6
+ import { withHeartbeat } from '../../cli/cli-theme.js';
6
7
  export const SKS_MENUBAR_LABEL = 'com.sneakoscope.sks-menubar';
7
8
  const LABEL = SKS_MENUBAR_LABEL;
8
9
  const CONTROL_CENTER_DOMAIN = 'com.apple.controlcenter';
@@ -16,6 +17,7 @@ const MENU_ITEMS = [
16
17
  'Fast Check',
17
18
  'SKS Version Check',
18
19
  'Update SKS Now',
20
+ 'Open Dashboard',
19
21
  'Open Codex Settings',
20
22
  'Restart Codex',
21
23
  'Quit SKS Menu'
@@ -208,7 +210,8 @@ export async function installSksMenuBar(opts = {}) {
208
210
  codesign,
209
211
  swiftSource,
210
212
  infoPlist,
211
- actions
213
+ actions,
214
+ quiet: opts.quiet === true
212
215
  });
213
216
  }
214
217
  catch (err) {
@@ -245,7 +248,7 @@ export async function installSksMenuBar(opts = {}) {
245
248
  warnings.push(preferredPosition.warning);
246
249
  }
247
250
  const launch = launchRequested && launchctl && !(stampMatches && runningBeforeLaunch)
248
- ? await launchWithLaunchctl({ launchctl, open, paths, skipIfRunning: stampMatches })
251
+ ? await launchWithLaunchctl({ launchctl, open, paths, skipIfRunning: stampMatches, quiet: opts.quiet === true })
249
252
  : {
250
253
  requested: launchRequested && !(stampMatches && runningBeforeLaunch),
251
254
  method: 'skipped',
@@ -724,6 +727,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
724
727
  add(menu, "SKS Version Check", #selector(sksVersionCheck))
725
728
  add(menu, "Update SKS Now", #selector(updateSksNow))
726
729
  menu.addItem(NSMenuItem.separator())
730
+ add(menu, "Open Dashboard", #selector(openDashboard))
727
731
  add(menu, "Open Codex Settings", #selector(openCodexSettings))
728
732
  add(menu, "Restart Codex", #selector(restartCodex))
729
733
  menu.addItem(NSMenuItem.separator())
@@ -844,6 +848,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
844
848
  runSksInTerminal(["update"], tail: "echo; echo 'SKS update finished.'")
845
849
  }
846
850
 
851
+ @objc func openDashboard() {
852
+ let command = "\\(shellQuote(actionScript)) ui; echo; echo 'SKS dashboard requested.'"
853
+ runInTerminal(command)
854
+ runProcess("/usr/bin/open", ["http://127.0.0.1:4477"])
855
+ }
856
+
847
857
  @objc func openCodexSettings() {
848
858
  runProcess("/usr/bin/open", ["codex://settings"])
849
859
  }
@@ -916,10 +926,11 @@ async function buildMenuBarAppAtomically(input) {
916
926
  input.actions.push(`wrote ${input.paths.source_path}`);
917
927
  await writeTextAtomic(path.join(input.paths.staging_app_path, 'Contents', 'Info.plist'), input.infoPlist);
918
928
  const stagingExecutable = path.join(input.paths.staging_app_path, 'Contents', 'MacOS', 'SKSMenuBar');
919
- const compile = await runProcess(input.swiftc, ['-framework', 'Cocoa', input.paths.source_path, '-o', stagingExecutable], {
929
+ const compileWork = runProcess(input.swiftc, ['-framework', 'Cocoa', input.paths.source_path, '-o', stagingExecutable], {
920
930
  timeoutMs: 60_000,
921
931
  maxOutputBytes: 64 * 1024
922
932
  }).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
933
+ const compile = input.quiet === true ? await compileWork : await withHeartbeat('swiftc SKS menu bar', compileWork, { warnAfterMs: 30_000 });
923
934
  if (compile.code !== 0) {
924
935
  throw new MenuBarBuildError('swift_compile_failed', String(compile.stderr || compile.stdout || '').trim());
925
936
  }
@@ -956,7 +967,8 @@ async function launchWithLaunchctl(input) {
956
967
  stdoutFile: path.join(input.paths.install_dir, 'launchctl.out.log'),
957
968
  stderrFile: path.join(input.paths.install_dir, 'launchctl.err.log')
958
969
  };
959
- const already = await waitForLaunchctlRunning(input.launchctl, service);
970
+ const alreadyWork = waitForLaunchctlRunning(input.launchctl, service);
971
+ const already = input.quiet === true ? await alreadyWork : await withHeartbeat('launchctl SKS menu bar wait', alreadyWork, { warnAfterMs: 10_000 });
960
972
  if (input.skipIfRunning && already.running) {
961
973
  return { requested: true, method: 'launchctl', ok: true, print_code: already.code, error: null };
962
974
  }
@@ -975,7 +987,8 @@ async function launchWithLaunchctl(input) {
975
987
  ...stdio
976
988
  }).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
977
989
  if (kickstart.code !== 0) {
978
- const printed = await waitForLaunchctlRunning(input.launchctl, service);
990
+ const printedWork = waitForLaunchctlRunning(input.launchctl, service);
991
+ const printed = input.quiet === true ? await printedWork : await withHeartbeat('launchctl SKS menu bar wait', printedWork, { warnAfterMs: 10_000 });
979
992
  if (printed.running) {
980
993
  return {
981
994
  requested: true,
@@ -582,6 +582,7 @@ export function codexAppGuidance({ appInstalled, codex, mcpList, featureList, re
582
582
  }
583
583
  else if (appInstalled || codex?.bin) {
584
584
  lines.push('Codex image_generation was not visible from `codex features list`. Required imagegen/gpt-image-2 evidence must stay blocked or unverified until $imagegen is available in Codex App.');
585
+ lines.push('Run: sks doctor --fix to attempt Codex CLI/App image_generation repair, then rerun the blocked visual route.');
585
586
  }
586
587
  if (computerUseReady && !computerUseMcpListed) {
587
588
  lines.push('Computer Use plugin files are installed, but this check cannot prove the current thread exposes the live Computer Use tools. Start a new Codex App thread and invoke @Computer or @AppName only for native Mac/non-web target apps or screens; web/browser/webapp verification must use the Chrome Extension gate.');
@@ -1,8 +1,9 @@
1
1
  export function buildCodexSdkConfig(input) {
2
2
  const model = String(input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL || 'gpt-5.5');
3
+ const serviceTier = String(input.serviceTier || process.env.SKS_SERVICE_TIER || 'fast');
3
4
  const config = {
4
5
  model,
5
- service_tier: 'fast',
6
+ service_tier: serviceTier === 'standard' ? 'standard' : 'fast',
6
7
  model_reasoning_effort: String(input.modelReasoningEffort || input.reasoningEffort || process.env.SKS_CODEX_REASONING || process.env.CODEX_MODEL_REASONING_EFFORT || 'medium'),
7
8
  mcp_servers: {},
8
9
  sks: {
@@ -30,7 +30,7 @@ export function buildCodexSdkEnv(input) {
30
30
  env.SKS_AGENT_SESSION_ID = input.sessionId;
31
31
  if (input.generationIndex !== undefined)
32
32
  env.SKS_AGENT_GENERATION_INDEX = String(input.generationIndex);
33
- env.SKS_SERVICE_TIER = 'fast';
33
+ env.SKS_SERVICE_TIER = String(input.serviceTier || 'fast');
34
34
  const isolatedRoot = path.resolve(input.mutationLedgerRoot, 'codex-sdk-home');
35
35
  env.HOME = path.join(isolatedRoot, 'home');
36
36
  env.CODEX_HOME = path.join(isolatedRoot, 'codex');
@@ -3,7 +3,7 @@ const patchOperationSchema = {
3
3
  type: 'object',
4
4
  required: ['op', 'path', 'search', 'replace', 'content', 'diff'],
5
5
  properties: {
6
- op: { type: 'string', enum: ['replace', 'write', 'unified_diff'] },
6
+ op: { type: 'string', enum: ['replace', 'write', 'unified_diff', 'git_apply_patch'] },
7
7
  path: { type: 'string' },
8
8
  search: { type: 'string' },
9
9
  replace: { type: 'string' },
@@ -38,7 +38,12 @@ const patchEnvelopeSchema = {
38
38
  lease_id: { type: 'string' },
39
39
  allowed_paths: { type: 'array', items: { type: 'string' } },
40
40
  operations: { type: 'array', items: patchOperationSchema },
41
- rationale: { type: 'string' }
41
+ rationale: { type: 'string' },
42
+ cochange_acknowledged: { type: 'boolean' },
43
+ cochange_acknowledged_reason: { type: 'string' },
44
+ regression_proof: { type: 'object', additionalProperties: true },
45
+ repair_hypothesis: { type: 'object', additionalProperties: true },
46
+ tournament: { type: 'object', additionalProperties: true }
42
47
  },
43
48
  additionalProperties: false
44
49
  };
@@ -70,7 +75,11 @@ export const codexAgentWorkerResultSchema = {
70
75
  additionalProperties: false
71
76
  },
72
77
  rollback_notes: { type: 'array', items: { type: 'string' } },
73
- blockers: { type: 'array', items: { type: 'string' } }
78
+ blockers: { type: 'array', items: { type: 'string' } },
79
+ work_item_kind: { type: 'string' },
80
+ regression_proof: { type: 'object', additionalProperties: true },
81
+ repair_hypothesis: { type: 'object', additionalProperties: true },
82
+ tournament: { type: 'object', additionalProperties: true }
74
83
  },
75
84
  additionalProperties: false
76
85
  };