sneakoscope 4.0.13 → 4.0.14

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 (101) hide show
  1. package/README.md +10 -2
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/bin/sks.js +1 -1
  6. package/dist/cli/global-mode-router.js +2 -1
  7. package/dist/core/commands/mad-sks-command.js +3 -0
  8. package/dist/core/fsx.js +1 -1
  9. package/dist/core/providers/glm/bench/glm-bench-model-lock-proof.js +32 -3
  10. package/dist/core/providers/glm/bench/glm-benchmark-runner.js +29 -5
  11. package/dist/core/providers/glm/bench/glm-benchmark-types.js +1 -1
  12. package/dist/core/providers/glm/naruto/glm-naruto-critical-path.js +51 -0
  13. package/dist/core/providers/glm/naruto/glm-naruto-final-seal.js +9 -2
  14. package/dist/core/providers/glm/naruto/glm-naruto-orchestrator.js +101 -15
  15. package/dist/core/providers/glm/naruto/glm-naruto-parallelism-summary.js +55 -0
  16. package/dist/core/providers/glm/naruto/glm-naruto-requirement-coverage.js +92 -0
  17. package/dist/core/providers/glm/naruto/glm-naruto-requirement-ledger.js +42 -0
  18. package/dist/core/providers/glm/naruto/glm-naruto-stage-scheduler.js +85 -0
  19. package/dist/core/providers/glm/naruto/glm-naruto-task-size-classifier.js +12 -0
  20. package/dist/core/providers/glm/naruto/glm-naruto-trace.js +4 -0
  21. package/dist/core/providers/glm/naruto/glm-naruto-verifier-output.js +5 -0
  22. package/dist/core/providers/glm/naruto/glm-naruto-worker-pool.js +130 -44
  23. package/dist/core/providers/glm/naruto/glm-naruto-worker-runtime.js +6 -2
  24. package/dist/core/routes/model-mode-router.js +44 -0
  25. package/dist/core/version.js +1 -1
  26. package/package.json +24 -1
  27. package/dist/scripts/agent-dynamic-pool-fixture.js +0 -80
  28. package/dist/scripts/agent-native-release-gate.js +0 -274
  29. package/dist/scripts/agent-patch-swarm-gate-lib.js +0 -113
  30. package/dist/scripts/agent-real-codex-patch-envelope-smoke.js +0 -126
  31. package/dist/scripts/agent-route-blackbox-lib.js +0 -132
  32. package/dist/scripts/blackbox-command-import-smoke.js +0 -143
  33. package/dist/scripts/blackbox-global-shim.js +0 -77
  34. package/dist/scripts/blackbox-matrix.js +0 -70
  35. package/dist/scripts/blackbox-npx-one-shot.js +0 -69
  36. package/dist/scripts/blackbox-pack-install.js +0 -174
  37. package/dist/scripts/build-dist.js +0 -64
  38. package/dist/scripts/check-architecture.js +0 -135
  39. package/dist/scripts/check-cli-entrypoint.js +0 -43
  40. package/dist/scripts/check-command-module-budget.js +0 -25
  41. package/dist/scripts/check-dist-runtime.js +0 -100
  42. package/dist/scripts/check-feature-quality.js +0 -53
  43. package/dist/scripts/check-legacy-free.js +0 -66
  44. package/dist/scripts/check-package-boundary.js +0 -108
  45. package/dist/scripts/check-pipeline-budget.js +0 -69
  46. package/dist/scripts/check-pipeline-runtime.js +0 -25
  47. package/dist/scripts/check-publish-tag.js +0 -30
  48. package/dist/scripts/check-route-modularity.js +0 -82
  49. package/dist/scripts/check-runtime-schemas.js +0 -87
  50. package/dist/scripts/check-source-runtime.js +0 -4
  51. package/dist/scripts/check-ts-contracts.js +0 -69
  52. package/dist/scripts/check-ts-suppressions.js +0 -58
  53. package/dist/scripts/clean-dist.js +0 -8
  54. package/dist/scripts/codex-0140-feature-gate-lib.js +0 -14
  55. package/dist/scripts/codex-config-eperm-fixture.js +0 -32
  56. package/dist/scripts/codex-lb-missing-env-regression.js +0 -40
  57. package/dist/scripts/codex-native-runtime-e2e-fixture.js +0 -75
  58. package/dist/scripts/codex-project-config-policy-merge-regression.js +0 -92
  59. package/dist/scripts/core-skill-legacy-promotion-api-audit.js +0 -54
  60. package/dist/scripts/ensure-bin-executable.js +0 -10
  61. package/dist/scripts/fixtures/fake-codex-config-loader.js +0 -51
  62. package/dist/scripts/github-release-body-helper.js +0 -65
  63. package/dist/scripts/gpt-image-2-real-file-smoke.js +0 -448
  64. package/dist/scripts/hooks-no-unsupported-handlers.js +0 -15
  65. package/dist/scripts/hooks-runtime-replay-warning-zero-v2.js +0 -26
  66. package/dist/scripts/hooks-runtime-replay-warning-zero.js +0 -10
  67. package/dist/scripts/hooks-trust-warning-zero.js +0 -14
  68. package/dist/scripts/lib/codex-sdk-gate-lib.js +0 -92
  69. package/dist/scripts/lib/ensure-dist-fresh.js +0 -142
  70. package/dist/scripts/lib/git-worktree-fixture.js +0 -33
  71. package/dist/scripts/lib/mad-sks-actual-executor-check-lib.js +0 -255
  72. package/dist/scripts/lib/native-cli-session-swarm-check-lib.js +0 -79
  73. package/dist/scripts/lib/real-codex-parallel-gate.js +0 -94
  74. package/dist/scripts/lib/real-codex-parallel-proof-fixture.js +0 -55
  75. package/dist/scripts/lib/valid-png-fixture.js +0 -25
  76. package/dist/scripts/mad-sks-live-protected-core-smoke.js +0 -5
  77. package/dist/scripts/naruto-real-local-gpt-final-smoke.js +0 -25
  78. package/dist/scripts/perf-gate.js +0 -39
  79. package/dist/scripts/prepublish-release-check-or-fast.js +0 -121
  80. package/dist/scripts/release-3112-required-gates.js +0 -30
  81. package/dist/scripts/release-3113-required-gates.js +0 -25
  82. package/dist/scripts/release-4000-required-gates.js +0 -36
  83. package/dist/scripts/release-4001-required-gates.js +0 -13
  84. package/dist/scripts/release-4002-required-gates.js +0 -14
  85. package/dist/scripts/release-check-dynamic-execute.js +0 -259
  86. package/dist/scripts/release-check-dynamic.js +0 -107
  87. package/dist/scripts/release-check-stamp.js +0 -261
  88. package/dist/scripts/release-gate-dag-runner.js +0 -56
  89. package/dist/scripts/release-gate-existence-audit.js +0 -111
  90. package/dist/scripts/release-gate-planner.js +0 -34
  91. package/dist/scripts/release-gate-worker.js +0 -10
  92. package/dist/scripts/release-speed-summary.js +0 -67
  93. package/dist/scripts/repo-audit.js +0 -83
  94. package/dist/scripts/rust-smoke.js +0 -5
  95. package/dist/scripts/sizecheck.js +0 -146
  96. package/dist/scripts/sks-1-11-gate-lib.js +0 -78
  97. package/dist/scripts/sks-1-18-gate-lib.js +0 -55
  98. package/dist/scripts/tmux-removal-inventory.js +0 -36
  99. package/dist/scripts/write-build-manifest.js +0 -71
  100. package/dist/scripts/zellij-dashboard-watch.js +0 -41
  101. package/dist/scripts/zellij-right-column-geometry-proof.js +0 -162
