sneakoscope 4.8.7 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -726
- package/config/bench-baseline.json +7 -0
- 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/install.js +35 -0
- package/dist/bin/sks.js +1 -1
- package/dist/cli/cli-theme.js +51 -0
- package/dist/cli/command-registry.js +15 -4
- package/dist/cli/help-fast.js +18 -8
- package/dist/cli/insane-search-command.js +36 -8
- package/dist/cli/install-helpers.js +32 -0
- package/dist/commands/codex-lb.js +2 -0
- package/dist/commands/doctor.js +94 -9
- package/dist/commands/proof.js +6 -3
- package/dist/config/skills-manifest.json +82 -54
- package/dist/core/agents/agent-conflict-graph.js +5 -0
- package/dist/core/agents/agent-lease.js +5 -0
- package/dist/core/agents/agent-ledger-schemas.js +1 -0
- package/dist/core/agents/agent-lifecycle.js +5 -3
- package/dist/core/agents/agent-orchestrator.js +268 -62
- package/dist/core/agents/agent-output-validator.js +14 -3
- package/dist/core/agents/agent-patch-queue-store.js +95 -2
- package/dist/core/agents/agent-patch-queue.js +6 -3
- package/dist/core/agents/agent-patch-schema.js +13 -0
- package/dist/core/agents/agent-proof-evidence.js +6 -1
- package/dist/core/agents/agent-runner-fake.js +40 -0
- package/dist/core/agents/agent-worker-pipeline.js +36 -2
- package/dist/core/agents/codex-exec-worker-adapter.js +2 -0
- package/dist/core/agents/native-cli-worker.js +0 -1
- package/dist/core/agents/native-worker-backend-router.js +58 -1
- package/dist/core/codex-app/sks-menubar.js +477 -132
- package/dist/core/codex-app.js +1 -0
- package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
- package/dist/core/codex-control/codex-sdk-env-policy.js +1 -1
- package/dist/core/codex-control/schemas/agent-worker-result.schema.js +12 -3
- package/dist/core/codex-hooks/codex-hook-managed-install.js +5 -0
- package/dist/core/codex-hooks/codex-hook-state-writer.js +70 -11
- package/dist/core/codex-hooks/codex-hook-trust-doctor.js +2 -2
- package/dist/core/codex-lb/codex-lb-env.js +20 -1
- package/dist/core/commands/basic-cli.js +18 -1
- package/dist/core/commands/check-command.js +37 -5
- package/dist/core/commands/computer-use-command.js +62 -7
- package/dist/core/commands/db-command.js +31 -5
- package/dist/core/commands/fast-mode-command.js +3 -0
- package/dist/core/commands/gate-result-contract.js +43 -0
- package/dist/core/commands/gates-command.js +6 -1
- package/dist/core/commands/gc-command.js +29 -2
- package/dist/core/commands/goal-command.js +9 -2
- package/dist/core/commands/gx-command.js +79 -7
- package/dist/core/commands/image-ux-review-command.js +188 -13
- package/dist/core/commands/mad-db-command.js +85 -176
- package/dist/core/commands/mad-sks-command.js +230 -29
- package/dist/core/commands/menubar-command.js +24 -2
- package/dist/core/commands/naruto-command.js +64 -10
- package/dist/core/commands/plan-command.js +76 -0
- package/dist/core/commands/ppt-command.js +159 -24
- package/dist/core/commands/qa-loop-command.js +6 -2
- package/dist/core/commands/release-command.js +55 -2
- package/dist/core/commands/research-command.js +1 -1
- package/dist/core/commands/review-command.js +217 -0
- package/dist/core/commands/route-success-helpers.js +59 -0
- package/dist/core/commands/run-command.js +19 -7
- package/dist/core/commands/seo-command.js +49 -1
- package/dist/core/commands/ui-command.js +161 -0
- package/dist/core/commands/uninstall-command.js +15 -1
- package/dist/core/db-safety.js +2 -2
- package/dist/core/doctor/doctor-dirty-planner.js +51 -7
- package/dist/core/doctor/doctor-transaction.js +8 -0
- package/dist/core/doctor/doctor-zellij-repair.js +1 -0
- package/dist/core/doctor/imagegen-repair.js +161 -0
- package/dist/core/feature-fixture-runner.js +2 -2
- package/dist/core/feature-fixtures.js +58 -37
- package/dist/core/feature-registry.js +102 -2
- package/dist/core/fsx.js +39 -6
- package/dist/core/image-ux-review/imagegen-adapter.js +48 -11
- package/dist/core/image-ux-review.js +16 -0
- package/dist/core/imagegen/imagegen-capability.js +11 -5
- package/dist/core/imagegen/require-imagegen.js +57 -0
- package/dist/core/init/skills.js +10 -5
- package/dist/core/mad-db/mad-db-coordinator.js +94 -18
- package/dist/core/mad-db/mad-db-policy.js +12 -10
- package/dist/core/mad-sks/executors/executor-base.js +8 -2
- package/dist/core/mad-sks/executors/index.js +4 -0
- package/dist/core/mad-sks/executors/sql-plane-executor.js +194 -0
- package/dist/core/naruto/naruto-active-pool.js +15 -4
- package/dist/core/naruto/naruto-real-worker-child.js +11 -1
- package/dist/core/naruto/naruto-role-policy.js +3 -0
- package/dist/core/naruto/naruto-task-hints.js +10 -0
- package/dist/core/naruto/naruto-work-graph.js +8 -2
- package/dist/core/naruto/naruto-work-item.js +6 -0
- package/dist/core/naruto/solution-tournament.js +101 -0
- package/dist/core/permission-gates.js +30 -0
- package/dist/core/pipeline-internals/runtime-core.js +11 -3
- package/dist/core/pipeline-internals/runtime-gates.js +27 -0
- package/dist/core/ppt-review/index.js +6 -1
- package/dist/core/ppt-review/slide-imagegen-review.js +75 -10
- package/dist/core/ppt.js +70 -2
- package/dist/core/proof/auto-finalize.js +70 -11
- package/dist/core/proof/proof-schema.js +2 -0
- package/dist/core/proof/route-adapter.js +5 -1
- package/dist/core/proof/route-finalizer.js +8 -5
- package/dist/core/proof/selftest-proof-fixtures.js +18 -5
- package/dist/core/proof/validation.js +2 -0
- package/dist/core/provider/model-router.js +53 -0
- package/dist/core/release/release-gate-node.js +3 -0
- package/dist/core/release/release-gate-resource-governor.js +1 -0
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes.js +65 -18
- package/dist/core/safety/mutation-guard.js +5 -1
- package/dist/core/stop-gate/gate-evaluator.js +102 -0
- package/dist/core/stop-gate/stop-gate-check.js +16 -1
- package/dist/core/stop-gate/stop-gate-writer.js +4 -0
- package/dist/core/triwiki/agents-md-projector.js +184 -0
- package/dist/core/triwiki-wrongness/wrongness-schema.js +3 -1
- package/dist/core/trust-kernel/trust-kernel-schema.js +1 -0
- package/dist/core/trust-kernel/trust-report.js +1 -1
- package/dist/core/trust-kernel/trust-status.js +2 -0
- package/dist/core/ui/dashboard-html.js +111 -0
- package/dist/core/update/update-migration-state.js +386 -15
- package/dist/core/update-check.js +178 -81
- package/dist/core/verification/diff-quality.js +100 -0
- package/dist/core/verification/impact-scan.js +164 -0
- package/dist/core/verification/machine-feedback.js +146 -0
- package/dist/core/verification/mistake-rule-compiler.js +195 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-self-heal.js +9 -6
- package/dist/core/zellij/zellij-slot-telemetry.js +1 -1
- package/dist/scripts/check-feature-quality.js +2 -2
- package/dist/scripts/cli-output-consistency-check.js +57 -0
- package/dist/scripts/coding-bench-check.js +136 -0
- package/dist/scripts/doctor-imagegen-repair-check.js +62 -0
- package/dist/scripts/ensure-bin-executable.js +11 -3
- package/dist/scripts/harness-benchmark-check.js +104 -0
- package/dist/scripts/legacy-update-e2e-check.js +228 -0
- package/dist/scripts/mad-db-command-check.js +11 -8
- package/dist/scripts/mad-db-route-identity-check.js +8 -6
- package/dist/scripts/mad-db-safety-conflict-matrix-check.js +31 -8
- package/dist/scripts/mad-db-skill-policy-snapshot-check.js +4 -5
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +26 -1
- package/dist/scripts/ppt-real-imagegen-wiring-check.js +5 -1
- package/dist/scripts/proof-root-cause-policy-check.js +2 -0
- package/dist/scripts/release-dag-full-coverage-check.js +13 -4
- package/dist/scripts/release-gate-dag-runner.js +14 -0
- package/dist/scripts/release-gate-existence-audit.js +2 -1
- package/dist/scripts/release-gate-planner.js +2 -1
- package/dist/scripts/release-gate-script-parity-check.js +45 -17
- package/dist/scripts/release-metadata-1-19-check.js +2 -1
- package/dist/scripts/seo-geo-feature-fixture-quality-check.js +1 -1
- package/dist/scripts/sks-1-11-gate-lib.js +8 -6
- package/dist/scripts/sks-menubar-install-check.js +57 -20
- package/dist/scripts/ux-review-real-loop-fixture-check.js +9 -4
- package/dist/scripts/ux-review-run-wires-imagegen-check.js +4 -0
- package/dist/scripts/zellij-slot-telemetry-runtime-check.js +1 -0
- package/docs/assets/sneakoscope-architecture-pipeline.jpg +0 -0
- package/docs/demo.tape +28 -0
- package/package.json +31 -24
- package/schemas/codex/completion-proof.schema.json +3 -2
- package/schemas/release/release-gate-node.schema.json +2 -1
- package/dist/scripts/agent-backfill-route-blackbox.js +0 -5
- package/dist/scripts/agent-dynamic-pool-route-blackbox.js +0 -5
- package/dist/scripts/agent-parallel-write-blackbox.js +0 -56
- package/dist/scripts/agent-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/agent-route-blackbox-lib.js +0 -132
- package/dist/scripts/blackbox-command-import-smoke.js +0 -143
- package/dist/scripts/blackbox-global-shim.js +0 -77
- package/dist/scripts/blackbox-matrix.js +0 -70
- package/dist/scripts/blackbox-npx-one-shot.js +0 -69
- package/dist/scripts/blackbox-pack-install.js +0 -174
- package/dist/scripts/brand-neutrality-zero-leakage-blackbox.js +0 -4
- package/dist/scripts/build-once-runner-blackbox.js +0 -34
- package/dist/scripts/codex-0140-integration-blackbox.js +0 -13
- package/dist/scripts/codex-agent-type-blackbox.js +0 -4
- package/dist/scripts/codex-app-harness-blackbox.js +0 -4
- package/dist/scripts/codex-app-skill-agent-blackbox.js +0 -4
- package/dist/scripts/codex-hook-approval-blackbox.js +0 -4
- package/dist/scripts/codex-init-deep-directory-local-blackbox.js +0 -4
- package/dist/scripts/codex-native-feature-broker-blackbox.js +0 -4
- package/dist/scripts/codex-native-pattern-analysis-blackbox.js +0 -4
- package/dist/scripts/codex-native-read-repair-split-blackbox.js +0 -55
- package/dist/scripts/codex-native-reference-cache-blackbox.js +0 -41
- package/dist/scripts/core-skill-integrity-blackbox.js +0 -32
- package/dist/scripts/dfix-fast-blackbox-check.js +0 -37
- package/dist/scripts/dfix-parallel-write-blackbox.js +0 -48
- package/dist/scripts/dfix-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/doctor-dirty-repair-blackbox.js +0 -22
- package/dist/scripts/doctor-dirty-semantic-blackbox.js +0 -8
- package/dist/scripts/doctor-native-capability-repair-blackbox.js +0 -39
- package/dist/scripts/doctor-transaction-engine-blackbox.js +0 -28
- package/dist/scripts/doctor-zellij-fix-blackbox.js +0 -4
- package/dist/scripts/doctor-zellij-no-homebrew-blackbox.js +0 -4
- package/dist/scripts/doctor-zellij-upgrade-blackbox.js +0 -4
- package/dist/scripts/gate-pack-runner-blackbox.js +0 -27
- package/dist/scripts/gate-pack-v2-blackbox.js +0 -18
- package/dist/scripts/geo-cli-blackbox-check.js +0 -18
- package/dist/scripts/loop-collision-blackbox.js +0 -3
- package/dist/scripts/loop-concurrency-oversubscription-blackbox.js +0 -3
- package/dist/scripts/loop-fixture-production-misuse-blackbox.js +0 -3
- package/dist/scripts/loop-kill-interrupt-real-blackbox.js +0 -3
- package/dist/scripts/loop-merge-strategy-blackbox.js +0 -3
- package/dist/scripts/loop-mesh-production-e2e-blackbox.js +0 -3
- package/dist/scripts/loop-side-effect-blackbox.js +0 -3
- package/dist/scripts/mad-db-operation-lifecycle-blackbox.js +0 -29
- package/dist/scripts/mad-sks-actual-executor-blackbox.js +0 -5
- package/dist/scripts/mad-zellij-headless-fallback-blackbox.js +0 -4
- package/dist/scripts/mad-zellij-self-heal-blackbox.js +0 -4
- package/dist/scripts/naruto-loop-mesh-blackbox.js +0 -3
- package/dist/scripts/naruto-real-parallelism-blackbox.js +0 -307
- package/dist/scripts/naruto-worktree-coding-blackbox.js +0 -29
- package/dist/scripts/parallel-runtime-real-blackbox.js +0 -44
- package/dist/scripts/pipeline-codex-native-doctor-mad-routing-real-blackbox.js +0 -77
- package/dist/scripts/pipeline-codex-native-e2e-blackbox.js +0 -13
- package/dist/scripts/pipeline-codex-native-image-routing-real-blackbox.js +0 -50
- package/dist/scripts/pipeline-codex-native-loop-routing-real-blackbox.js +0 -74
- package/dist/scripts/pipeline-codex-native-qa-routing-real-blackbox.js +0 -51
- package/dist/scripts/pipeline-codex-native-research-routing-real-blackbox.js +0 -45
- package/dist/scripts/pipeline-execution-profile-routing-blackbox.js +0 -4
- package/dist/scripts/postinstall-global-doctor-blackbox.js +0 -12
- package/dist/scripts/ppt-full-e2e-blackbox-check.js +0 -109
- package/dist/scripts/ppt-imagegen-blackbox-check.js +0 -46
- package/dist/scripts/qa-backfill-route-blackbox.js +0 -5
- package/dist/scripts/qa-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/release-full-parallelism-blackbox.js +0 -41
- package/dist/scripts/release-triwiki-first-runner-blackbox.js +0 -48
- package/dist/scripts/release-wiring-3110-blackbox.js +0 -27
- package/dist/scripts/release-wiring-3112-blackbox.js +0 -17
- package/dist/scripts/release-wiring-3113-blackbox.js +0 -17
- package/dist/scripts/research-backfill-route-blackbox.js +0 -5
- package/dist/scripts/research-final-reviewer-blackbox.js +0 -70
- package/dist/scripts/research-stage-cycle-runtime-blackbox.js +0 -40
- package/dist/scripts/research-synthesis-writer-blackbox.js +0 -24
- package/dist/scripts/route-blackbox-realism-check.js +0 -21
- package/dist/scripts/scheduler-resource-claim-blackbox.js +0 -24
- package/dist/scripts/seo-cli-blackbox-check.js +0 -18
- package/dist/scripts/sks-3110-all-feature-regression-blackbox.js +0 -116
- package/dist/scripts/sks-3112-all-feature-regression-blackbox.js +0 -29
- package/dist/scripts/sks-3113-all-feature-regression-blackbox.js +0 -17
- package/dist/scripts/sks-400-all-feature-regression-blackbox.js +0 -21
- package/dist/scripts/sks-400-extreme-parallel-blackbox.js +0 -8
- package/dist/scripts/sks-400-five-minute-blackbox.js +0 -9
- package/dist/scripts/sks-400-legacy-purge-blackbox.js +0 -8
- package/dist/scripts/sks-401-all-feature-regression-blackbox.js +0 -46
- package/dist/scripts/sks-401-five-minute-actual-blackbox.js +0 -23
- package/dist/scripts/sks-402-all-feature-regression-blackbox.js +0 -9
- package/dist/scripts/sks-402-five-minute-real-blackbox.js +0 -22
- package/dist/scripts/sksd-warm-cache-blackbox.js +0 -12
- package/dist/scripts/team-backfill-route-blackbox.js +0 -5
- package/dist/scripts/team-parallel-write-blackbox.js +0 -55
- package/dist/scripts/team-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/triwiki-affected-graph-blackbox.js +0 -28
- package/dist/scripts/triwiki-proof-bank-blackbox.js +0 -30
- package/dist/scripts/triwiki-proof-bank-lock-blackbox.js +0 -7
- package/dist/scripts/ux-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/ux-review-imagegen-blackbox-check.js +0 -67
- package/dist/scripts/zellij-initial-main-only-blackbox.js +0 -28
- package/dist/scripts/zellij-pane-lock-concurrency-blackbox.js +0 -80
- package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +0 -137
- package/dist/scripts/zellij-self-heal-typed-blackbox.js +0 -4
- package/dist/scripts/zellij-slot-telemetry-real-blackbox.js +0 -20
- package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +0 -81
- package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +0 -202
|
@@ -264,6 +264,7 @@ export function simulateNarutoActivePool(input) {
|
|
|
264
264
|
let maxObserved = 0;
|
|
265
265
|
let maxObservedWriteLeaseConflicts = 0;
|
|
266
266
|
let conflictItemsEnqueued = 0;
|
|
267
|
+
const repairWaves = [];
|
|
267
268
|
while (pending.length || active.size) {
|
|
268
269
|
let launched = 0;
|
|
269
270
|
for (;;) {
|
|
@@ -293,7 +294,15 @@ export function simulateNarutoActivePool(input) {
|
|
|
293
294
|
if (shouldFail) {
|
|
294
295
|
failed.add(generation.work_item_id);
|
|
295
296
|
conflictItemsEnqueued += 1;
|
|
296
|
-
const
|
|
297
|
+
const attempt = executed.get(generation.work_item_id) || 1;
|
|
298
|
+
const followup = conflictResolutionFollowup(generation.work_item_id, input.graph.work_items.length + conflictItemsEnqueued, attempt);
|
|
299
|
+
repairWaves.push({
|
|
300
|
+
failed_work_item_id: generation.work_item_id,
|
|
301
|
+
followup_work_item_id: followup.id,
|
|
302
|
+
attempt,
|
|
303
|
+
requires_hypothesis: true,
|
|
304
|
+
tournament_forced: Boolean(followup.tournament && followup.tournament >= 2)
|
|
305
|
+
});
|
|
297
306
|
pending.push(followup);
|
|
298
307
|
byId.set(followup.id, followup);
|
|
299
308
|
}
|
|
@@ -325,6 +334,7 @@ export function simulateNarutoActivePool(input) {
|
|
|
325
334
|
duplicate_execution_count: duplicateExecutionCount,
|
|
326
335
|
conflict_items_enqueued: conflictItemsEnqueued,
|
|
327
336
|
max_observed_write_lease_conflicts: maxObservedWriteLeaseConflicts,
|
|
337
|
+
repair_waves: repairWaves,
|
|
328
338
|
timeline,
|
|
329
339
|
blockers
|
|
330
340
|
};
|
|
@@ -359,12 +369,12 @@ function countActiveWriteLeaseConflicts(active, byId) {
|
|
|
359
369
|
}
|
|
360
370
|
return [...counts.values()].filter((count) => count > 1).reduce((sum, count) => sum + count - 1, 0);
|
|
361
371
|
}
|
|
362
|
-
function conflictResolutionFollowup(failedId, index) {
|
|
372
|
+
function conflictResolutionFollowup(failedId, index, attempt = 1) {
|
|
363
373
|
const id = `NW-CONFLICT-${String(index).padStart(4, '0')}`;
|
|
364
374
|
return {
|
|
365
375
|
id,
|
|
366
376
|
kind: 'conflict_resolution',
|
|
367
|
-
title: `Resolve failed work item ${failedId}`,
|
|
377
|
+
title: `Resolve failed work item ${failedId} with repair-hypothesis.json before patching`,
|
|
368
378
|
target_paths: [],
|
|
369
379
|
readonly_paths: [],
|
|
370
380
|
write_paths: [`.sneakoscope/naruto/conflicts/${id}.json`],
|
|
@@ -376,7 +386,8 @@ function conflictResolutionFollowup(failedId, index) {
|
|
|
376
386
|
conflicts_with: [],
|
|
377
387
|
estimated_cost: { tokens: 4000, latency_ms: 45000, cpu_weight: 1, memory_mb: 256, gpu_weight: 0 },
|
|
378
388
|
lease_requirements: [{ path: `.sneakoscope/naruto/conflicts/${id}.json`, kind: 'write' }],
|
|
379
|
-
acceptance: { requires_patch_envelope: true, requires_verification: true, requires_gpt_final: true }
|
|
389
|
+
acceptance: { requires_patch_envelope: true, requires_verification: true, requires_gpt_final: true },
|
|
390
|
+
...(attempt >= 3 ? { tournament: 3 } : {})
|
|
380
391
|
};
|
|
381
392
|
}
|
|
382
393
|
//# sourceMappingURL=naruto-active-pool.js.map
|
|
@@ -136,7 +136,7 @@ function startDeadmanHeartbeat(input) {
|
|
|
136
136
|
schema: 'sks.naruto-actual-worker-heartbeat.v1',
|
|
137
137
|
ts: nowIso(),
|
|
138
138
|
item_id: input.intake.item.id,
|
|
139
|
-
status: '
|
|
139
|
+
status: 'timed_out',
|
|
140
140
|
elapsed_ms: elapsedMs,
|
|
141
141
|
progress: null
|
|
142
142
|
}, 2 * 1024 * 1024).catch(() => undefined);
|
|
@@ -180,9 +180,19 @@ function buildNarutoWorkerPrompt(item, parentPrompt) {
|
|
|
180
180
|
writeAllowed
|
|
181
181
|
? 'If changes are needed, return model-authored patch_envelopes scoped to write paths.'
|
|
182
182
|
: 'This is read-only work. Do not mutate files and return an empty patch_envelopes array.',
|
|
183
|
+
writeAllowed
|
|
184
|
+
? 'Before changing exported signatures, inspect references and include cochanged callers in the same patch; only set cochange_acknowledged with a concrete compatibility reason.'
|
|
185
|
+
: null,
|
|
186
|
+
/bug|fix|regression|broken|버그|수정/i.test(String(item?.kind || '') + ' ' + String(item?.title || ''))
|
|
187
|
+
? 'Bugfix protocol: first add a regression test, record failed_before and passed_after in regression_proof, then patch the bug.'
|
|
188
|
+
: null,
|
|
189
|
+
/repair|conflict|fix/i.test(String(item?.kind || '') + ' ' + String(item?.title || ''))
|
|
190
|
+
? 'Repair protocol: write repair_hypothesis before patching, including failure, hypotheses, chosen evidence, and minimal_probe.'
|
|
191
|
+
: null,
|
|
183
192
|
writeAllowed
|
|
184
193
|
? null
|
|
185
194
|
: 'For read-only work, inspect requested files/artifacts only; do not run package scripts, build commands, tests, or temp-file-creating checks unless the parent objective explicitly requires them.',
|
|
195
|
+
'Impact scan, machine feedback, diff-quality, mistake-rule, TDD, and repair-hypothesis gates run before patch queue acceptance.',
|
|
186
196
|
'Include verification checks, rollback notes, blockers, findings, and changed_files.'
|
|
187
197
|
].filter(Boolean).join('\n');
|
|
188
198
|
}
|
|
@@ -17,6 +17,8 @@ export function narutoRoleAllowsWrite(role) {
|
|
|
17
17
|
}
|
|
18
18
|
export function mapWorkKindToNarutoRole(kind) {
|
|
19
19
|
switch (kind) {
|
|
20
|
+
case 'bugfix':
|
|
21
|
+
case 'feature':
|
|
20
22
|
case 'implementation':
|
|
21
23
|
return 'implementer';
|
|
22
24
|
case 'code_modification':
|
|
@@ -34,6 +36,7 @@ export function mapWorkKindToNarutoRole(kind) {
|
|
|
34
36
|
case 'research':
|
|
35
37
|
return 'researcher';
|
|
36
38
|
case 'documentation':
|
|
39
|
+
case 'chore':
|
|
37
40
|
return 'modifier';
|
|
38
41
|
case 'conflict_resolution':
|
|
39
42
|
return 'conflict_resolver';
|
|
@@ -38,6 +38,16 @@ export function pathPrefix(pathValue) {
|
|
|
38
38
|
return parts.slice(0, 3).join('/');
|
|
39
39
|
return parts.slice(0, 2).join('/');
|
|
40
40
|
}
|
|
41
|
+
export function classifyNarutoDeliveryKind(text) {
|
|
42
|
+
const hay = String(text || '').toLowerCase();
|
|
43
|
+
if (/(^|\b)(fix|bug|broken|regression|failure|failing|crash|error)(\b|$)|버그|고쳐|수정|회귀/.test(hay))
|
|
44
|
+
return 'bugfix';
|
|
45
|
+
if (/(^|\b)(refactor|cleanup|simplify|restructure)(\b|$)|리팩터|정리/.test(hay))
|
|
46
|
+
return 'refactor';
|
|
47
|
+
if (/(^|\b)(chore|docs?|config|metadata|version)(\b|$)|문서|설정/.test(hay))
|
|
48
|
+
return 'chore';
|
|
49
|
+
return 'feature';
|
|
50
|
+
}
|
|
41
51
|
function normalizePaths(paths) {
|
|
42
52
|
return [...new Set(paths.map((file) => normalizeNarutoPath(String(file || ''))).filter(Boolean))].sort();
|
|
43
53
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mapWorkKindToNarutoRole } from './naruto-role-policy.js';
|
|
2
2
|
import { isNarutoWriteKind, normalizeNarutoPath } from './naruto-work-item.js';
|
|
3
|
+
import { classifyNarutoDeliveryKind } from './naruto-task-hints.js';
|
|
3
4
|
const WRITE_CAPABLE_KIND_CYCLE = [
|
|
4
5
|
'implementation',
|
|
5
6
|
'code_modification',
|
|
@@ -53,7 +54,11 @@ export function buildNarutoWorkGraph(input = {}) {
|
|
|
53
54
|
}
|
|
54
55
|
for (let index = 0; index < totalWorkItems; index += 1) {
|
|
55
56
|
const id = `NW-${String(index + 1).padStart(6, '0')}`;
|
|
56
|
-
const
|
|
57
|
+
const baseKind = kindCycle[index % kindCycle.length] || 'verification';
|
|
58
|
+
const deliveryKind = classifyNarutoDeliveryKind(input.prompt || '');
|
|
59
|
+
const kind = writeCapable && index === 0 && ['implementation', 'code_modification', 'refactor'].includes(baseKind)
|
|
60
|
+
? deliveryKind
|
|
61
|
+
: baseKind;
|
|
57
62
|
const kindWrites = writeCapable && isNarutoWriteKind(kind);
|
|
58
63
|
const selectedTarget = targetPaths.length ? targetPaths[index % targetPaths.length] || targetPaths[0] || '' : `${basePath}/${id}.json`;
|
|
59
64
|
const writePaths = kindWrites ? [selectedTarget].filter(Boolean) : [];
|
|
@@ -95,7 +100,8 @@ export function buildNarutoWorkGraph(input = {}) {
|
|
|
95
100
|
required: worktreePolicy.required,
|
|
96
101
|
allocation_required: worktreePolicy.mode === 'git-worktree'
|
|
97
102
|
}
|
|
98
|
-
} : {})
|
|
103
|
+
} : {}),
|
|
104
|
+
...(writePaths.length > 0 && input.tournament && input.tournament >= 2 ? { tournament: Math.min(4, Math.max(2, Math.floor(input.tournament))) } : {})
|
|
99
105
|
});
|
|
100
106
|
}
|
|
101
107
|
const activeWaves = planNarutoWorkWaves(workItems, Math.max(1, normalizePositiveInt(input.maxActiveWorkers, requestedClones)));
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export const NARUTO_WORK_KINDS = [
|
|
2
|
+
'bugfix',
|
|
3
|
+
'feature',
|
|
2
4
|
'implementation',
|
|
3
5
|
'code_modification',
|
|
4
6
|
'refactor',
|
|
7
|
+
'chore',
|
|
5
8
|
'test_generation',
|
|
6
9
|
'test_execution',
|
|
7
10
|
'verification',
|
|
@@ -17,9 +20,12 @@ export const NARUTO_WORK_KINDS = [
|
|
|
17
20
|
'final_review_input_pack'
|
|
18
21
|
];
|
|
19
22
|
export const NARUTO_WRITE_WORK_KINDS = new Set([
|
|
23
|
+
'bugfix',
|
|
24
|
+
'feature',
|
|
20
25
|
'implementation',
|
|
21
26
|
'code_modification',
|
|
22
27
|
'refactor',
|
|
28
|
+
'chore',
|
|
23
29
|
'test_generation',
|
|
24
30
|
'documentation',
|
|
25
31
|
'conflict_resolution',
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { runMachineFeedback } from '../verification/machine-feedback.js';
|
|
2
|
+
import { scanImpact } from '../verification/impact-scan.js';
|
|
3
|
+
export const APPROACHES = [
|
|
4
|
+
'기존 코드 재사용을 극대화하는 최소 diff 접근',
|
|
5
|
+
'해당 모듈의 지배적 패턴을 따르는 정석 접근',
|
|
6
|
+
'근본 원인을 한 단계 위에서 해결하는 구조적 접근',
|
|
7
|
+
'테스트와 관찰 가능성을 먼저 고정하는 증거 중심 접근'
|
|
8
|
+
];
|
|
9
|
+
export async function runSolutionTournament(input) {
|
|
10
|
+
const n = Math.min(Math.max(input.n ?? 3, 2), 4);
|
|
11
|
+
const candidates = await Promise.all(APPROACHES.slice(0, n).map((approach, index) => input.spawnWorker({ ...input.item, id: `${input.item.id}-cand${index + 1}`, approach_directive: approach, isolation: 'worktree' })
|
|
12
|
+
.then((candidate) => ({ ...candidate, id: candidate.id || `${input.item.id}-cand${index + 1}`, approach }))));
|
|
13
|
+
await Promise.all(candidates.map(async (candidate) => {
|
|
14
|
+
candidate.score = await scoreCandidate(input.root, candidate);
|
|
15
|
+
}));
|
|
16
|
+
const alive = candidates
|
|
17
|
+
.filter((candidate) => candidate.score?.machine_ok && candidate.score.impact_breaks === 0)
|
|
18
|
+
.sort((a, b) => rank(a.score) - rank(b.score));
|
|
19
|
+
if (alive.length === 0)
|
|
20
|
+
return { schema: 'sks.solution-tournament.v1', winner: null, reason: 'all_candidates_failed_machine_checks', candidates };
|
|
21
|
+
if (alive.length === 1)
|
|
22
|
+
return { schema: 'sks.solution-tournament.v1', winner: alive[0] || null, reason: 'single_survivor', candidates };
|
|
23
|
+
const verdict = await input.judgeWorker({
|
|
24
|
+
a: alive[0],
|
|
25
|
+
b: alive[1],
|
|
26
|
+
prompt: '두 패치 중 6개월 뒤 유지보수자가 고마워할 쪽을 골라라. 근거는 코드 사실만.'
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
schema: 'sks.solution-tournament.v1',
|
|
30
|
+
winner: verdict.pick === 'b' ? alive[1] : alive[0],
|
|
31
|
+
reason: `judge:${verdict.reason_digest}`,
|
|
32
|
+
candidates
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export async function scoreCandidate(root, candidate) {
|
|
36
|
+
const patchText = patchTextFromCandidate(candidate);
|
|
37
|
+
const changedFiles = changedFilesFromCandidate(candidate);
|
|
38
|
+
const feedbackRoot = candidate.worktree || root;
|
|
39
|
+
const [feedback, impact] = await Promise.all([
|
|
40
|
+
runMachineFeedback(feedbackRoot, changedFiles, { timeoutMs: 60_000 }),
|
|
41
|
+
scanImpact(feedbackRoot, changedFiles, patchText)
|
|
42
|
+
]);
|
|
43
|
+
const score = {
|
|
44
|
+
machine_ok: feedback.ok,
|
|
45
|
+
tests_passed: feedback.tests.ok ? feedback.tests.selected.length : 0,
|
|
46
|
+
tests_failed: feedback.tests.failed.length,
|
|
47
|
+
diff_lines: diffLineCount(patchText),
|
|
48
|
+
new_symbols: newExportCount(patchText),
|
|
49
|
+
impact_breaks: impact.cochange_required.length,
|
|
50
|
+
total: 0
|
|
51
|
+
};
|
|
52
|
+
score.total = rank(score);
|
|
53
|
+
return score;
|
|
54
|
+
}
|
|
55
|
+
export function summarizeTournament(result) {
|
|
56
|
+
return {
|
|
57
|
+
schema: result.schema,
|
|
58
|
+
winner_id: result.winner?.id || null,
|
|
59
|
+
reason: result.reason,
|
|
60
|
+
candidates: result.candidates.map((candidate) => ({
|
|
61
|
+
id: candidate.id,
|
|
62
|
+
approach: candidate.approach,
|
|
63
|
+
worktree: candidate.worktree,
|
|
64
|
+
score: candidate.score
|
|
65
|
+
}))
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export function rank(s) {
|
|
69
|
+
return s.tests_failed * 1000 + s.impact_breaks * 500 + s.new_symbols * 20 + s.diff_lines;
|
|
70
|
+
}
|
|
71
|
+
function changedFilesFromCandidate(candidate) {
|
|
72
|
+
const patch = candidate.patch || {};
|
|
73
|
+
if (Array.isArray(patch.changed_files))
|
|
74
|
+
return patch.changed_files.map(String);
|
|
75
|
+
if (Array.isArray(patch.git_worktree?.changed_files))
|
|
76
|
+
return patch.git_worktree.changed_files.map(String);
|
|
77
|
+
if (Array.isArray(patch.operations))
|
|
78
|
+
return [...new Set(patch.operations.map((operation) => String(operation.path || '')).filter(Boolean))];
|
|
79
|
+
if (Array.isArray(patch.patch_envelopes))
|
|
80
|
+
return [...new Set(patch.patch_envelopes.flatMap((envelope) => changedFilesFromCandidate({ ...candidate, patch: envelope })))];
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
function patchTextFromCandidate(candidate) {
|
|
84
|
+
const patch = candidate.patch || {};
|
|
85
|
+
if (typeof patch.diff === 'string')
|
|
86
|
+
return patch.diff;
|
|
87
|
+
if (typeof patch.patch_text === 'string')
|
|
88
|
+
return patch.patch_text;
|
|
89
|
+
if (Array.isArray(patch.operations))
|
|
90
|
+
return patch.operations.map((operation) => operation.diff || operation.content || operation.replace || '').join('\n');
|
|
91
|
+
if (Array.isArray(patch.patch_envelopes))
|
|
92
|
+
return patch.patch_envelopes.map((envelope) => patchTextFromCandidate({ ...candidate, patch: envelope })).join('\n');
|
|
93
|
+
return '';
|
|
94
|
+
}
|
|
95
|
+
function diffLineCount(patchText) {
|
|
96
|
+
return String(patchText || '').split(/\r?\n/).filter((line) => /^[+-]/.test(line) && !/^(---|\+\+\+)/.test(line)).length;
|
|
97
|
+
}
|
|
98
|
+
function newExportCount(patchText) {
|
|
99
|
+
return String(patchText || '').split(/\r?\n/).filter((line) => /^\+\s*export\s+(?:async\s+)?(?:function|const|class|interface|type)\s+\w+/.test(line)).length;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=solution-tournament.js.map
|
|
@@ -86,6 +86,36 @@ export function madSksCatastrophicDbReasons(cls = {}) {
|
|
|
86
86
|
blocked.push('dangerous_project_or_branch_management');
|
|
87
87
|
return [...new Set(blocked)];
|
|
88
88
|
}
|
|
89
|
+
export function madSksCatastrophicSqlLiteralRequirements(cls = {}) {
|
|
90
|
+
const reasons = madSksCatastrophicDbReasons(cls);
|
|
91
|
+
const requirements = {
|
|
92
|
+
drop_database: /\bdrop\s+database\b/i,
|
|
93
|
+
drop_schema: /\bdrop\s+schema\b/i,
|
|
94
|
+
drop_table: /\bdrop\s+table\b/i,
|
|
95
|
+
truncate: /\btruncate\b/i,
|
|
96
|
+
delete_without_where: /\bdelete\s+from\b(?![\s\S]*\bwhere\b)/i,
|
|
97
|
+
update_without_where: /\bupdate\b[\s\S]*\bset\b(?![\s\S]*\bwhere\b)/i
|
|
98
|
+
};
|
|
99
|
+
return reasons
|
|
100
|
+
.flatMap((reason) => {
|
|
101
|
+
const pattern = requirements[reason];
|
|
102
|
+
return pattern ? [{ reason, pattern }] : [];
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
export function madSksCatastrophicSqlExplicitlyRequested({ classification, userIntent, sql } = {}) {
|
|
106
|
+
const requirements = madSksCatastrophicSqlLiteralRequirements(classification || {});
|
|
107
|
+
if (!requirements.length)
|
|
108
|
+
return { required: false, ok: true, missing: [] };
|
|
109
|
+
// The SQL text can be generated by the agent. Only the user's literal request
|
|
110
|
+
// or CLI statement counts as explicit catastrophic authorization.
|
|
111
|
+
const haystack = String(userIntent || '');
|
|
112
|
+
const missing = requirements.filter((entry) => !entry.pattern.test(haystack)).map((entry) => entry.reason);
|
|
113
|
+
return {
|
|
114
|
+
required: true,
|
|
115
|
+
ok: missing.length === 0,
|
|
116
|
+
missing
|
|
117
|
+
};
|
|
118
|
+
}
|
|
89
119
|
export function evaluatePermission({ action, scope, profile, classification, active = false, env = process.env } = {}) {
|
|
90
120
|
const selectedProfile = normalizePermissionProfile(profile, env);
|
|
91
121
|
const actionId = String(action || scope || '').trim();
|
|
@@ -870,6 +870,13 @@ async function materializeAutoSealedMadSks(dir, id, route, routeContext = {}, co
|
|
|
870
870
|
normal_db_writes_allowed: true,
|
|
871
871
|
live_server_writes_allowed: true,
|
|
872
872
|
migration_apply_allowed: true,
|
|
873
|
+
sql_plane: {
|
|
874
|
+
requested: false,
|
|
875
|
+
capability_id: null,
|
|
876
|
+
operation_classes: [],
|
|
877
|
+
read_back_passed: false,
|
|
878
|
+
profile_closed: false
|
|
879
|
+
},
|
|
873
880
|
catastrophic_safety_guard_active: true,
|
|
874
881
|
permission_profile: permissionGateSummary(),
|
|
875
882
|
contract_hash: contract.sealed_hash || null
|
|
@@ -962,7 +969,7 @@ async function prepareDb(root, route, task, required, opts = {}) {
|
|
|
962
969
|
return routeContext(route, id, task, required, 'Run sks db policy/scan/check as needed, keep DB operations read-only, record safe MCP policy, and pass db-review.json.');
|
|
963
970
|
}
|
|
964
971
|
async function prepareMadDb(root, route, task, required, opts = {}) {
|
|
965
|
-
const prepared = await prepareMadDbMission({ root, task, verifyTools: false, sessionKey: opts.sessionKey });
|
|
972
|
+
const prepared = await prepareMadDbMission({ root, task, verifyTools: false, sessionKey: opts.sessionKey, route: 'MadSKS', routeCommand: '$MAD-SKS' });
|
|
966
973
|
const dir = missionDir(root, prepared.mission_id);
|
|
967
974
|
const pipelinePlan = await writePipelinePlan(dir, {
|
|
968
975
|
missionId: prepared.mission_id,
|
|
@@ -978,7 +985,7 @@ async function prepareMadDb(root, route, task, required, opts = {}) {
|
|
|
978
985
|
cycle_id: prepared.cycle_id,
|
|
979
986
|
blockers: prepared.blockers
|
|
980
987
|
});
|
|
981
|
-
await setCurrent(root, routeState(prepared.mission_id, route, prepared.ok ? '
|
|
988
|
+
await setCurrent(root, routeState(prepared.mission_id, route, prepared.ok ? 'MADSKS_SQL_PLANE_CAPABILITY_ACTIVE' : 'MADSKS_SQL_PLANE_BLOCKED', required, {
|
|
982
989
|
prompt: task,
|
|
983
990
|
questions_allowed: false,
|
|
984
991
|
implementation_allowed: prepared.ok,
|
|
@@ -990,7 +997,8 @@ async function prepareMadDb(root, route, task, required, opts = {}) {
|
|
|
990
997
|
mad_db_profile_sha256: prepared.capability.transport.profile_sha256,
|
|
991
998
|
mad_db_capability_mission_id: prepared.mission_id,
|
|
992
999
|
mad_db_capability_file: 'mad-db-capability.json',
|
|
993
|
-
|
|
1000
|
+
mad_sks_gate_file: 'mad-sks-gate.json',
|
|
1001
|
+
stop_gate: 'mad-sks-gate.json',
|
|
994
1002
|
pipeline_plan_ready: validatePipelinePlan(pipelinePlan).ok,
|
|
995
1003
|
pipeline_plan_path: PIPELINE_PLAN_ARTIFACT
|
|
996
1004
|
}), { sessionKey: opts.sessionKey });
|
|
@@ -18,6 +18,7 @@ import { SSOT_GUARD_ARTIFACT, validateSsotGuardArtifact } from '../safety/ssot-g
|
|
|
18
18
|
import { validateTeamRuntimeArtifacts } from '../team-dag.js';
|
|
19
19
|
import { checkStopGate } from '../stop-gate/stop-gate-check.js';
|
|
20
20
|
import { clarificationStopReason, context7Evidence, hasContext7DocsEvidence, hasSubagentEvidence, subagentEvidence, } from './runtime-core.js';
|
|
21
|
+
import { projectTriwikiToAgentsMd } from '../triwiki/agents-md-projector.js';
|
|
21
22
|
const REFLECTION_ARTIFACT = 'reflection.md';
|
|
22
23
|
const REFLECTION_GATE = 'reflection-gate.json';
|
|
23
24
|
const REFLECTION_MEMORY_PATH = '.sneakoscope/memory/q2_facts/post-route-reflection.md';
|
|
@@ -289,8 +290,34 @@ export async function evaluateStop(root, state, payload, opts = {}) {
|
|
|
289
290
|
const reflection = await reflectionGateStatus(root, state, jsonCache);
|
|
290
291
|
if (!reflection.ok)
|
|
291
292
|
return complianceBlock(root, state, reflectionStopReason(state, reflection), { gate: 'reflection', missing: reflection.missing });
|
|
293
|
+
fireAndForgetProjectMemory(root, state);
|
|
292
294
|
return null;
|
|
293
295
|
}
|
|
296
|
+
function fireAndForgetProjectMemory(root, state = {}) {
|
|
297
|
+
if (!state?.mission_id)
|
|
298
|
+
return;
|
|
299
|
+
void projectTriwikiToAgentsMd(String(root)).then((report) => {
|
|
300
|
+
const id = state.mission_id;
|
|
301
|
+
if (!id)
|
|
302
|
+
return null;
|
|
303
|
+
return appendJsonl(path.join(missionDir(root, id), 'events.jsonl'), {
|
|
304
|
+
ts: nowIso(),
|
|
305
|
+
type: 'triwiki.agents_md_projected',
|
|
306
|
+
ok: report.ok,
|
|
307
|
+
reason: report.reason,
|
|
308
|
+
written: report.written
|
|
309
|
+
});
|
|
310
|
+
}).catch((err) => {
|
|
311
|
+
const id = state.mission_id;
|
|
312
|
+
if (!id)
|
|
313
|
+
return null;
|
|
314
|
+
return appendJsonl(path.join(missionDir(root, id), 'events.jsonl'), {
|
|
315
|
+
ts: nowIso(),
|
|
316
|
+
type: 'triwiki.agents_md_project_failed',
|
|
317
|
+
error: err?.message || String(err)
|
|
318
|
+
}).catch(() => undefined);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
294
321
|
async function routeProofGateStatus(root, state = {}) {
|
|
295
322
|
const route = routeFromState(state);
|
|
296
323
|
const required = state.proof_required === true || routeRequiresCompletionProof(route);
|
|
@@ -2,7 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import { nowIso, readJson, writeJsonAtomic } from '../fsx.js';
|
|
3
3
|
import { addImageRelation, ingestImage } from '../wiki-image/image-voxel-ledger.js';
|
|
4
4
|
import { exportSlidesToImages, PPT_DECK_INVENTORY_ARTIFACT, PPT_SLIDE_EXPORT_LEDGER_ARTIFACT } from './slide-exporter.js';
|
|
5
|
-
import { buildSlideImagegenRequestArtifact, buildSlideImagegenResponseArtifact, generateSlideCalloutReviews, PPT_SLIDE_CALLOUT_LEDGER_ARTIFACT, PPT_SLIDE_IMAGEGEN_REQUEST_ARTIFACT, PPT_SLIDE_IMAGEGEN_RESPONSE_ARTIFACT } from './slide-imagegen-review.js';
|
|
5
|
+
import { buildSlideImagegenRequestArtifact, buildSlideImagegenResponseArtifact, buildSlideImagegenEvidence, generateSlideCalloutReviews, PPT_SLIDE_CALLOUT_LEDGER_ARTIFACT, PPT_SLIDE_IMAGEGEN_REQUEST_ARTIFACT, PPT_SLIDE_IMAGEGEN_RESPONSE_ARTIFACT } from './slide-imagegen-review.js';
|
|
6
6
|
import { extractSlideIssues, PPT_DECK_ISSUE_LEDGER_ARTIFACT, PPT_SLIDE_EXTRACTION_REPORT_ARTIFACT, PPT_SLIDE_ISSUE_LEDGER_ARTIFACT } from './slide-issue-extraction.js';
|
|
7
7
|
import { writePptFixTaskPlan, PPT_FIX_TASK_PLAN_ARTIFACT } from './ppt-fix-task-planner.js';
|
|
8
8
|
import { writePptPatchHandoff, PPT_PATCH_HANDOFF_ARTIFACT, PPT_PATCH_RESULT_ARTIFACT } from './ppt-patch-handoff.js';
|
|
@@ -117,6 +117,9 @@ function buildPptImagegenReviewGate(parts = {}) {
|
|
|
117
117
|
const p0p1 = Number(parts.deckIssueLedger.p0_p1_count || parts.deckIssueLedger.p0_p1_open_count || 0);
|
|
118
118
|
const patchRequested = parts.fixRequested || p0p1 > 0 || parts.patchHandoff.result?.re_export_required === true;
|
|
119
119
|
const changedSlidesRechecked = !patchRequested || parts.recheckReport.status === 'complete' || parts.mock === true;
|
|
120
|
+
const imagegenEvidence = buildSlideImagegenEvidence(parts.calloutLedger);
|
|
121
|
+
if (imagegenEvidence.required && imagegenEvidence.passed !== true)
|
|
122
|
+
blockers.push(...imagegenEvidence.blockers);
|
|
120
123
|
const gate = {
|
|
121
124
|
schema: 'sks.ppt-imagegen-review-gate.v1',
|
|
122
125
|
created_at: nowIso(),
|
|
@@ -129,6 +132,7 @@ function buildPptImagegenReviewGate(parts = {}) {
|
|
|
129
132
|
patch_requested: patchRequested,
|
|
130
133
|
changed_slides_rechecked: changedSlidesRechecked,
|
|
131
134
|
image_voxel_relations_created: parts.imageVoxelRelationsCreated === true,
|
|
135
|
+
imagegen_evidence: imagegenEvidence,
|
|
132
136
|
wrongness_checked: true,
|
|
133
137
|
honest_mode_complete: true,
|
|
134
138
|
mock_fixture: parts.mock === true,
|
|
@@ -144,6 +148,7 @@ function buildPptImagegenReviewGate(parts = {}) {
|
|
|
144
148
|
&& gate.p0_p1_zero_after_fix
|
|
145
149
|
&& gate.changed_slides_rechecked
|
|
146
150
|
&& gate.image_voxel_relations_created
|
|
151
|
+
&& gate.imagegen_evidence.passed === true
|
|
147
152
|
&& gate.blockers.length === 0;
|
|
148
153
|
return gate;
|
|
149
154
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import fsp from 'node:fs/promises';
|
|
3
|
-
import { nowIso } from '../fsx.js';
|
|
3
|
+
import { nowIso, readJson } from '../fsx.js';
|
|
4
4
|
import { CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_IMAGEGEN_REQUIRED_POLICY } from '../routes.js';
|
|
5
5
|
import { sha256File, imageDimensions } from '../wiki-image/image-hash.js';
|
|
6
6
|
import { generateGptImage2CalloutReview } from '../image-ux-review/imagegen-adapter.js';
|
|
@@ -45,6 +45,9 @@ export async function generateSlideCalloutReviews({ root, dir, slideExportLedger
|
|
|
45
45
|
...metadata,
|
|
46
46
|
status: 'generated',
|
|
47
47
|
source: 'mock_fixture',
|
|
48
|
+
evidence_class: 'mock_fixture',
|
|
49
|
+
output_source: 'mock_fixture',
|
|
50
|
+
output_sha256: metadata.sha256,
|
|
48
51
|
callout_extraction_status: 'succeeded',
|
|
49
52
|
callouts: [{
|
|
50
53
|
callout_id: 'callout-1',
|
|
@@ -62,8 +65,15 @@ export async function generateSlideCalloutReviews({ root, dir, slideExportLedger
|
|
|
62
65
|
else if (generatedSlideImage && slides.length > 0) {
|
|
63
66
|
const slide = slides[0];
|
|
64
67
|
const generatedPath = await stageGeneratedSlideReview(root, dir, path.resolve(root, generatedSlideImage), path.basename(generatedSlideImage));
|
|
68
|
+
const metadata = await generatedSlideMetadata(root, generatedPath, slide, {
|
|
69
|
+
mock: false,
|
|
70
|
+
realGenerated: true,
|
|
71
|
+
providerSurface: 'codex_app_imagegen',
|
|
72
|
+
evidenceClass: 'codex_app_imagegen',
|
|
73
|
+
outputSource: 'manual_attach'
|
|
74
|
+
});
|
|
65
75
|
generatedReviewImages.push({
|
|
66
|
-
...
|
|
76
|
+
...metadata,
|
|
67
77
|
status: 'attached_generated_review',
|
|
68
78
|
source: 'user_attached_generated_slide_review',
|
|
69
79
|
callout_extraction_status: 'pending',
|
|
@@ -85,15 +95,23 @@ export async function generateSlideCalloutReviews({ root, dir, slideExportLedger
|
|
|
85
95
|
blockers.push(generated.blocker || 'ppt_imagegen_callouts_missing');
|
|
86
96
|
continue;
|
|
87
97
|
}
|
|
88
|
-
const
|
|
98
|
+
const response = generated.response_artifact ? await readJson(generated.response_artifact, null).catch(() => null) : null;
|
|
99
|
+
const evidenceClass = String(response?.evidence_class || '');
|
|
100
|
+
const fakeGenerated = evidenceClass === 'mock_fixture' || generated.provider === 'fake_imagegen_adapter';
|
|
101
|
+
const codexGenerated = evidenceClass === 'codex_app_imagegen';
|
|
102
|
+
if (!codexGenerated)
|
|
103
|
+
blockers.push(evidenceClass === 'non_codex_api_fallback' ? 'ppt_imagegen_non_codex_api_fallback_not_full_evidence' : fakeGenerated ? 'ppt_imagegen_mock_fixture_not_full_evidence' : 'ppt_imagegen_evidence_class_missing');
|
|
89
104
|
generatedReviewImages.push({
|
|
90
105
|
...await generatedSlideMetadata(root, generated.generated_image_path, slide, {
|
|
91
106
|
mock: fakeGenerated,
|
|
92
|
-
realGenerated:
|
|
93
|
-
providerSurface: generated.provider || 'gpt-image-2'
|
|
107
|
+
realGenerated: codexGenerated,
|
|
108
|
+
providerSurface: generated.provider || 'gpt-image-2',
|
|
109
|
+
evidenceClass,
|
|
110
|
+
outputSource: response?.output_source || null,
|
|
111
|
+
outputSha256: response?.output_sha256 || response?.output_image_sha256 || null
|
|
94
112
|
}),
|
|
95
113
|
status: 'generated',
|
|
96
|
-
source: fakeGenerated ? 'mock_fixture' : 'real_gpt_image_2_callout',
|
|
114
|
+
source: fakeGenerated ? 'mock_fixture' : codexGenerated ? 'real_gpt_image_2_callout' : 'non_codex_api_fallback',
|
|
97
115
|
callout_extraction_status: fakeGenerated ? 'succeeded' : 'pending',
|
|
98
116
|
callouts: fakeGenerated ? [{
|
|
99
117
|
callout_id: 'fake-slide-callout-1',
|
|
@@ -159,9 +177,51 @@ export function buildSlideImagegenResponseArtifact(calloutLedger = {}) {
|
|
|
159
177
|
schema: 'sks.ppt-slide-imagegen-response.v1',
|
|
160
178
|
created_at: nowIso(),
|
|
161
179
|
generated_review_images: calloutLedger.generated_review_images || [],
|
|
180
|
+
imagegen_evidence: buildSlideImagegenEvidence(calloutLedger),
|
|
162
181
|
blockers: calloutLedger.blockers || []
|
|
163
182
|
};
|
|
164
183
|
}
|
|
184
|
+
export function buildSlideImagegenEvidence(calloutLedger = {}) {
|
|
185
|
+
const images = Array.isArray(calloutLedger.generated_review_images) ? calloutLedger.generated_review_images : [];
|
|
186
|
+
const requiredCount = Number(calloutLedger.required_count || images.length || 0);
|
|
187
|
+
const blockers = [];
|
|
188
|
+
for (const image of images) {
|
|
189
|
+
const evidenceClass = String(image.evidence_class || '');
|
|
190
|
+
const outputSource = String(image.output_source || '');
|
|
191
|
+
const outputSha = String(image.output_sha256 || '');
|
|
192
|
+
if (evidenceClass !== 'codex_app_imagegen')
|
|
193
|
+
blockers.push(evidenceClass ? `ppt_slide_imagegen_evidence_class_not_codex_app:${evidenceClass}` : 'ppt_slide_imagegen_evidence_class_missing');
|
|
194
|
+
if (!['manual_attach', 'auto_discovered_generated_images'].includes(outputSource))
|
|
195
|
+
blockers.push(`ppt_slide_imagegen_output_source_invalid:${outputSource || 'missing'}`);
|
|
196
|
+
if (!outputSha)
|
|
197
|
+
blockers.push('ppt_slide_imagegen_output_sha256_missing');
|
|
198
|
+
else if (image.sha256 && image.sha256 !== outputSha)
|
|
199
|
+
blockers.push('ppt_slide_imagegen_output_sha256_mismatch');
|
|
200
|
+
if (image.real_generated !== true)
|
|
201
|
+
blockers.push('ppt_slide_imagegen_not_real_codex_app_output');
|
|
202
|
+
}
|
|
203
|
+
if (requiredCount > 0 && images.length < requiredCount)
|
|
204
|
+
blockers.push('ppt_slide_imagegen_required_outputs_missing');
|
|
205
|
+
return {
|
|
206
|
+
schema: 'sks.ppt-slide-imagegen-evidence.v1',
|
|
207
|
+
required: requiredCount > 0,
|
|
208
|
+
required_count: requiredCount,
|
|
209
|
+
generated_count: images.length,
|
|
210
|
+
codex_app_generated_count: images.filter((image) => image.evidence_class === 'codex_app_imagegen' && image.real_generated === true).length,
|
|
211
|
+
images: images.map((image) => ({
|
|
212
|
+
image_path: image.image_path || image.path || null,
|
|
213
|
+
output_source: image.output_source || null,
|
|
214
|
+
output_sha256: image.output_sha256 || null,
|
|
215
|
+
sha256: image.sha256 || null,
|
|
216
|
+
evidence_class: image.evidence_class || null,
|
|
217
|
+
real_generated: image.real_generated === true,
|
|
218
|
+
mock: image.mock === true,
|
|
219
|
+
response_artifact: image.imagegen_response_artifact || null
|
|
220
|
+
})),
|
|
221
|
+
blockers: [...new Set(blockers)],
|
|
222
|
+
passed: requiredCount > 0 && images.length >= requiredCount && blockers.length === 0
|
|
223
|
+
};
|
|
224
|
+
}
|
|
165
225
|
async function stageGeneratedSlideReview(root, dir, source, preferredName) {
|
|
166
226
|
const dest = path.join(dir, 'generated-slide-reviews', preferredName);
|
|
167
227
|
await fsp.mkdir(path.dirname(dest), { recursive: true });
|
|
@@ -170,21 +230,26 @@ async function stageGeneratedSlideReview(root, dir, source, preferredName) {
|
|
|
170
230
|
return path.relative(root, dest).split(path.sep).join('/');
|
|
171
231
|
}
|
|
172
232
|
async function generatedSlideMetadata(root, relPath, slide, opts = {}) {
|
|
173
|
-
const absolute = path.resolve(root, relPath);
|
|
233
|
+
const absolute = path.isAbsolute(relPath) ? relPath : path.resolve(root, relPath);
|
|
174
234
|
const dims = await imageDimensions(absolute);
|
|
235
|
+
const normalizedPath = path.relative(root, absolute).split(path.sep).join('/');
|
|
236
|
+
const sha = await sha256File(absolute);
|
|
175
237
|
return {
|
|
176
238
|
id: opts.mock ? `ppt-generated-review-fixture-${slide.slide_index || 1}` : `ppt-generated-review-${slide.slide_index || 1}`,
|
|
177
239
|
generated_review_image_id: opts.mock ? `ppt-generated-review-fixture-${slide.slide_index || 1}` : `ppt-generated-review-${slide.slide_index || 1}`,
|
|
178
240
|
slide_id: slide.slide_id,
|
|
179
241
|
slide_index: slide.slide_index,
|
|
180
242
|
source_slide_image_path: slide.image_path,
|
|
181
|
-
image_path:
|
|
182
|
-
sha256:
|
|
243
|
+
image_path: normalizedPath,
|
|
244
|
+
sha256: sha,
|
|
245
|
+
output_sha256: opts.outputSha256 || sha,
|
|
246
|
+
output_source: opts.outputSource || (opts.mock ? 'mock_fixture' : 'manual_attach'),
|
|
247
|
+
evidence_class: opts.evidenceClass || (opts.mock ? 'mock_fixture' : opts.realGenerated ? 'codex_app_imagegen' : 'non_codex_api_fallback'),
|
|
183
248
|
width: dims.width,
|
|
184
249
|
height: dims.height,
|
|
185
250
|
format: dims.format,
|
|
186
251
|
provider_surface: opts.mock ? 'mock_fixture' : (opts.providerSurface || 'Codex App $imagegen'),
|
|
187
|
-
real_generated: opts.realGenerated === true,
|
|
252
|
+
real_generated: opts.realGenerated === true && (opts.evidenceClass || (opts.mock ? 'mock_fixture' : 'codex_app_imagegen')) === 'codex_app_imagegen',
|
|
188
253
|
mock: opts.mock === true,
|
|
189
254
|
local_only: true
|
|
190
255
|
};
|