sneakoscope 4.0.11 → 4.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/sks.js +1 -1
- package/dist/core/commands/glm-command.js +11 -5
- package/dist/core/fsx.js +1 -1
- package/dist/core/providers/glm/bench/glm-bench-comparison.js +48 -0
- package/dist/core/providers/glm/bench/glm-bench-fixture.js +65 -0
- package/dist/core/providers/glm/bench/glm-bench-model-lock-proof.js +24 -0
- package/dist/core/providers/glm/bench/glm-bench-report.js +75 -0
- package/dist/core/providers/glm/bench/glm-benchmark-runner.js +219 -0
- package/dist/core/providers/glm/bench/glm-benchmark-types.js +2 -0
- package/dist/core/providers/glm/bench/glm-direct-bench-runner.js +73 -0
- package/dist/core/providers/glm/naruto/glm-naruto-apply-transaction.js +54 -8
- package/dist/core/providers/glm/naruto/glm-naruto-bench.js +4 -118
- package/dist/core/providers/glm/naruto/glm-naruto-command.js +20 -3
- package/dist/core/providers/glm/naruto/glm-naruto-final-seal.js +75 -0
- package/dist/core/providers/glm/naruto/glm-naruto-orchestrator.js +41 -5
- package/dist/core/providers/glm/naruto/glm-naruto-targeted-checks.js +76 -0
- package/dist/core/providers/glm/naruto/glm-naruto-trace.js +50 -0
- package/dist/core/providers/glm/naruto/glm-naruto-worker-pool.js +61 -19
- package/dist/core/providers/glm/naruto/glm-naruto-worker-runtime.js +26 -4
- package/dist/core/providers/glm/naruto/glm-naruto-worker-scheduler.js +178 -0
- package/dist/core/providers/glm/naruto/glm-naruto-worktree-worker.js +34 -4
- package/dist/core/version.js +1 -1
- package/package.json +1 -1
- package/dist/core/providers/glm/glm-bench.js +0 -127
|
@@ -3,22 +3,28 @@ import path from 'node:path';
|
|
|
3
3
|
import { sha256, writeJsonAtomic, writeTextAtomic } from '../../../fsx.js';
|
|
4
4
|
import { parseUnifiedDiffPatch } from '../glm-patch-parser.js';
|
|
5
5
|
import { combineGlmNarutoPatches } from './glm-naruto-combined-patch.js';
|
|
6
|
+
import { runGlmNarutoTargetedChecks } from './glm-naruto-targeted-checks.js';
|
|
6
7
|
export async function runGlmNarutoApplyTransaction(input) {
|
|
7
8
|
const preStatus = await gitText(input.cwd, ['status', '--short']);
|
|
8
9
|
const preDiff = await gitText(input.cwd, ['diff', '--binary']);
|
|
9
10
|
const patch = combineGlmNarutoPatches(input.envelopes, input.selectedPatchIds);
|
|
10
11
|
const parsed = parseUnifiedDiffPatch(patch);
|
|
12
|
+
const dirtyTouchedPaths = await dirtyPaths(input.cwd, parsed.touchedPaths);
|
|
11
13
|
const patchPath = path.join(input.artifactDir, 'selected-combined.patch');
|
|
12
14
|
await writeTextAtomic(patchPath, patch);
|
|
13
15
|
const blockers = [];
|
|
14
16
|
let applyCheckPassed = false;
|
|
15
17
|
let applyPassed = false;
|
|
18
|
+
let targetedChecksPassed = null;
|
|
16
19
|
let rollbackAttempted = false;
|
|
17
20
|
let rollbackPassed = null;
|
|
18
21
|
let finalStatus = 'blocked';
|
|
19
22
|
if (!patch.trim()) {
|
|
20
23
|
blockers.push('combined_patch_empty');
|
|
21
24
|
}
|
|
25
|
+
else if (dirtyTouchedPaths.length > 0 && !input.allowDirtyApply) {
|
|
26
|
+
blockers.push(`dirty_touched_paths_before_apply:${dirtyTouchedPaths.join(',')}`);
|
|
27
|
+
}
|
|
22
28
|
else {
|
|
23
29
|
const checked = await gitApply(input.cwd, patch, ['apply', '--check', '--whitespace=nowarn', '-']);
|
|
24
30
|
applyCheckPassed = checked.code === 0;
|
|
@@ -28,16 +34,41 @@ export async function runGlmNarutoApplyTransaction(input) {
|
|
|
28
34
|
const applied = await gitApply(input.cwd, patch, ['apply', '--whitespace=nowarn', '-']);
|
|
29
35
|
applyPassed = applied.code === 0;
|
|
30
36
|
if (applyPassed) {
|
|
31
|
-
|
|
37
|
+
const targeted = await runGlmNarutoTargetedChecks({
|
|
38
|
+
cwd: input.cwd,
|
|
39
|
+
touchedPaths: parsed.touchedPaths,
|
|
40
|
+
artifactDir: input.artifactDir,
|
|
41
|
+
...(input.strictChecks !== undefined ? { strictChecks: input.strictChecks } : {})
|
|
42
|
+
});
|
|
43
|
+
targetedChecksPassed = targeted.ok;
|
|
44
|
+
if (targeted.ok) {
|
|
45
|
+
finalStatus = 'applied';
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
blockers.push(...targeted.blockers);
|
|
49
|
+
if (!input.noRollback) {
|
|
50
|
+
rollbackAttempted = true;
|
|
51
|
+
const rollback = await gitApply(input.cwd, patch, ['apply', '-R', '--whitespace=nowarn', '-']);
|
|
52
|
+
rollbackPassed = rollback.code === 0;
|
|
53
|
+
finalStatus = rollbackPassed ? 'rolled_back' : 'blocked';
|
|
54
|
+
if (!rollbackPassed)
|
|
55
|
+
blockers.push(rollback.stderr || rollback.stdout || 'rollback_reverse_patch_failed');
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
finalStatus = 'blocked';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
32
61
|
}
|
|
33
62
|
else {
|
|
34
63
|
blockers.push(applied.stderr || applied.stdout || 'git_apply_failed');
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
64
|
+
if (!input.noRollback) {
|
|
65
|
+
rollbackAttempted = true;
|
|
66
|
+
const rollback = await gitApply(input.cwd, patch, ['apply', '-R', '--whitespace=nowarn', '-']);
|
|
67
|
+
rollbackPassed = rollback.code === 0;
|
|
68
|
+
finalStatus = rollbackPassed ? 'rolled_back' : 'blocked';
|
|
69
|
+
if (!rollbackPassed)
|
|
70
|
+
blockers.push(rollback.stderr || rollback.stdout || 'rollback_reverse_patch_failed');
|
|
71
|
+
}
|
|
41
72
|
}
|
|
42
73
|
}
|
|
43
74
|
}
|
|
@@ -47,12 +78,15 @@ export async function runGlmNarutoApplyTransaction(input) {
|
|
|
47
78
|
mission_id: input.missionId,
|
|
48
79
|
selected_patch_ids: input.selectedPatchIds,
|
|
49
80
|
touched_paths: parsed.touchedPaths,
|
|
81
|
+
dirty_touched_paths_before_apply: dirtyTouchedPaths,
|
|
82
|
+
dirty_policy: input.allowDirtyApply ? 'allow' : 'block',
|
|
50
83
|
pre_status: preStatus,
|
|
51
84
|
pre_diff_sha256: sha256(preDiff),
|
|
85
|
+
post_diff_sha256: sha256(postDiff),
|
|
52
86
|
combined_patch_sha256: sha256(patch),
|
|
53
87
|
apply_check_passed: applyCheckPassed,
|
|
54
88
|
apply_passed: applyPassed,
|
|
55
|
-
targeted_checks_passed:
|
|
89
|
+
targeted_checks_passed: targetedChecksPassed,
|
|
56
90
|
rollback_attempted: rollbackAttempted,
|
|
57
91
|
rollback_passed: rollbackPassed,
|
|
58
92
|
final_status: finalStatus,
|
|
@@ -76,6 +110,18 @@ function gitText(cwd, args) {
|
|
|
76
110
|
child.on('close', () => resolve(stdout));
|
|
77
111
|
});
|
|
78
112
|
}
|
|
113
|
+
async function dirtyPaths(cwd, paths) {
|
|
114
|
+
if (paths.length === 0)
|
|
115
|
+
return [];
|
|
116
|
+
const status = await gitText(cwd, ['status', '--short', '--', ...paths]);
|
|
117
|
+
return status.split(/\r?\n/)
|
|
118
|
+
.map((line) => line.trimEnd())
|
|
119
|
+
.filter(Boolean)
|
|
120
|
+
.map((line) => {
|
|
121
|
+
const raw = line.slice(3).trim();
|
|
122
|
+
return raw.includes(' -> ') ? raw.split(' -> ').pop().trim() : raw;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
79
125
|
function gitApply(cwd, patch, args) {
|
|
80
126
|
return new Promise((resolve) => {
|
|
81
127
|
const child = spawn('git', [...args], { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
@@ -1,121 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import fsp from 'node:fs/promises';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import { GLM_52_OPENROUTER_MODEL } from '../glm-52-settings.js';
|
|
6
|
-
import { resolveOpenRouterApiKey } from '../../openrouter/openrouter-secret-store.js';
|
|
1
|
+
import { runGlmBenchmark } from '../bench/glm-benchmark-runner.js';
|
|
2
|
+
import { runGlmDirectSpeedRun } from '../glm-direct-run.js';
|
|
7
3
|
import { runGlmNarutoMission } from './glm-naruto-orchestrator.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const live = args.includes('--live');
|
|
11
|
-
const execute = args.includes('--execute');
|
|
12
|
-
const started = Date.now();
|
|
13
|
-
if (execute && !live) {
|
|
14
|
-
return blocked(root, ['execute_requires_live_flag']);
|
|
15
|
-
}
|
|
16
|
-
if (!live) {
|
|
17
|
-
return {
|
|
18
|
-
schema: 'sks.glm-naruto-bench.v1',
|
|
19
|
-
version: '4.0.11',
|
|
20
|
-
generated_at: nowIso(),
|
|
21
|
-
status: 'dry_run',
|
|
22
|
-
model: GLM_52_OPENROUTER_MODEL,
|
|
23
|
-
gpt_fallback_allowed: false,
|
|
24
|
-
summary: {
|
|
25
|
-
simulated_workers: 12,
|
|
26
|
-
simulated_waves: 3,
|
|
27
|
-
simulated_patch_candidates: 24,
|
|
28
|
-
simulated_gate_passed: 18,
|
|
29
|
-
simulated_mergeable: 12,
|
|
30
|
-
wall_clock_ms: Date.now() - started
|
|
31
|
-
},
|
|
32
|
-
warnings: ['dry_run_no_live_api_calls']
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
const key = await resolveOpenRouterApiKey({ env: process.env });
|
|
36
|
-
if (!key.key)
|
|
37
|
-
return blocked(root, ['live_bench_requires_openrouter_key']);
|
|
38
|
-
const fixture = await fsp.mkdtemp(path.join(os.tmpdir(), 'sks-glm-naruto-live-bench-'));
|
|
39
|
-
await fsp.mkdir(path.join(fixture, 'src'), { recursive: true });
|
|
40
|
-
await fsp.writeFile(path.join(fixture, 'src', 'bench-target.ts'), 'export const value = 1;\n', 'utf8');
|
|
41
|
-
const cases = [];
|
|
42
|
-
for (const workers of [1, 4, 8, 12]) {
|
|
43
|
-
const caseStarted = Date.now();
|
|
44
|
-
const result = await runGlmNarutoMission({
|
|
45
|
-
cwd: fixture,
|
|
46
|
-
task: 'Change src/bench-target.ts so value is 2. Return the smallest patch only.',
|
|
47
|
-
args: ['--bench', '--live', '--no-apply'],
|
|
48
|
-
missionId: `glm-naruto-live-bench-${workers}-${Date.now()}`,
|
|
49
|
-
maxWorkers: workers,
|
|
50
|
-
noApply: true
|
|
51
|
-
});
|
|
52
|
-
const traces = await readWorkerTraces(result.artifact_dir);
|
|
53
|
-
const metrics = summarizeGlmNarutoWorkerMetrics(traces);
|
|
54
|
-
cases.push({
|
|
55
|
-
name: workers === 1 ? 'direct single GLM' : `GLM Naruto ${workers} workers`,
|
|
56
|
-
workers,
|
|
57
|
-
wall_clock_ms: Date.now() - caseStarted,
|
|
58
|
-
p50_ttft_ms: metrics.p50_ttft_ms,
|
|
59
|
-
p90_ttft_ms: metrics.p90_ttft_ms,
|
|
60
|
-
p50_total_ms: metrics.p50_total_ms,
|
|
61
|
-
p90_total_ms: metrics.p90_total_ms,
|
|
62
|
-
candidate_count: result.patch_candidates,
|
|
63
|
-
gate_pass_rate: result.patch_candidates ? result.gate_passed_candidates / result.patch_candidates : 0,
|
|
64
|
-
verifier_pass_rate: metrics.verifier_pass_rate,
|
|
65
|
-
merge_success: result.mergeable_candidates > 0,
|
|
66
|
-
cached_tokens_sum: metrics.cached_tokens_sum,
|
|
67
|
-
cache_write_tokens_sum: metrics.cache_write_tokens_sum,
|
|
68
|
-
reasoning_tokens_sum: metrics.reasoning_tokens_sum,
|
|
69
|
-
workers_completed: metrics.workers_completed,
|
|
70
|
-
workers_failed: metrics.workers_failed
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
return {
|
|
74
|
-
schema: 'sks.glm-naruto-bench.v1',
|
|
75
|
-
version: '4.0.11',
|
|
76
|
-
generated_at: nowIso(),
|
|
77
|
-
status: 'live',
|
|
78
|
-
model: GLM_52_OPENROUTER_MODEL,
|
|
79
|
-
gpt_fallback_allowed: false,
|
|
80
|
-
cases,
|
|
81
|
-
summary: {
|
|
82
|
-
simulated_workers: Math.max(...cases.map((row) => row.workers)),
|
|
83
|
-
simulated_waves: cases.length,
|
|
84
|
-
simulated_patch_candidates: cases.reduce((sum, row) => sum + row.candidate_count, 0),
|
|
85
|
-
simulated_gate_passed: cases.reduce((sum, row) => sum + Math.round(row.candidate_count * row.gate_pass_rate), 0),
|
|
86
|
-
simulated_mergeable: cases.filter((row) => row.merge_success).length,
|
|
87
|
-
wall_clock_ms: Date.now() - started
|
|
88
|
-
},
|
|
89
|
-
warnings: ['live_bench_no_apply_temp_repo']
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
function blocked(root, warnings) {
|
|
93
|
-
return {
|
|
94
|
-
schema: 'sks.glm-naruto-bench.v1',
|
|
95
|
-
version: '4.0.11',
|
|
96
|
-
generated_at: nowIso(),
|
|
97
|
-
status: 'blocked',
|
|
98
|
-
model: GLM_52_OPENROUTER_MODEL,
|
|
99
|
-
gpt_fallback_allowed: false,
|
|
100
|
-
summary: {
|
|
101
|
-
simulated_workers: 0,
|
|
102
|
-
simulated_waves: 0,
|
|
103
|
-
simulated_patch_candidates: 0,
|
|
104
|
-
simulated_gate_passed: 0,
|
|
105
|
-
simulated_mergeable: 0,
|
|
106
|
-
wall_clock_ms: 0
|
|
107
|
-
},
|
|
108
|
-
warnings
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
async function readWorkerTraces(artifactDir) {
|
|
112
|
-
if (!artifactDir)
|
|
113
|
-
return [];
|
|
114
|
-
try {
|
|
115
|
-
return JSON.parse(await fsp.readFile(path.join(artifactDir, 'worker-traces.json'), 'utf8'));
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
return [];
|
|
119
|
-
}
|
|
4
|
+
export async function runGlmNarutoBench(root, args = [], deps = {}) {
|
|
5
|
+
return runGlmBenchmark(root, args, deps);
|
|
120
6
|
}
|
|
121
7
|
//# sourceMappingURL=glm-naruto-bench.js.map
|
|
@@ -4,13 +4,24 @@ import { runGlmNarutoMission } from './glm-naruto-orchestrator.js';
|
|
|
4
4
|
import { runGlmNarutoBench } from './glm-naruto-bench.js';
|
|
5
5
|
export async function glmNarutoCommand(args = []) {
|
|
6
6
|
if (flag(args, '--bench')) {
|
|
7
|
+
// --compare is an alias; the benchmark always compares direct vs Naruto.
|
|
7
8
|
const result = await runGlmNarutoBench(process.cwd(), args);
|
|
8
9
|
if (flag(args, '--json'))
|
|
9
10
|
printJson(result);
|
|
10
11
|
else if (result.status === 'blocked')
|
|
11
|
-
console.error(`GLM
|
|
12
|
-
else
|
|
13
|
-
console.log(`GLM
|
|
12
|
+
console.error(`GLM benchmark blocked: ${result.warnings.join(', ')}`);
|
|
13
|
+
else if (result.status === 'dry_run')
|
|
14
|
+
console.log(`GLM benchmark: dry-run (use --live for real measurement)`);
|
|
15
|
+
else {
|
|
16
|
+
const direct = result.cases.find((c) => c.implementation_path === 'direct-glm');
|
|
17
|
+
const best = result.comparison.best_naruto_runner_id;
|
|
18
|
+
console.log(`GLM benchmark: ${result.status} (${result.cases.length} cases)`);
|
|
19
|
+
if (direct)
|
|
20
|
+
console.log(` Direct GLM: ${direct.wall_clock_ms}ms`);
|
|
21
|
+
if (result.comparison.best_naruto_wall_clock_ms !== null)
|
|
22
|
+
console.log(` Best Naruto: ${best} at ${result.comparison.best_naruto_wall_clock_ms}ms`);
|
|
23
|
+
console.log(` Recommendation: ${result.comparison.recommendation}`);
|
|
24
|
+
}
|
|
14
25
|
return result;
|
|
15
26
|
}
|
|
16
27
|
const positional = positionalArgs(args).map(String);
|
|
@@ -46,6 +57,9 @@ export async function glmNarutoCommand(args = []) {
|
|
|
46
57
|
const allowPatchEnvelopeFallback = flag(args, '--allow-patch-envelope-fallback');
|
|
47
58
|
const noApply = flag(args, '--no-apply');
|
|
48
59
|
const skipVerifier = flag(args, '--skip-verifier');
|
|
60
|
+
const allowDirtyApply = flag(args, '--allow-dirty-apply');
|
|
61
|
+
const noRollback = flag(args, '--no-rollback');
|
|
62
|
+
const strictChecks = flag(args, '--strict-checks');
|
|
49
63
|
const mergeStrategy = readOption(args, '--merge-strategy', 'deterministic');
|
|
50
64
|
const result = await runGlmNarutoMission({
|
|
51
65
|
cwd: process.cwd(),
|
|
@@ -62,6 +76,9 @@ export async function glmNarutoCommand(args = []) {
|
|
|
62
76
|
cleanupWorktrees,
|
|
63
77
|
noApply: noApply || flag(args, '--dry-run'),
|
|
64
78
|
skipVerifier,
|
|
79
|
+
allowDirtyApply,
|
|
80
|
+
noRollback,
|
|
81
|
+
strictChecks,
|
|
65
82
|
mergeStrategy
|
|
66
83
|
});
|
|
67
84
|
if (flag(args, '--json')) {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { writeJsonAtomic } from '../../../fsx.js';
|
|
3
|
+
import { GLM_52_OPENROUTER_MODEL } from '../glm-52-settings.js';
|
|
4
|
+
export async function writeGlmNarutoFinalSeal(input) {
|
|
5
|
+
const mismatches = [
|
|
6
|
+
...input.envelopes.filter((env) => env.model !== GLM_52_OPENROUTER_MODEL || env.gpt_fallback_allowed !== false).map((env) => `envelope:${env.worker_id}`),
|
|
7
|
+
...input.traces.filter((trace) => trace.model !== GLM_52_OPENROUTER_MODEL).map((trace) => `trace:${trace.worker_id}`)
|
|
8
|
+
];
|
|
9
|
+
const isolationViolations = input.isolationPolicy.selected === 'blocked' ? input.isolationPolicy.blockers : [];
|
|
10
|
+
const status = finalSealStatus({
|
|
11
|
+
result: input.result,
|
|
12
|
+
secretOk: input.secretAudit.ok,
|
|
13
|
+
mismatches,
|
|
14
|
+
isolationViolations,
|
|
15
|
+
queueDrained: input.scheduler.queue_drained
|
|
16
|
+
});
|
|
17
|
+
const seal = {
|
|
18
|
+
schema: 'sks.glm-naruto-final-seal.v1',
|
|
19
|
+
mission_id: input.missionId,
|
|
20
|
+
status,
|
|
21
|
+
model_lock: {
|
|
22
|
+
model: GLM_52_OPENROUTER_MODEL,
|
|
23
|
+
gpt_fallback_allowed: false,
|
|
24
|
+
requests_checked: input.envelopes.length + input.traces.length,
|
|
25
|
+
mismatches
|
|
26
|
+
},
|
|
27
|
+
isolation: {
|
|
28
|
+
selected: input.isolationPolicy.selected,
|
|
29
|
+
workers_write_main_workspace: false,
|
|
30
|
+
violations: isolationViolations
|
|
31
|
+
},
|
|
32
|
+
scheduler: {
|
|
33
|
+
bounded: true,
|
|
34
|
+
max_observed_active_workers: input.scheduler.max_observed_active_workers,
|
|
35
|
+
queue_drained: input.scheduler.queue_drained,
|
|
36
|
+
backpressure_events: input.scheduler.backpressure_events
|
|
37
|
+
},
|
|
38
|
+
candidates: {
|
|
39
|
+
total: input.envelopes.length,
|
|
40
|
+
gate_passed: input.envelopes.filter((env) => env.status === 'gate_passed').length,
|
|
41
|
+
verifier_passed: input.envelopes.filter((env) => env.verification_passed === true).length,
|
|
42
|
+
selected: input.selectedPatchIds
|
|
43
|
+
},
|
|
44
|
+
apply: {
|
|
45
|
+
attempted: input.applyTransaction !== null,
|
|
46
|
+
transaction_path: input.applyTransaction ? path.join(input.artifactDir, 'apply-transaction.json') : null,
|
|
47
|
+
final_status: input.applyTransaction?.final_status ?? null,
|
|
48
|
+
rollback_attempted: input.applyTransaction?.rollback_attempted ?? false,
|
|
49
|
+
rollback_passed: input.applyTransaction?.rollback_passed ?? null
|
|
50
|
+
},
|
|
51
|
+
secret_audit: {
|
|
52
|
+
ok: input.secretAudit.ok,
|
|
53
|
+
findings: input.secretAudit.findings ?? []
|
|
54
|
+
},
|
|
55
|
+
stop_gate: {
|
|
56
|
+
path: input.stopGatePath,
|
|
57
|
+
passed: input.stopGatePassed
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const out = path.join(input.artifactDir, 'final-seal.json');
|
|
61
|
+
await writeJsonAtomic(out, seal);
|
|
62
|
+
return { seal, path: out, passed: seal.status === 'passed' };
|
|
63
|
+
}
|
|
64
|
+
function finalSealStatus(input) {
|
|
65
|
+
if (!input.secretOk || input.mismatches.length > 0 || input.isolationViolations.length > 0 || !input.queueDrained)
|
|
66
|
+
return 'blocked';
|
|
67
|
+
if (input.result.ok)
|
|
68
|
+
return 'passed';
|
|
69
|
+
if (input.result.status === 'partial_candidates')
|
|
70
|
+
return 'partial';
|
|
71
|
+
if (input.result.status === 'blocked')
|
|
72
|
+
return 'blocked';
|
|
73
|
+
return 'failed';
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=glm-naruto-final-seal.js.map
|
|
@@ -20,6 +20,7 @@ import { getGitHead, getGitRoot } from './glm-naruto-worktree-manager.js';
|
|
|
20
20
|
import { buildGlmNarutoCandidateScoreboard } from './glm-naruto-scoreboard.js';
|
|
21
21
|
import { runGlmNarutoApplyTransaction } from './glm-naruto-apply-transaction.js';
|
|
22
22
|
import { finalizeGlmNarutoTerminal } from './glm-naruto-terminal.js';
|
|
23
|
+
import { writeGlmNarutoFinalSeal } from './glm-naruto-final-seal.js';
|
|
23
24
|
import { GLM_NARUTO_LIMITS } from './glm-naruto-types.js';
|
|
24
25
|
export async function runGlmNarutoMission(input) {
|
|
25
26
|
const missionId = input.missionId || `glm-naruto-${nowIso().replace(/[:.]/g, '-')}`;
|
|
@@ -94,7 +95,8 @@ export async function runGlmNarutoMission(input) {
|
|
|
94
95
|
strategies: strategyMap,
|
|
95
96
|
isolationMode: isolationPolicy.selected,
|
|
96
97
|
cleanupWorktrees: input.cleanupWorktrees ?? !input.keepWorktrees,
|
|
97
|
-
baseCommit
|
|
98
|
+
baseCommit,
|
|
99
|
+
health: healthTracker
|
|
98
100
|
});
|
|
99
101
|
for (const trace of poolResult.traces) {
|
|
100
102
|
traceState = recordWorkerTrace(traceState, trace);
|
|
@@ -112,6 +114,7 @@ export async function runGlmNarutoMission(input) {
|
|
|
112
114
|
let envelopes = poolResult.envelopes;
|
|
113
115
|
let failedShardIds = poolResult.failedShardIds;
|
|
114
116
|
let repairWaves = 0;
|
|
117
|
+
let schedulerSummary = poolResult.schedulerSummary;
|
|
115
118
|
// Repair wave if needed
|
|
116
119
|
if (failedShardIds.length > 0 && repairWaves < GLM_NARUTO_LIMITS.max_repair_waves) {
|
|
117
120
|
const repairPlan = planRepairWave({
|
|
@@ -132,9 +135,15 @@ export async function runGlmNarutoMission(input) {
|
|
|
132
135
|
strategies: new Map(repairPlan.shardsToRepair.map((s) => [s.id, [s.strategy]])),
|
|
133
136
|
isolationMode: isolationPolicy.selected,
|
|
134
137
|
cleanupWorktrees: input.cleanupWorktrees ?? !input.keepWorktrees,
|
|
135
|
-
baseCommit
|
|
138
|
+
baseCommit,
|
|
139
|
+
health: healthTracker
|
|
136
140
|
});
|
|
137
141
|
envelopes = [...envelopes, ...repairPool.envelopes];
|
|
142
|
+
schedulerSummary = {
|
|
143
|
+
max_observed_active_workers: Math.max(schedulerSummary.max_observed_active_workers, repairPool.schedulerSummary.max_observed_active_workers),
|
|
144
|
+
backpressure_events: schedulerSummary.backpressure_events + repairPool.schedulerSummary.backpressure_events,
|
|
145
|
+
queue_drained: schedulerSummary.queue_drained && repairPool.schedulerSummary.queue_drained
|
|
146
|
+
};
|
|
138
147
|
for (const trace of repairPool.traces) {
|
|
139
148
|
traceState = recordWorkerTrace(traceState, trace);
|
|
140
149
|
}
|
|
@@ -229,7 +238,10 @@ export async function runGlmNarutoMission(input) {
|
|
|
229
238
|
missionId,
|
|
230
239
|
envelopes,
|
|
231
240
|
selectedPatchIds: mergePlan.selected_patches,
|
|
232
|
-
artifactDir
|
|
241
|
+
artifactDir,
|
|
242
|
+
...(input.allowDirtyApply !== undefined ? { allowDirtyApply: input.allowDirtyApply } : {}),
|
|
243
|
+
...(input.noRollback !== undefined ? { noRollback: input.noRollback } : {}),
|
|
244
|
+
...(input.strictChecks !== undefined ? { strictChecks: input.strictChecks } : {})
|
|
233
245
|
});
|
|
234
246
|
applyTransaction = transactionResult.transaction;
|
|
235
247
|
appliedPatches = transactionResult.ok ? transactionResult.applied.length : 0;
|
|
@@ -300,13 +312,33 @@ export async function runGlmNarutoMission(input) {
|
|
|
300
312
|
findings: [`audit_failed:${err instanceof Error ? err.message : String(err)}`]
|
|
301
313
|
}));
|
|
302
314
|
await writeJsonAtomic(path.join(writtenArtifactDir, 'secret-audit.json'), secretAudit).catch(() => undefined);
|
|
315
|
+
const predictedStopGatePath = path.join(cwd, '.sneakoscope', 'missions', missionId, 'stop-gate.json');
|
|
316
|
+
const finalSeal = await writeGlmNarutoFinalSeal({
|
|
317
|
+
artifactDir: writtenArtifactDir,
|
|
318
|
+
missionId,
|
|
319
|
+
result,
|
|
320
|
+
envelopes,
|
|
321
|
+
traces: traceState.workerTraces,
|
|
322
|
+
isolationPolicy,
|
|
323
|
+
scheduler: schedulerSummary,
|
|
324
|
+
selectedPatchIds: mergePlan.selected_patches,
|
|
325
|
+
applyTransaction,
|
|
326
|
+
secretAudit,
|
|
327
|
+
stopGatePath: predictedStopGatePath,
|
|
328
|
+
stopGatePassed: result.ok && secretAudit.ok
|
|
329
|
+
}).catch((err) => ({
|
|
330
|
+
seal: null,
|
|
331
|
+
path: path.join(writtenArtifactDir, 'final-seal.json'),
|
|
332
|
+
passed: false,
|
|
333
|
+
error: err instanceof Error ? err.message : String(err)
|
|
334
|
+
}));
|
|
303
335
|
// 4.0.9: Write canonical stop-gate artifacts for hook resolution.
|
|
304
336
|
await writeFinalStopGate({
|
|
305
337
|
root: cwd,
|
|
306
338
|
missionId,
|
|
307
339
|
route: 'GLM_NARUTO',
|
|
308
340
|
routeCommand: '$Naruto',
|
|
309
|
-
status: result.ok && secretAudit.ok ? 'passed' : (terminalState === 'blocked' || !secretAudit.ok ? 'blocked' : 'failed'),
|
|
341
|
+
status: result.ok && secretAudit.ok && finalSeal.passed ? 'passed' : (terminalState === 'blocked' || !secretAudit.ok || !finalSeal.passed ? 'blocked' : 'failed'),
|
|
310
342
|
terminal: terminalState === 'completed' || terminalState === 'blocked',
|
|
311
343
|
terminalState,
|
|
312
344
|
evidence: {
|
|
@@ -316,12 +348,16 @@ export async function runGlmNarutoMission(input) {
|
|
|
316
348
|
per_worker_artifacts: true,
|
|
317
349
|
verifier_wave_run: verifierWaveRun,
|
|
318
350
|
model_guard_enforced: true,
|
|
351
|
+
final_seal_passed: finalSeal.passed,
|
|
352
|
+
final_seal_path: finalSeal.path,
|
|
319
353
|
proof_required: false,
|
|
320
354
|
proof_passed: true,
|
|
321
355
|
reflection_required: false,
|
|
322
356
|
reflection_passed: 'not_required',
|
|
323
357
|
},
|
|
324
|
-
blockers: secretAudit.ok
|
|
358
|
+
blockers: secretAudit.ok
|
|
359
|
+
? (finalSeal.passed ? (result.blockers || []) : [...(result.blockers || []), 'glm_naruto_final_seal_not_passed'])
|
|
360
|
+
: ['glm_naruto_secret_leak_detected'],
|
|
325
361
|
nativeGateFile: 'termination.json',
|
|
326
362
|
}).catch(() => null);
|
|
327
363
|
return { ...result, artifact_dir: writtenArtifactDir };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import fsp from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { exists, writeJsonAtomic } from '../../../fsx.js';
|
|
5
|
+
export async function runGlmNarutoTargetedChecks(input) {
|
|
6
|
+
const checks = [];
|
|
7
|
+
const touchedPaths = [...new Set(input.touchedPaths)].sort();
|
|
8
|
+
const diffCheck = await runProcess(input.cwd, ['git', 'diff', '--check']);
|
|
9
|
+
checks.push({
|
|
10
|
+
id: 'git_diff_check',
|
|
11
|
+
ok: diffCheck.code === 0,
|
|
12
|
+
command: ['git', 'diff', '--check'],
|
|
13
|
+
...(diffCheck.code === 0 ? {} : { message: diffCheck.stderr || diffCheck.stdout || 'git diff --check failed' })
|
|
14
|
+
});
|
|
15
|
+
for (const rel of touchedPaths.filter((file) => /\.(?:json)$/i.test(file))) {
|
|
16
|
+
const absolute = path.join(input.cwd, rel);
|
|
17
|
+
try {
|
|
18
|
+
JSON.parse(await fsp.readFile(absolute, 'utf8'));
|
|
19
|
+
checks.push({ id: 'json_parse', ok: true, path: rel });
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
checks.push({ id: 'json_parse', ok: false, path: rel, message: err instanceof Error ? err.message : String(err) });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
for (const rel of touchedPaths.filter((file) => /\.(?:js|mjs|cjs)$/i.test(file))) {
|
|
26
|
+
const nodeCheck = await runProcess(input.cwd, ['node', '--check', rel]);
|
|
27
|
+
checks.push({
|
|
28
|
+
id: 'node_check',
|
|
29
|
+
ok: nodeCheck.code === 0,
|
|
30
|
+
path: rel,
|
|
31
|
+
command: ['node', '--check', rel],
|
|
32
|
+
...(nodeCheck.code === 0 ? {} : { message: nodeCheck.stderr || nodeCheck.stdout || 'node --check failed' })
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const tsTouched = touchedPaths.filter((file) => /\.(?:ts|tsx)$/i.test(file));
|
|
36
|
+
const tscThreshold = input.tscFileThreshold ?? 3;
|
|
37
|
+
if (tsTouched.length > 0 && (input.strictChecks || tsTouched.length <= tscThreshold)) {
|
|
38
|
+
const tscBin = path.join(input.cwd, 'node_modules', '.bin', 'tsc');
|
|
39
|
+
const tsconfig = path.join(input.cwd, 'tsconfig.json');
|
|
40
|
+
if (await exists(tscBin) && await exists(tsconfig)) {
|
|
41
|
+
const tsc = await runProcess(input.cwd, [tscBin, '-p', 'tsconfig.json', '--noEmit']);
|
|
42
|
+
checks.push({
|
|
43
|
+
id: 'tsc_no_emit',
|
|
44
|
+
ok: tsc.code === 0,
|
|
45
|
+
command: [tscBin, '-p', 'tsconfig.json', '--noEmit'],
|
|
46
|
+
...(tsc.code === 0 ? {} : { message: tsc.stderr || tsc.stdout || 'tsc --noEmit failed' })
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
checks.push({ id: 'tsc_no_emit', ok: true, skipped: true, message: 'tsc_or_tsconfig_unavailable' });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const blockers = checks.filter((check) => !check.ok).map((check) => `${check.id}${check.path ? `:${check.path}` : ''}`);
|
|
54
|
+
const result = {
|
|
55
|
+
schema: 'sks.glm-naruto-targeted-checks.v1',
|
|
56
|
+
ok: blockers.length === 0,
|
|
57
|
+
touched_paths: touchedPaths,
|
|
58
|
+
checks,
|
|
59
|
+
blockers
|
|
60
|
+
};
|
|
61
|
+
if (input.artifactDir)
|
|
62
|
+
await writeJsonAtomic(path.join(input.artifactDir, 'targeted-checks.json'), result);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
function runProcess(cwd, command) {
|
|
66
|
+
return new Promise((resolve) => {
|
|
67
|
+
const child = spawn(command[0], command.slice(1), { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
68
|
+
let stdout = '';
|
|
69
|
+
let stderr = '';
|
|
70
|
+
child.stdout.on('data', (chunk) => { stdout += String(chunk); });
|
|
71
|
+
child.stderr.on('data', (chunk) => { stderr += String(chunk); });
|
|
72
|
+
child.on('close', (code) => resolve({ code, stdout, stderr }));
|
|
73
|
+
child.on('error', (err) => resolve({ code: 1, stdout, stderr: err.message }));
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=glm-naruto-targeted-checks.js.map
|
|
@@ -40,6 +40,14 @@ export async function writeMissionArtifacts(input) {
|
|
|
40
40
|
await writeJsonAtomic(path.join(dir, 'apply-result.json'), sanitizeArtifact(input.applyResult));
|
|
41
41
|
if (input.applyTransaction)
|
|
42
42
|
await writeJsonAtomic(path.join(dir, 'apply-transaction.json'), sanitizeArtifact(input.applyTransaction));
|
|
43
|
+
if (input.mergePlan) {
|
|
44
|
+
await writeTextAtomic(path.join(dir, 'merge-rationale.md'), renderMergeRationale({
|
|
45
|
+
mergePlan: input.mergePlan,
|
|
46
|
+
conflictGraph: input.conflictGraph,
|
|
47
|
+
candidateScoreboard: input.candidateScoreboard,
|
|
48
|
+
applyTransaction: input.applyTransaction
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
43
51
|
if (input.verificationSummary)
|
|
44
52
|
await writeJsonAtomic(path.join(dir, 'verification-summary.json'), sanitizeArtifact(input.verificationSummary));
|
|
45
53
|
if (input.missionResult)
|
|
@@ -85,6 +93,48 @@ export async function writeMissionArtifacts(input) {
|
|
|
85
93
|
}
|
|
86
94
|
return dir;
|
|
87
95
|
}
|
|
96
|
+
function renderMergeRationale(input) {
|
|
97
|
+
const plan = input.mergePlan;
|
|
98
|
+
const graph = input.conflictGraph;
|
|
99
|
+
const scoreboard = input.candidateScoreboard;
|
|
100
|
+
const tx = input.applyTransaction;
|
|
101
|
+
const selected = Array.isArray(plan?.selected_patches) ? plan.selected_patches : [];
|
|
102
|
+
const scores = Array.isArray(scoreboard?.scores) ? scoreboard.scores : [];
|
|
103
|
+
const edges = Array.isArray(graph?.edges) ? graph.edges : [];
|
|
104
|
+
const rejected = scores
|
|
105
|
+
.filter((score) => !selected.includes(score.patch_id))
|
|
106
|
+
.map((score) => `- ${score.patch_id}: score=${score.total_score}; disqualified=${Boolean(score.disqualified)}; reasons=${(score.disqualification_reasons || []).join(', ') || 'none'}`);
|
|
107
|
+
const selectedRows = selected.map((patchId) => {
|
|
108
|
+
const score = scores.find((row) => row.patch_id === patchId);
|
|
109
|
+
return `- ${patchId}: score=${score?.total_score ?? 'n/a'}; components=${JSON.stringify(score?.components ?? {})}`;
|
|
110
|
+
});
|
|
111
|
+
const conflictRows = edges.map((edge) => `- ${edge.left_patch_id} vs ${edge.right_patch_id}: ${edge.reason}`);
|
|
112
|
+
return [
|
|
113
|
+
'# GLM Naruto Merge Rationale',
|
|
114
|
+
'',
|
|
115
|
+
`Mission: ${plan?.mission_id ?? 'unknown'}`,
|
|
116
|
+
`Strategy: ${plan?.strategy ?? 'unknown'}`,
|
|
117
|
+
`Rationale: ${plan?.rationale ?? 'not_recorded'}`,
|
|
118
|
+
'',
|
|
119
|
+
'## Selected Patch IDs',
|
|
120
|
+
selectedRows.length ? selectedRows.join('\n') : '- none',
|
|
121
|
+
'',
|
|
122
|
+
'## Rejected Patch IDs',
|
|
123
|
+
rejected.length ? rejected.join('\n') : '- none',
|
|
124
|
+
'',
|
|
125
|
+
'## Conflicts',
|
|
126
|
+
conflictRows.length ? conflictRows.join('\n') : '- none',
|
|
127
|
+
'',
|
|
128
|
+
'## Apply Transaction',
|
|
129
|
+
`- final_status: ${tx?.final_status ?? 'not_attempted'}`,
|
|
130
|
+
`- apply_passed: ${tx?.apply_passed ?? false}`,
|
|
131
|
+
`- targeted_checks_passed: ${tx?.targeted_checks_passed ?? null}`,
|
|
132
|
+
`- rollback_attempted: ${tx?.rollback_attempted ?? false}`,
|
|
133
|
+
`- rollback_passed: ${tx?.rollback_passed ?? null}`,
|
|
134
|
+
`- blockers: ${(tx?.blockers || []).join(', ') || 'none'}`,
|
|
135
|
+
''
|
|
136
|
+
].join('\n');
|
|
137
|
+
}
|
|
88
138
|
function sanitizeArtifact(value) {
|
|
89
139
|
return JSON.parse(JSON.stringify(value, (key, raw) => {
|
|
90
140
|
if (isSecretLikeKey(key) && typeof raw === 'string' && raw.trim() && !isAllowedRedaction(raw))
|