@@ -0,0 +1,92 @@
1
+ export function enrichGlmNarutoCandidateRequirementCoverage(input) {
2
+ const coverage = inferCandidateRequirementCoverage(input);
3
+ return {
4
+ ...input.envelope,
5
+ requirements_satisfied: coverage.requirements_satisfied,
6
+ requirements_risk: coverage.requirements_risk,
7
+ assumptions: coverage.assumptions
8
+ };
9
+ }
10
+ export function inferCandidateRequirementCoverage(input) {
11
+ const satisfied = [];
12
+ const risk = [];
13
+ const missing = [];
14
+ const assumptions = [];
15
+ const touched = new Set(input.envelope.target_paths);
16
+ const patch = input.envelope.patch.toLowerCase();
17
+ for (const requirement of input.ledger.requirements) {
18
+ const relatedPaths = extractPaths(requirement.text);
19
+ const pathCovered = relatedPaths.some((file) => touched.has(file) || patch.includes(file.toLowerCase()));
20
+ const lower = requirement.text.toLowerCase();
21
+ const preservationClause = /\b(preserve|do not|don't|without|never|no fallback|no fake|보존|금지|없이)\b/.test(lower);
22
+ const onlyClause = /\bonly\b|만\b/.test(lower);
23
+ if (relatedPaths.length > 0 && pathCovered && (!onlyClause || input.envelope.target_paths.every((file) => relatedPaths.includes(file)))) {
24
+ satisfied.push(requirement.id);
25
+ continue;
26
+ }
27
+ if (onlyClause && relatedPaths.length > 0 && input.envelope.target_paths.some((file) => !relatedPaths.includes(file))) {
28
+ risk.push(requirement.id);
29
+ missing.push(requirement.id);
30
+ continue;
31
+ }
32
+ if (preservationClause) {
33
+ risk.push(requirement.id);
34
+ missing.push(requirement.id);
35
+ assumptions.push(`manual_preservation_evidence_required:${requirement.id}`);
36
+ continue;
37
+ }
38
+ if (input.envelope.patch.trim()) {
39
+ satisfied.push(requirement.id);
40
+ }
41
+ else {
42
+ missing.push(requirement.id);
43
+ }
44
+ }
45
+ return {
46
+ schema: 'sks.glm-naruto-candidate-requirement-coverage.v1',
47
+ mission_id: input.envelope.mission_id,
48
+ worker_id: input.envelope.worker_id,
49
+ patch_id: input.envelope.patch_sha256,
50
+ requirements_satisfied: [...new Set(satisfied)],
51
+ requirements_risk: [...new Set(risk)],
52
+ requirements_missing: [...new Set(missing)],
53
+ assumptions: [...new Set(assumptions)]
54
+ };
55
+ }
56
+ export function buildGlmNarutoRequirementCoverageSummary(input) {
57
+ const selected = input.selectedPatchIds.length
58
+ ? input.envelopes.filter((env) => input.selectedPatchIds.includes(env.worker_id))
59
+ : input.envelopes;
60
+ const rows = input.ledger.requirements.map((requirement) => {
61
+ const satisfiedBy = selected
62
+ .filter((env) => env.requirements_satisfied?.includes(requirement.id))
63
+ .map((env) => env.worker_id);
64
+ const riskBy = selected
65
+ .filter((env) => env.requirements_risk?.includes(requirement.id))
66
+ .map((env) => env.worker_id);
67
+ const covered = satisfiedBy.length > 0 && riskBy.length === 0;
68
+ return {
69
+ requirement_id: requirement.id,
70
+ required: requirement.required,
71
+ covered,
72
+ satisfied_by: satisfiedBy,
73
+ risk_by: riskBy
74
+ };
75
+ });
76
+ const uncovered = rows
77
+ .filter((row) => row.required && !row.covered)
78
+ .map((row) => row.requirement_id);
79
+ return {
80
+ schema: 'sks.glm-naruto-requirement-coverage-summary.v1',
81
+ mission_id: input.missionId,
82
+ required_total: input.ledger.requirements.filter((req) => req.required).length,
83
+ required_covered: rows.filter((row) => row.required && row.covered).length,
84
+ uncovered_required_requirements: uncovered,
85
+ passed: uncovered.length === 0,
86
+ requirements: rows
87
+ };
88
+ }
89
+ function extractPaths(text) {
90
+ return [...new Set(text.match(/[A-Za-z0-9_.-]+\/[A-Za-z0-9_./-]+\.[A-Za-z0-9]+/g) ?? [])];
91
+ }
92
+ //# sourceMappingURL=glm-naruto-requirement-coverage.js.map
@@ -0,0 +1,42 @@
1
+ export function buildGlmNarutoRequirementLedger(input) {
2
+ const requirements = [];
3
+ const seen = new Set();
4
+ const add = (text, source, required = true) => {
5
+ const clean = text.replace(/\s+/g, ' ').trim();
6
+ if (!clean || seen.has(`${source}:${clean.toLowerCase()}`))
7
+ return;
8
+ seen.add(`${source}:${clean.toLowerCase()}`);
9
+ requirements.push({
10
+ id: `REQ-${String(requirements.length + 1).padStart(3, '0')}`,
11
+ text: clean,
12
+ source,
13
+ required
14
+ });
15
+ };
16
+ for (const clause of splitRequirementClauses(input.task)) {
17
+ const lower = clause.toLowerCase();
18
+ if (/\b(must|without|do not|don't|preserve|only|never|no fallback|no fake|금지|필수|보존|없이|만)\b/.test(lower)) {
19
+ add(clause, 'user_task', true);
20
+ }
21
+ }
22
+ for (const file of input.mentionedPaths ?? []) {
23
+ add(`Touch or preserve mentioned path: ${file}`, 'user_task', true);
24
+ }
25
+ if (input.gitStatus && input.gitStatus.trim()) {
26
+ add('Preserve pre-existing dirty worktree changes unless explicitly selected.', 'git_status', true);
27
+ }
28
+ if (requirements.length === 0)
29
+ add(input.task, 'user_task', true);
30
+ return {
31
+ schema: 'sks.glm-naruto-requirement-ledger.v1',
32
+ mission_id: input.missionId,
33
+ requirements
34
+ };
35
+ }
36
+ function splitRequirementClauses(task) {
37
+ return task
38
+ .split(/\r?\n|[.;]|(?:\s+-\s+)/g)
39
+ .map((part) => part.replace(/^[-*\d.)\s]+/, '').trim())
40
+ .filter(Boolean);
41
+ }
42
+ //# sourceMappingURL=glm-naruto-requirement-ledger.js.map
@@ -0,0 +1,85 @@
1
+ export async function runGlmNarutoStageScheduler(input) {
2
+ const started = Date.now();
3
+ const queue = input.jobs.map((job, index) => ({ job, index }));
4
+ const running = new Map();
5
+ const results = new Array(input.jobs.length);
6
+ const events = [];
7
+ const maxActive = Math.max(1, Math.min(Math.max(1, input.max_active), Math.max(1, input.jobs.length)));
8
+ let nextKey = 0;
9
+ let maxObservedActive = 0;
10
+ let sumJobDurationMs = 0;
11
+ while (queue.length > 0 || running.size > 0) {
12
+ while (queue.length > 0 && running.size < maxActive) {
13
+ const next = queue.shift();
14
+ const key = nextKey++;
15
+ const active = running.size + 1;
16
+ maxObservedActive = Math.max(maxObservedActive, active);
17
+ await emit({
18
+ schema: 'sks.glm-naruto-stage-event.v1',
19
+ stage: input.stage,
20
+ job_id: next.job.id,
21
+ phase: 'start',
22
+ active,
23
+ timestamp_ms: Date.now()
24
+ });
25
+ running.set(key, runOne(key, next.index, next.job, input));
26
+ }
27
+ if (running.size === 0)
28
+ continue;
29
+ const completed = await Promise.race([...running.values()]);
30
+ running.delete(completed.key);
31
+ const duration = Math.max(0, Date.now() - completed.started_ms);
32
+ sumJobDurationMs += duration;
33
+ results[completed.index] = completed.settled;
34
+ await emit({
35
+ schema: 'sks.glm-naruto-stage-event.v1',
36
+ stage: input.stage,
37
+ job_id: completed.job.id,
38
+ phase: 'end',
39
+ active: running.size,
40
+ timestamp_ms: Date.now(),
41
+ duration_ms: duration,
42
+ status: completed.settled.status
43
+ });
44
+ }
45
+ const wallClockMs = Math.max(0, Date.now() - started);
46
+ return {
47
+ stage: input.stage,
48
+ results: results.map((row) => row),
49
+ max_observed_active: maxObservedActive,
50
+ wall_clock_ms: wallClockMs,
51
+ sum_job_duration_ms: sumJobDurationMs,
52
+ overlap_ratio: wallClockMs > 0 ? sumJobDurationMs / wallClockMs : input.jobs.length > 1 ? input.jobs.length : 1,
53
+ events
54
+ };
55
+ async function emit(event) {
56
+ events.push(event);
57
+ if (input.onEvent)
58
+ await input.onEvent(event);
59
+ }
60
+ }
61
+ async function runOne(key, index, job, input) {
62
+ const startedMs = Date.now();
63
+ try {
64
+ const value = await withTimeout(input.runJob(job), input.timeout_ms);
65
+ return { key, index, job, started_ms: startedMs, settled: { status: 'fulfilled', value } };
66
+ }
67
+ catch (reason) {
68
+ return { key, index, job, started_ms: startedMs, settled: { status: 'rejected', reason } };
69
+ }
70
+ }
71
+ function withTimeout(promise, timeoutMs) {
72
+ if (!timeoutMs || timeoutMs <= 0)
73
+ return promise;
74
+ let timer;
75
+ return Promise.race([
76
+ promise,
77
+ new Promise((_, reject) => {
78
+ timer = setTimeout(() => reject(new Error('glm_stage_job_timeout')), timeoutMs);
79
+ })
80
+ ]).finally(() => {
81
+ if (timer)
82
+ clearTimeout(timer);
83
+ });
84
+ }
85
+ //# sourceMappingURL=glm-naruto-stage-scheduler.js.map
@@ -0,0 +1,12 @@
1
+ export function classifyGlmTaskSize(task) {
2
+ const paths = [...new Set(task.match(/[A-Za-z0-9_.-]+\/[A-Za-z0-9_./-]+\.[A-Za-z0-9]+/g) ?? [])];
3
+ const lower = task.toLowerCase();
4
+ if (paths.length === 1 && /\b(tiny|small|simple|copy|spacing|label|one file|single-file)\b/.test(lower)) {
5
+ return { kind: 'tiny_single_file', confidence: 0.82, reasons: ['one_mentioned_file', 'tiny_task_language'] };
6
+ }
7
+ if (paths.length > 1 || /\b(parallel|multi-file|refactor|route|scheduler|coverage|benchmark)\b/.test(lower)) {
8
+ return { kind: 'parallelizable_multi_file', confidence: 0.78, reasons: paths.length > 1 ? ['multiple_mentioned_files'] : ['parallelizable_task_language'] };
9
+ }
10
+ return { kind: 'unknown', confidence: 0.4, reasons: ['insufficient_task_shape_evidence'] };
11
+ }
12
+ //# sourceMappingURL=glm-naruto-task-size-classifier.js.map
@@ -67,6 +67,10 @@ export async function writeMissionArtifacts(input) {
67
67
  shard_id: env.shard_id,
68
68
  model: env.model || null,
69
69
  provider: 'openrouter',
70
+ gpt_fallback_allowed: false,
71
+ fallback_models_count: 0,
72
+ openai_key_used: false,
73
+ authorization_source: 'openrouter',
70
74
  request_body_size: env.request_body_size ?? null,
71
75
  cached: env.cached ?? false,
72
76
  created_at: nowIso(),
@@ -12,6 +12,11 @@ export function parseGlmNarutoVerifierOutput(content) {
12
12
  issues.push('risk_score');
13
13
  if (typeof parsed.confidence !== 'number' || parsed.confidence < 0 || parsed.confidence > 1)
14
14
  issues.push('confidence');
15
+ for (const key of ['requirements_satisfied', 'requirements_missing', 'detail_loss_risks']) {
16
+ if (parsed[key] !== undefined && (!Array.isArray(parsed[key]) || parsed[key].some((item) => typeof item !== 'string'))) {
17
+ issues.push(key);
18
+ }
19
+ }
15
20
  if (issues.length)
16
21
  return { ok: false, issues: issues.map((issue) => `invalid_${issue}`) };
17
22
  return { ok: true, output: parsed, issues: [] };
@@ -8,11 +8,15 @@ import { writeGlmNarutoWorkerArtifacts } from './glm-naruto-worker-artifacts.js'
8
8
  import { materializePatchViaWorktree } from './glm-naruto-worktree-worker.js';
9
9
  import { createProviderHealthTracker } from '../../openrouter/openrouter-provider-health.js';
10
10
  import { runGlmNarutoWorkerScheduler } from './glm-naruto-worker-scheduler.js';
11
+ import { runGlmNarutoStageScheduler } from './glm-naruto-stage-scheduler.js';
12
+ import { createStageParallelismMetric, metricFromStageResult } from './glm-naruto-parallelism-summary.js';
11
13
  export async function runPatchWorkerPool(input) {
12
14
  const envelopes = [];
13
15
  const traces = [];
14
16
  const failedShardIds = [];
15
17
  const concurrencyDecisions = [];
18
+ const stageMetrics = [];
19
+ const stageEvents = [];
16
20
  const mutableShards = input.shards.filter((s) => s.mutable);
17
21
  const decision = decideConcurrency({
18
22
  requestedClones: input.maxWorkers,
@@ -33,6 +37,7 @@ export async function runPatchWorkerPool(input) {
33
37
  }
34
38
  }
35
39
  const health = input.health ?? createProviderHealthTracker();
40
+ const patchGenerationStarted = Date.now();
36
41
  const schedulerResult = await runGlmNarutoWorkerScheduler({
37
42
  jobs,
38
43
  initial_active_workers: decision.target_active_workers,
@@ -52,23 +57,56 @@ export async function runPatchWorkerPool(input) {
52
57
  timeoutMs: input.workerTimeoutMs
53
58
  })
54
59
  });
60
+ const patchGenerationWallClockMs = Date.now() - patchGenerationStarted;
55
61
  await writeSchedulerArtifacts(input.cwd, input.missionId, schedulerResult).catch(() => undefined);
56
62
  const results = schedulerResult.results;
63
+ stageMetrics.push(createStageParallelismMetric({
64
+ stage: input.stageName ?? 'patch_generation',
65
+ job_count: jobs.length,
66
+ max_observed_active: schedulerResult.max_observed_active_workers,
67
+ wall_clock_ms: patchGenerationWallClockMs,
68
+ sum_job_duration_ms: schedulerResult.results.reduce((sum, result) => (result.status === 'fulfilled' ? sum + Math.max(0, result.value.trace.total_ms) : sum + input.workerTimeoutMs), 0),
69
+ overlap_ratio: 1
70
+ }));
71
+ const successfulCandidates = [];
57
72
  for (const result of results) {
58
73
  if (result.status === 'fulfilled' && result.value.ok && result.value.envelope) {
59
- const isolationMode = input.isolationMode ?? 'patch-envelope-only';
60
- let candidateEnvelope = result.value.envelope;
61
- let worktreeRecord;
62
- if (isolationMode === 'git-worktree') {
74
+ successfulCandidates.push({ envelope: result.value.envelope, trace: result.value.trace });
75
+ }
76
+ else if (result.status === 'fulfilled') {
77
+ traces.push(result.value.trace);
78
+ failedShardIds.push(result.value.trace.shard_id);
79
+ }
80
+ else {
81
+ // rejected promise
82
+ failedShardIds.push('unknown');
83
+ }
84
+ }
85
+ const isolationMode = input.isolationMode ?? 'patch-envelope-only';
86
+ let materializedCandidates = successfulCandidates.map((candidate) => ({
87
+ envelope: candidate.envelope,
88
+ trace: candidate.trace,
89
+ gateEligible: true
90
+ }));
91
+ if (isolationMode === 'git-worktree' && materializedCandidates.length > 0) {
92
+ const worktreeStage = await runGlmNarutoStageScheduler({
93
+ stage: 'worktree_materialization',
94
+ jobs: materializedCandidates.map((candidate) => ({
95
+ id: candidate.envelope.worker_id,
96
+ stage: 'worktree_materialization',
97
+ input: candidate
98
+ })),
99
+ max_active: Math.min(4, materializedCandidates.length),
100
+ timeout_ms: input.workerTimeoutMs,
101
+ runJob: async (job) => {
63
102
  const worktree = await materializePatchViaWorktree({
64
103
  repoRoot: input.cwd,
65
104
  missionId: input.missionId,
66
- envelope: candidateEnvelope,
105
+ envelope: job.input.envelope,
67
106
  ...(input.baseCommit !== undefined ? { baseCommit: input.baseCommit } : {}),
68
107
  cleanup: input.cleanupWorktrees !== false
69
108
  });
70
- candidateEnvelope = worktree.envelope;
71
- worktreeRecord = {
109
+ const worktreeRecord = {
72
110
  schema: 'sks.glm-naruto-worker-worktree.v1',
73
111
  selected: 'git-worktree',
74
112
  ok: worktree.ok,
@@ -80,34 +118,88 @@ export async function runPatchWorkerPool(input) {
80
118
  applied_patch_was_extracted: worktree.worktree?.applied_patch_was_extracted ?? false,
81
119
  blockers: worktree.blockers
82
120
  };
83
- if (!worktree.ok) {
84
- await writeGlmNarutoWorkerArtifacts({
85
- root: input.cwd,
86
- missionId: input.missionId,
87
- workerId: candidateEnvelope.worker_id,
88
- shardId: candidateEnvelope.shard_id,
89
- patchEnvelope: candidateEnvelope,
90
- streamTrace: result.value.trace,
91
- isolation: {
92
- schema: 'sks.glm-naruto-worker-isolation.v1',
93
- selected: isolationMode,
94
- workers_write_main_workspace: false
95
- },
96
- worktree: worktreeRecord,
97
- termination: { status: candidateEnvelope.status, ok: false, blockers: candidateEnvelope.blockers }
98
- }).catch(() => undefined);
99
- envelopes.push(candidateEnvelope);
100
- traces.push(result.value.trace);
101
- failedShardIds.push(candidateEnvelope.shard_id);
102
- continue;
103
- }
121
+ return {
122
+ envelope: worktree.ok ? worktree.envelope : { ...worktree.envelope, status: 'gate_failed', blockers: worktree.blockers },
123
+ worktreeRecord,
124
+ ok: worktree.ok
125
+ };
104
126
  }
105
- const gate = await evaluateGlmNarutoPatchCandidateGate({
127
+ });
128
+ stageMetrics.push(metricFromStageResult(worktreeStage));
129
+ stageEvents.push(...worktreeStage.events);
130
+ materializedCandidates = materializedCandidates.map((candidate, index) => {
131
+ const result = worktreeStage.results[index];
132
+ if (result?.status === 'fulfilled') {
133
+ return {
134
+ envelope: result.value.envelope,
135
+ trace: candidate.trace,
136
+ gateEligible: result.value.ok,
137
+ worktreeRecord: result.value.worktreeRecord
138
+ };
139
+ }
140
+ return {
141
+ envelope: { ...candidate.envelope, status: 'gate_failed', blockers: ['worktree_materialization_failed'] },
142
+ trace: candidate.trace,
143
+ gateEligible: false
144
+ };
145
+ });
146
+ }
147
+ for (const candidate of materializedCandidates.filter((item) => !item.gateEligible)) {
148
+ await writeGlmNarutoWorkerArtifacts({
149
+ root: input.cwd,
150
+ missionId: input.missionId,
151
+ workerId: candidate.envelope.worker_id,
152
+ shardId: candidate.envelope.shard_id,
153
+ patchEnvelope: candidate.envelope,
154
+ streamTrace: candidate.trace,
155
+ isolation: {
156
+ schema: 'sks.glm-naruto-worker-isolation.v1',
157
+ selected: isolationMode,
158
+ workers_write_main_workspace: false
159
+ },
160
+ ...(candidate.worktreeRecord ? { worktree: candidate.worktreeRecord } : {}),
161
+ termination: { status: candidate.envelope.status, ok: false, blockers: candidate.envelope.blockers }
162
+ }).catch(() => undefined);
163
+ envelopes.push(candidate.envelope);
164
+ traces.push(candidate.trace);
165
+ failedShardIds.push(candidate.envelope.shard_id);
166
+ }
167
+ const gateCandidates = materializedCandidates.filter((item) => item.gateEligible);
168
+ if (gateCandidates.length > 0) {
169
+ const gateStage = await runGlmNarutoStageScheduler({
170
+ stage: 'candidate_gate',
171
+ jobs: gateCandidates.map((candidate) => ({
172
+ id: candidate.envelope.worker_id,
173
+ stage: 'candidate_gate',
174
+ input: candidate
175
+ })),
176
+ max_active: Math.min(8, gateCandidates.length),
177
+ timeout_ms: Math.min(60_000, input.workerTimeoutMs),
178
+ runJob: (job) => evaluateGlmNarutoPatchCandidateGate({
106
179
  cwd: input.cwd,
107
- envelope: candidateEnvelope,
180
+ envelope: job.input.envelope,
108
181
  apply: false
109
- });
110
- let envelope = candidateEnvelope;
182
+ })
183
+ });
184
+ stageMetrics.push(metricFromStageResult(gateStage));
185
+ stageEvents.push(...gateStage.events);
186
+ for (let index = 0; index < gateCandidates.length; index += 1) {
187
+ const candidate = gateCandidates[index];
188
+ const result = gateStage.results[index];
189
+ const gate = result?.status === 'fulfilled'
190
+ ? result.value
191
+ : {
192
+ schema: 'sks.glm-naruto-patch-candidate-gate.v1',
193
+ ok: false,
194
+ worker_id: candidate.envelope.worker_id,
195
+ shard_id: candidate.envelope.shard_id,
196
+ patch_id: candidate.envelope.patch_sha256,
197
+ extracted_patch: '',
198
+ touched_paths: [],
199
+ checks: [],
200
+ blockers: ['candidate_gate_failed']
201
+ };
202
+ let envelope = candidate.envelope;
111
203
  if (gate.ok) {
112
204
  envelope = createPatchEnvelope({
113
205
  missionId: envelope.mission_id,
@@ -135,25 +227,17 @@ export async function runPatchWorkerPool(input) {
135
227
  shardId: envelope.shard_id,
136
228
  patchEnvelope: envelope,
137
229
  gateResult: gate,
138
- streamTrace: result.value.trace,
230
+ streamTrace: candidate.trace,
139
231
  isolation: {
140
232
  schema: 'sks.glm-naruto-worker-isolation.v1',
141
233
  selected: isolationMode,
142
234
  workers_write_main_workspace: false
143
235
  },
144
- ...(worktreeRecord ? { worktree: worktreeRecord } : {}),
236
+ ...(candidate.worktreeRecord ? { worktree: candidate.worktreeRecord } : {}),
145
237
  termination: { status: envelope.status, ok: gate.ok, blockers: envelope.blockers }
146
238
  }).catch(() => undefined);
147
239
  envelopes.push(envelope);
148
- traces.push(result.value.trace);
149
- }
150
- else if (result.status === 'fulfilled') {
151
- traces.push(result.value.trace);
152
- failedShardIds.push(result.value.trace.shard_id);
153
- }
154
- else {
155
- // rejected promise
156
- failedShardIds.push('unknown');
240
+ traces.push(candidate.trace);
157
241
  }
158
242
  }
159
243
  return {
@@ -165,7 +249,9 @@ export async function runPatchWorkerPool(input) {
165
249
  max_observed_active_workers: schedulerResult.max_observed_active_workers,
166
250
  backpressure_events: schedulerResult.backpressure_events,
167
251
  queue_drained: true
168
- }
252
+ },
253
+ stageMetrics,
254
+ stageEvents
169
255
  };
170
256
  }
171
257
  async function writeSchedulerArtifacts(root, missionId, schedulerResult) {
@@ -65,6 +65,10 @@ export async function runPatchWorker(input) {
65
65
  request_body_size: encoded.entry.byteLength,
66
66
  request_body_stored: encoded.entry.bodyStored,
67
67
  cache_hit: encoded.cacheHit,
68
+ gpt_fallback_allowed: false,
69
+ fallback_models_count: Array.isArray(requestWithSession.models) ? requestWithSession.models?.length ?? 0 : 0,
70
+ openai_key_used: false,
71
+ authorization_source: 'openrouter',
68
72
  stable_prefix_digest: stablePrefixDigest,
69
73
  shard_suffix_digest: shardSuffixDigest
70
74
  }
@@ -239,8 +243,8 @@ export async function runVerifierWorker(input) {
239
243
  const started = Date.now();
240
244
  const sessionId = normalizeGlmNarutoSessionId(`sks-glm-naruto-verify-${input.missionId}-${input.workerId}`);
241
245
  const messages = [
242
- { role: 'system', content: `You are a SKS GLM Naruto verifier. Model: ${GLM_52_OPENROUTER_MODEL}. No GPT fallback. Return only JSON with schema "sks.glm-naruto-verifier-output.v1", ok boolean, issues string array, risk_score number 0..1, confidence number 0..1. Do not include markdown.` },
243
- { role: 'user', content: JSON.stringify({ patch_sha256: input.envelope.patch_sha256, target_paths: input.envelope.target_paths, patch: input.envelope.patch.slice(0, 4000) }) }
246
+ { role: 'system', content: `You are a SKS GLM Naruto verifier. Model: ${GLM_52_OPENROUTER_MODEL}. No GPT fallback. Return only JSON with schema "sks.glm-naruto-verifier-output.v1", ok boolean, issues string array, risk_score number 0..1, confidence number 0..1, requirements_satisfied string array, requirements_missing string array, and detail_loss_risks string array. Do not include markdown.` },
247
+ { role: 'user', content: JSON.stringify({ patch_sha256: input.envelope.patch_sha256, target_paths: input.envelope.target_paths, requirements_satisfied: input.envelope.requirements_satisfied ?? [], requirements_risk: input.envelope.requirements_risk ?? [], patch: input.envelope.patch.slice(0, 4000) }) }
244
248
  ];
245
249
  const request = buildGlm52Request({
246
250
  profile: 'speed',
@@ -0,0 +1,44 @@
1
+ export function resolveSksModelMode(args = []) {
2
+ const normalized = args.map(String);
3
+ const hasGlm = normalized.includes('--glm');
4
+ const hasMad = normalized.includes('--mad') || normalized.includes('--MAD') || normalized.includes('--mad-sks');
5
+ const hasNaruto = normalized.includes('--naruto') || normalized.includes('naruto');
6
+ if (hasGlm && hasNaruto) {
7
+ return decision('glm-naruto', true, false, 'explicit_--glm_with_naruto', normalized);
8
+ }
9
+ if (hasGlm) {
10
+ return decision('glm-direct', true, false, 'explicit_--glm', normalized);
11
+ }
12
+ if (hasMad) {
13
+ return decision('gpt-mad', false, true, 'mad_without_--glm', normalized);
14
+ }
15
+ if (hasNaruto) {
16
+ return decision('classic-naruto', false, true, 'naruto_without_--glm', normalized);
17
+ }
18
+ return decision('unknown', false, false, 'no_model_mode_flags', normalized);
19
+ }
20
+ export function assertGlmRoute(args = []) {
21
+ const resolved = resolveSksModelMode(args);
22
+ if (!resolved.glm_enabled) {
23
+ throw new Error(`sks_glm_route_required:${resolved.mode}`);
24
+ }
25
+ return resolved;
26
+ }
27
+ export function assertNonGlmMadRoute(args = []) {
28
+ const resolved = resolveSksModelMode(args);
29
+ if (resolved.glm_enabled || resolved.mode !== 'gpt-mad') {
30
+ throw new Error(`sks_mad_route_glm_leak:${resolved.mode}`);
31
+ }
32
+ return resolved;
33
+ }
34
+ function decision(mode, glmEnabled, gptMadPreserved, reason, args) {
35
+ return {
36
+ schema: 'sks.model-mode-decision.v1',
37
+ mode,
38
+ glm_enabled: glmEnabled,
39
+ gpt_mad_preserved: gptMadPreserved,
40
+ reason,
41
+ args
42
+ };
43
+ }
44
+ //# sourceMappingURL=model-mode-router.js.map
@@ -1,2 +1,2 @@
1
- export const PACKAGE_VERSION = '4.0.13';
1
+ export const PACKAGE_VERSION = '4.0.14';
2
2
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "4.0.13",
4
+ "version": "4.0.14",
5
5
  "description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
@@ -38,6 +38,29 @@
38
38
  "!dist/scripts/*-check-lib.js",
39
39
  "!dist/scripts/*-report.js",
40
40
  "!dist/scripts/release-readiness-report.js",
41
+ "!dist/scripts/*-smoke.js",
42
+ "!dist/scripts/*-gate.js",
43
+ "!dist/scripts/*-lib.js",
44
+ "!dist/scripts/*-proof.js",
45
+ "!dist/scripts/blackbox-*.js",
46
+ "!dist/scripts/check-*.js",
47
+ "!dist/scripts/*-fixture.js",
48
+ "!dist/scripts/*-audit.js",
49
+ "!dist/scripts/*-regression.js",
50
+ "!dist/scripts/*-helper.js",
51
+ "!dist/scripts/fixtures/",
52
+ "!dist/scripts/release-*.js",
53
+ "!dist/scripts/hooks-*.js",
54
+ "!dist/scripts/build-*.js",
55
+ "!dist/scripts/clean-*.js",
56
+ "!dist/scripts/ensure-*.js",
57
+ "!dist/scripts/sizecheck.js",
58
+ "!dist/scripts/perf-*.js",
59
+ "!dist/scripts/prepublish-*.js",
60
+ "!dist/scripts/write-*.js",
61
+ "!dist/scripts/*-inventory.js",
62
+ "!dist/scripts/*-watch.js",
63
+ "!dist/scripts/lib/",
41
64
  "schemas",
42
65
  "crates/sks-core/Cargo.lock",
43
66
  "crates/sks-core/Cargo.toml",