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
|
@@ -1,7 +1,27 @@
|
|
|
1
|
-
import { dirSize, formatBytes, packageRoot, sksRoot } from '../fsx.js';
|
|
1
|
+
import { dirSize, formatBytes, packageRoot, projectRoot, sksRoot } from '../fsx.js';
|
|
2
2
|
import { enforceRetention, storageReport } from '../retention.js';
|
|
3
3
|
import { flag } from './command-utils.js';
|
|
4
|
-
|
|
4
|
+
import { projectTriwikiToAgentsMd } from '../triwiki/agents-md-projector.js';
|
|
5
|
+
import { compileMistakeRules } from '../verification/mistake-rule-compiler.js';
|
|
6
|
+
export async function memoryCommand(sub, args = []) {
|
|
7
|
+
const action = String(sub || '').toLowerCase();
|
|
8
|
+
if (['build', 'project', 'agents', 'agents-md'].includes(action)) {
|
|
9
|
+
const root = await projectRoot();
|
|
10
|
+
const [result, rules] = await Promise.all([
|
|
11
|
+
projectTriwikiToAgentsMd(root, { maxLocalFiles: Number(readOption(args, '--max-local-files', 8)) }),
|
|
12
|
+
compileMistakeRules(root).catch((err) => ({ compiled: [], skipped: [`compile_failed:${err instanceof Error ? err.message : String(err)}`] }))
|
|
13
|
+
]);
|
|
14
|
+
const output = { ...result, mistake_rules: rules };
|
|
15
|
+
if (flag(args, '--json'))
|
|
16
|
+
return console.log(JSON.stringify(output, null, 2));
|
|
17
|
+
console.log(`SKS memory build: ${result.ok ? 'ok' : result.reason}`);
|
|
18
|
+
for (const file of result.written)
|
|
19
|
+
console.log(`- ${file}`);
|
|
20
|
+
console.log(`- mistake rules compiled: ${rules.compiled.length}, skipped: ${rules.skipped.length}`);
|
|
21
|
+
if (!result.ok)
|
|
22
|
+
process.exitCode = 1;
|
|
23
|
+
return output;
|
|
24
|
+
}
|
|
5
25
|
return gcCommand(args || []);
|
|
6
26
|
}
|
|
7
27
|
export async function gcCommand(args = []) {
|
|
@@ -16,6 +36,13 @@ export async function gcCommand(args = []) {
|
|
|
16
36
|
for (const a of res.actions.slice(0, 20))
|
|
17
37
|
console.log(`- ${a.action} ${a.path || a.mission || ''} ${a.bytes ? formatBytes(a.bytes) : ''}`);
|
|
18
38
|
}
|
|
39
|
+
function readOption(args = [], name, fallback = null) {
|
|
40
|
+
const index = args.indexOf(name);
|
|
41
|
+
if (index >= 0 && args[index + 1] && !String(args[index + 1]).startsWith('--'))
|
|
42
|
+
return args[index + 1];
|
|
43
|
+
const prefixed = args.find((arg) => String(arg).startsWith(`${name}=`));
|
|
44
|
+
return prefixed ? String(prefixed).slice(name.length + 1) : fallback;
|
|
45
|
+
}
|
|
19
46
|
export async function statsCommand(args = []) {
|
|
20
47
|
const root = await sksRoot();
|
|
21
48
|
const report = await storageReport(root);
|
|
@@ -6,6 +6,7 @@ import { GOAL_BRIDGE_ARTIFACT, GOAL_WORKFLOW_ARTIFACT, updateGoalWorkflow, write
|
|
|
6
6
|
import { flag, promptOf, resolveMissionId } from './command-utils.js';
|
|
7
7
|
import { compileGoalToLoopPlan } from '../loops/goal-to-loop-compat.js';
|
|
8
8
|
import { runLoopPlan } from '../loops/loop-runtime.js';
|
|
9
|
+
import { evaluateLocalGate } from './route-success-helpers.js';
|
|
9
10
|
export async function goalCommand(sub, args = []) {
|
|
10
11
|
const known = new Set(['create', 'pause', 'resume', 'clear', 'status', 'help', '--help', '-h']);
|
|
11
12
|
const action = known.has(sub) ? sub : 'create';
|
|
@@ -39,10 +40,16 @@ async function goalCreate(args) {
|
|
|
39
40
|
const workflow = await writeGoalWorkflow(dir, mission, { action: 'create', prompt });
|
|
40
41
|
const plan = await compileGoalToLoopPlan({ root, missionId: id, goalText: prompt, legacyGoalOptions: { native_goal: workflow.native_goal } });
|
|
41
42
|
const result = await runLoopPlan({ root, plan, parallelism: 'balanced' });
|
|
42
|
-
await
|
|
43
|
+
const gate = await evaluateLocalGate({ root, missionId: id, gateFile: 'loop-graph-proof.json' });
|
|
44
|
+
const ok = result.ok === true && gate.ok === true;
|
|
45
|
+
await setCurrent(root, { mission_id: id, mode: 'GOAL', route: 'Goal', route_command: '$Goal', phase: ok ? 'GOAL_LOOP_COMPLETED' : 'GOAL_LOOP_BLOCKED', questions_allowed: true, implementation_allowed: true, native_goal: workflow.native_goal, stop_gate: 'loop-graph-proof.json', stop_gate_blockers: gate.blockers }, { replace: true });
|
|
46
|
+
if (!ok)
|
|
47
|
+
process.exitCode = 1;
|
|
43
48
|
if (flag(args, '--json'))
|
|
44
|
-
return console.log(JSON.stringify({ schema: 'sks.goal-create.v1', ok
|
|
49
|
+
return console.log(JSON.stringify({ schema: 'sks.goal-create.v1', ok, mission_id: id, workflow, loop_plan: plan, loop_result: result, gate }, null, 2));
|
|
45
50
|
console.log(`Goal compiled to Loop Graph: ${id}`);
|
|
51
|
+
if (!ok)
|
|
52
|
+
console.log(`Gate blocked: ${gate.blockers.join(', ') || 'loop_result_not_ok'}`);
|
|
46
53
|
console.log('Use `sks loop status latest` to inspect.');
|
|
47
54
|
console.log(`Artifact: ${path.relative(root, path.join(dir, GOAL_WORKFLOW_ARTIFACT))}`);
|
|
48
55
|
console.log(`Bridge: ${path.relative(root, path.join(dir, GOAL_BRIDGE_ARTIFACT))}`);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { sksRoot, writeJsonAtomic } from '../fsx.js';
|
|
2
|
+
import { readJson, sksRoot, writeJsonAtomic } from '../fsx.js';
|
|
3
3
|
import { createMission } from '../mission.js';
|
|
4
4
|
import { driftCartridge, renderCartridge, snapshotCartridge, validateCartridge } from '../gx-renderer.js';
|
|
5
5
|
import { maybeFinalizeRoute } from '../proof/auto-finalize.js';
|
|
6
6
|
import { flag, positionalArgs, readFlagValue } from './command-utils.js';
|
|
7
|
+
import { context7EvidenceStatus } from './route-success-helpers.js';
|
|
7
8
|
export async function gxCommand(sub, args = []) {
|
|
8
9
|
const root = await sksRoot();
|
|
9
10
|
const name = cartridgeName(args);
|
|
@@ -36,8 +37,38 @@ export async function gxCommand(sub, args = []) {
|
|
|
36
37
|
if (name === 'fixture' && flag(args, '--mock'))
|
|
37
38
|
return gxValidateFixture(root, args);
|
|
38
39
|
const validation = await validateCartridge(dir);
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
const vgraph = await readJson(path.join(dir, 'vgraph.json'), null);
|
|
41
|
+
const context7 = await context7EvidenceStatus(root);
|
|
42
|
+
const schemaBlockers = validateGxVGraph(vgraph);
|
|
43
|
+
const blockers = [
|
|
44
|
+
...(Array.isArray(validation.issues) ? validation.issues : []),
|
|
45
|
+
...schemaBlockers,
|
|
46
|
+
...(context7.ok ? [] : [context7.blocker])
|
|
47
|
+
].filter(Boolean);
|
|
48
|
+
const result = {
|
|
49
|
+
...validation,
|
|
50
|
+
ok: validation.ok === true && blockers.length === 0,
|
|
51
|
+
status: validation.ok === true && blockers.length === 0 ? 'pass' : 'blocked',
|
|
52
|
+
context7_policy: context7.policy,
|
|
53
|
+
context7_evidence: context7.evidence,
|
|
54
|
+
vgraph_schema_valid: schemaBlockers.length === 0,
|
|
55
|
+
blockers
|
|
56
|
+
};
|
|
57
|
+
const gate = {
|
|
58
|
+
schema: 'sks.gx-gate.v1',
|
|
59
|
+
schema_version: 1,
|
|
60
|
+
passed: result.ok,
|
|
61
|
+
ok: result.ok,
|
|
62
|
+
status: result.ok ? 'pass' : 'blocked',
|
|
63
|
+
gx_validation: 'gx-validation.json',
|
|
64
|
+
context7_policy: context7.policy,
|
|
65
|
+
vgraph_schema_valid: schemaBlockers.length === 0,
|
|
66
|
+
blockers
|
|
67
|
+
};
|
|
68
|
+
await writeJsonAtomic(path.join(dir, 'gx-validation.json'), result);
|
|
69
|
+
await writeJsonAtomic(path.join(dir, 'gx-gate.json'), gate);
|
|
70
|
+
console.log(JSON.stringify(result, null, 2));
|
|
71
|
+
process.exitCode = result.ok ? 0 : 2;
|
|
41
72
|
return;
|
|
42
73
|
}
|
|
43
74
|
if (sub === 'drift') {
|
|
@@ -56,12 +87,53 @@ export async function gxCommand(sub, args = []) {
|
|
|
56
87
|
}
|
|
57
88
|
async function gxValidateFixture(root, args) {
|
|
58
89
|
const { id, dir } = await createMission(root, { mode: 'gx', prompt: 'GX validate fixture' });
|
|
59
|
-
const validation = {
|
|
90
|
+
const validation = {
|
|
91
|
+
schema: 'sks.gx-validation.v1',
|
|
92
|
+
ok: false,
|
|
93
|
+
status: 'blocked',
|
|
94
|
+
execution_class: 'mock_fixture',
|
|
95
|
+
fixture: true,
|
|
96
|
+
cartridge: 'fixture',
|
|
97
|
+
blockers: ['gx_fixture_mode_cannot_claim_real']
|
|
98
|
+
};
|
|
60
99
|
await writeJsonAtomic(path.join(dir, 'gx-validation.json'), validation);
|
|
61
|
-
const gate = {
|
|
100
|
+
const gate = {
|
|
101
|
+
schema: 'sks.gx-gate.v1',
|
|
102
|
+
schema_version: 1,
|
|
103
|
+
passed: false,
|
|
104
|
+
ok: false,
|
|
105
|
+
status: 'blocked',
|
|
106
|
+
execution_class: 'mock_fixture',
|
|
107
|
+
gx_validation: 'gx-validation.json',
|
|
108
|
+
visual_claim: false,
|
|
109
|
+
blockers: ['gx_fixture_mode_cannot_claim_real']
|
|
110
|
+
};
|
|
62
111
|
await writeJsonAtomic(path.join(dir, 'gx-gate.json'), gate);
|
|
63
|
-
const proof = await maybeFinalizeRoute(root, { missionId: id, route: '$GX', gateFile: 'gx-gate.json', gate, mock: true, visual: true, artifacts: ['gx-validation.json', 'image-voxel-ledger.json', 'completion-proof.json'], claims: [{ id: 'gx-validate-fixture', status: '
|
|
64
|
-
|
|
112
|
+
const proof = await maybeFinalizeRoute(root, { missionId: id, route: '$GX', gateFile: 'gx-gate.json', gate, mock: true, visual: true, statusHint: 'blocked', blockers: gate.blockers, artifacts: ['gx-validation.json', 'image-voxel-ledger.json', 'completion-proof.json'], claims: [{ id: 'gx-validate-fixture', status: 'blocked' }], command: { cmd: 'sks gx validate fixture --mock', status: 1 } });
|
|
113
|
+
const result = { schema: 'sks.gx-validate-fixture.v1', ok: false, mission_id: id, validation, gate, proof: proof.validation };
|
|
114
|
+
console.log(JSON.stringify(result, null, 2));
|
|
115
|
+
process.exitCode = 1;
|
|
116
|
+
}
|
|
117
|
+
function validateGxVGraph(vgraph) {
|
|
118
|
+
const blockers = [];
|
|
119
|
+
if (!vgraph || typeof vgraph !== 'object')
|
|
120
|
+
return ['vgraph_missing_or_invalid_json'];
|
|
121
|
+
if (!String(vgraph.id || vgraph.name || '').trim())
|
|
122
|
+
blockers.push('vgraph_id_missing');
|
|
123
|
+
if (!Array.isArray(vgraph.nodes) || vgraph.nodes.length === 0)
|
|
124
|
+
blockers.push('vgraph_nodes_missing');
|
|
125
|
+
if (!Array.isArray(vgraph.edges))
|
|
126
|
+
blockers.push('vgraph_edges_missing');
|
|
127
|
+
const ids = new Set((Array.isArray(vgraph.nodes) ? vgraph.nodes : []).map((node) => String(node?.id || '').trim()).filter(Boolean));
|
|
128
|
+
if (ids.size !== (Array.isArray(vgraph.nodes) ? vgraph.nodes.length : 0))
|
|
129
|
+
blockers.push('vgraph_node_ids_missing_or_duplicate');
|
|
130
|
+
for (const edge of Array.isArray(vgraph.edges) ? vgraph.edges : []) {
|
|
131
|
+
const from = String(edge?.from || edge?.source || '').trim();
|
|
132
|
+
const to = String(edge?.to || edge?.target || '').trim();
|
|
133
|
+
if (!from || !to || !ids.has(from) || !ids.has(to))
|
|
134
|
+
blockers.push('vgraph_edge_endpoint_invalid');
|
|
135
|
+
}
|
|
136
|
+
return [...new Set(blockers)];
|
|
65
137
|
}
|
|
66
138
|
function cartridgeName(args, fallback = 'architecture-atlas') {
|
|
67
139
|
const raw = positionalArgs(args)[0] || fallback;
|
|
@@ -12,6 +12,7 @@ import { addImageRelation, ingestImage } from '../wiki-image/image-voxel-ledger.
|
|
|
12
12
|
import { sha256File, imageDimensions } from '../wiki-image/image-hash.js';
|
|
13
13
|
import { writeRouteCollaborationArtifacts } from '../agents/route-collaboration-ledger.js';
|
|
14
14
|
import { codexChromeExtensionStatus } from '../codex-app.js';
|
|
15
|
+
import { requireCodexImagegen } from '../imagegen/require-imagegen.js';
|
|
15
16
|
const ONE_BY_ONE_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMB/axX7V8AAAAASUVORK5CYII=';
|
|
16
17
|
const IMAGE_UX_REVIEW_ARTIFACT_PATHS = {
|
|
17
18
|
policy: IMAGE_UX_REVIEW_POLICY_ARTIFACT,
|
|
@@ -107,6 +108,32 @@ async function runImageUxReview(root, command, args = []) {
|
|
|
107
108
|
console.error('UX Review blocked: screenshot_required');
|
|
108
109
|
return result;
|
|
109
110
|
}
|
|
111
|
+
if (!flag(args, '--mock') && !generatedImage) {
|
|
112
|
+
const imagegenRequired = await requireCodexImagegen(root, { autoRepair: true, applyRepair: true });
|
|
113
|
+
if (!imagegenRequired.ok) {
|
|
114
|
+
const result = {
|
|
115
|
+
schema: 'sks.image-ux-review-run.v1',
|
|
116
|
+
ok: false,
|
|
117
|
+
status: 'blocked',
|
|
118
|
+
blocker: 'codex_imagegen_unavailable',
|
|
119
|
+
imagegen_required: imagegenRequired,
|
|
120
|
+
gate: {
|
|
121
|
+
schema: 'sks.image-ux-review-gate.v2',
|
|
122
|
+
passed: false,
|
|
123
|
+
status: 'blocked',
|
|
124
|
+
blockers: ['codex_imagegen_unavailable'],
|
|
125
|
+
generated_image_evidence: false
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
if (flag(args, '--json'))
|
|
130
|
+
return printJson(result);
|
|
131
|
+
console.error('UX Review blocked: Codex App imagegen/gpt-image-2 is unavailable.');
|
|
132
|
+
for (const action of imagegenRequired.blocker?.next_actions || [])
|
|
133
|
+
console.error(`- ${action}`);
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
110
137
|
const { id, dir, mission } = await createMission(root, { mode: 'image-ux-review', prompt: promptForRun(command, args) });
|
|
111
138
|
const sourceRel = imagePath ? await stageSourceImage(root, dir, imagePath) : null;
|
|
112
139
|
const contract = {
|
|
@@ -148,12 +175,23 @@ async function runImageUxReview(root, command, args = []) {
|
|
|
148
175
|
}
|
|
149
176
|
});
|
|
150
177
|
if (result.generated_image_path) {
|
|
151
|
-
const fakeGenerated = result.provider === 'fake_imagegen_adapter';
|
|
152
178
|
if (result.request_artifact)
|
|
153
179
|
await fsp.copyFile(result.request_artifact, path.join(dir, IMAGE_UX_REVIEW_GPT_IMAGE_2_REQUEST_ARTIFACT)).catch(() => { });
|
|
154
180
|
if (result.response_artifact)
|
|
155
181
|
await fsp.copyFile(result.response_artifact, path.join(dir, IMAGE_UX_REVIEW_GPT_IMAGE_2_RESPONSE_ARTIFACT)).catch(() => { });
|
|
156
|
-
await
|
|
182
|
+
const response = await readImagegenResponse(dir);
|
|
183
|
+
const evidenceClass = String(response?.evidence_class || '');
|
|
184
|
+
const fakeGenerated = evidenceClass === 'mock_fixture' || result.provider === 'fake_imagegen_adapter';
|
|
185
|
+
const realGenerated = evidenceClass === 'codex_app_imagegen';
|
|
186
|
+
await attachGeneratedReviewImage(root, dir, contract, result.generated_image_path, {
|
|
187
|
+
realGenerated,
|
|
188
|
+
mock: fakeGenerated,
|
|
189
|
+
providerSurface: result.provider,
|
|
190
|
+
evidenceClass,
|
|
191
|
+
outputSource: response?.output_source || null,
|
|
192
|
+
outputSha256: response?.output_sha256 || response?.output_image_sha256 || null,
|
|
193
|
+
responseArtifact: result.response_artifact || null
|
|
194
|
+
});
|
|
157
195
|
const extraction = await extractRealCallouts({
|
|
158
196
|
root,
|
|
159
197
|
generatedImagePath: result.generated_image_path,
|
|
@@ -169,6 +207,8 @@ async function runImageUxReview(root, command, args = []) {
|
|
|
169
207
|
}
|
|
170
208
|
}
|
|
171
209
|
const artifacts = await writeImageUxReviewRouteArtifacts(dir, contract, { root, wrongnessChecked: true, honestModeComplete: true });
|
|
210
|
+
artifacts.gate = await enforceImageUxRuntimeGate(dir, artifacts.gate, { mock: flag(args, '--mock') });
|
|
211
|
+
await writeJsonAtomic(path.join(dir, IMAGE_UX_REVIEW_GATE_ARTIFACT), artifacts.gate);
|
|
172
212
|
const proof = await finalizeImageUx(root, id, command, artifacts, { mock: flag(args, '--mock'), cmd: `sks ${command} run` });
|
|
173
213
|
const result = { schema: 'sks.image-ux-review-run.v1', ok: proof.ok && artifacts.gate?.passed === true, status: artifacts.gate?.status || (artifacts.gate?.passed ? 'passed' : 'blocked'), mission_id: id, artifacts, proof: proof.validation };
|
|
174
214
|
if (!result.ok)
|
|
@@ -298,6 +338,8 @@ async function rebuildExistingMission(root, command, args = [], opts = {}) {
|
|
|
298
338
|
recapture: { computerUseAvailable: false },
|
|
299
339
|
honestModeComplete: opts.proofRequested === true
|
|
300
340
|
});
|
|
341
|
+
artifacts.gate = await enforceImageUxRuntimeGate(dir, artifacts.gate, { mock: flag(args, '--mock') });
|
|
342
|
+
await writeJsonAtomic(path.join(dir, IMAGE_UX_REVIEW_GATE_ARTIFACT), artifacts.gate);
|
|
301
343
|
const proof = await finalizeImageUx(root, missionId, command, artifacts, { mock: flag(args, '--mock'), cmd: `sks ${command} ${opts.fixRequested ? 'fix' : opts.recaptureRequested ? 'recapture' : 'build'}` });
|
|
302
344
|
const result = { schema: 'sks.image-ux-review-build.v2', ok: proof.ok && artifacts.gate?.passed === true, status: artifacts.gate?.status || (artifacts.gate?.passed ? 'passed' : 'blocked'), mission_id: missionId, artifacts, proof: proof.validation };
|
|
303
345
|
if (!result.ok)
|
|
@@ -380,7 +422,7 @@ async function imageUxFixture(root, command, args) {
|
|
|
380
422
|
fix_action: 'No-op fixture recheck',
|
|
381
423
|
target_surface: 'fixture',
|
|
382
424
|
candidate_files: [],
|
|
383
|
-
status: '
|
|
425
|
+
status: 'mock',
|
|
384
426
|
confidence: 0.5,
|
|
385
427
|
source: 'mock_fixture',
|
|
386
428
|
extracted_from_generated_image: true,
|
|
@@ -392,18 +434,21 @@ async function imageUxFixture(root, command, args) {
|
|
|
392
434
|
severity_visible: true,
|
|
393
435
|
callout_number_visible: true,
|
|
394
436
|
text_ocr_confidence: 0.5,
|
|
395
|
-
fix_verification_status: '
|
|
437
|
+
fix_verification_status: 'mock',
|
|
396
438
|
post_fix_recheck_issue_id: null
|
|
397
439
|
}]
|
|
398
440
|
});
|
|
399
441
|
const artifacts = await writeImageUxReviewRouteArtifacts(dir, contract, { root, imageVoxelRelationsCreated: true, wrongnessChecked: true, honestModeComplete: true });
|
|
400
442
|
const gate = {
|
|
401
443
|
...artifacts.gate,
|
|
402
|
-
passed:
|
|
444
|
+
passed: false,
|
|
445
|
+
ok: false,
|
|
446
|
+
status: 'blocked',
|
|
447
|
+
execution_class: 'mock_fixture',
|
|
403
448
|
honest_mode_complete: true,
|
|
404
|
-
blockers: [],
|
|
449
|
+
blockers: ['image_ux_fixture_mode_cannot_claim_real'],
|
|
405
450
|
fixture: true,
|
|
406
|
-
verified_level: '
|
|
451
|
+
verified_level: 'unverified_fixture',
|
|
407
452
|
mock_fixture_cannot_claim_real: true
|
|
408
453
|
};
|
|
409
454
|
artifacts.gate = gate;
|
|
@@ -417,23 +462,49 @@ async function imageUxFixture(root, command, args) {
|
|
|
417
462
|
mode: 'IMAGE_UX_REVIEW'
|
|
418
463
|
});
|
|
419
464
|
const proof = await finalizeImageUx(root, id, command, artifacts, { mock: true, requireRelation: flag(args, '--require-relation'), cmd: `sks ${command} fixture --mock` });
|
|
420
|
-
const result = { schema: 'sks.image-ux-review-fixture.v2', ok:
|
|
465
|
+
const result = { schema: 'sks.image-ux-review-fixture.v2', ok: false, mission_id: id, artifacts, native_agent_collaboration: native, proof: proof.validation };
|
|
466
|
+
process.exitCode = 1;
|
|
421
467
|
if (flag(args, '--json'))
|
|
422
468
|
return printJson(result);
|
|
423
|
-
console.log(`Image UX fixture:
|
|
469
|
+
console.log(`Image UX fixture: blocked ${id}`);
|
|
424
470
|
return result;
|
|
425
471
|
}
|
|
426
472
|
async function attachGeneratedReviewImage(root, dir, contract, imagePath, opts = {}) {
|
|
427
473
|
const inventory = await readJson(path.join(dir, 'image-ux-screen-inventory.json'), null).catch(() => null);
|
|
428
474
|
const sourceScreen = inventory?.source_screens?.[0] || { id: 'screen-1' };
|
|
429
475
|
const staged = await stageGeneratedImage(root, dir, imagePath, opts.mock ? 'generated-review-fixture.png' : null);
|
|
476
|
+
const response = await readImagegenResponse(dir);
|
|
477
|
+
const evidenceClass = opts.evidenceClass || response?.evidence_class || (opts.mock ? 'mock_fixture' : opts.realGenerated ? 'codex_app_imagegen' : null);
|
|
478
|
+
const outputSource = opts.outputSource || response?.output_source || (opts.mock ? 'mock_fixture' : opts.realGenerated ? 'manual_attach' : null);
|
|
479
|
+
const outputSha256 = opts.outputSha256 || response?.output_sha256 || response?.output_image_sha256 || null;
|
|
430
480
|
const metadata = await generatedImageMetadata(root, staged, {
|
|
431
481
|
id: opts.mock ? 'generated-review-fixture-1' : undefined,
|
|
432
482
|
source_screen_id: sourceScreen.id || 'screen-1',
|
|
433
483
|
provider_surface: opts.providerSurface || 'Codex App $imagegen',
|
|
434
|
-
|
|
484
|
+
evidence_class: evidenceClass,
|
|
485
|
+
output_source: outputSource,
|
|
486
|
+
output_sha256: outputSha256 || undefined,
|
|
487
|
+
real_generated: opts.realGenerated === true && evidenceClass === 'codex_app_imagegen',
|
|
435
488
|
mock: opts.mock === true
|
|
436
489
|
});
|
|
490
|
+
if (!response && opts.realGenerated === true) {
|
|
491
|
+
await writeJsonAtomic(path.join(dir, IMAGE_UX_REVIEW_GPT_IMAGE_2_RESPONSE_ARTIFACT), {
|
|
492
|
+
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
493
|
+
created_at: nowIso(),
|
|
494
|
+
provider: 'codex_app_imagegen',
|
|
495
|
+
evidence_class: 'codex_app_imagegen',
|
|
496
|
+
model: 'gpt-image-2',
|
|
497
|
+
ok: true,
|
|
498
|
+
status: 'generated',
|
|
499
|
+
output_image_path: path.resolve(root, metadata.path),
|
|
500
|
+
output_image_sha256: metadata.sha256,
|
|
501
|
+
output_sha256: metadata.sha256,
|
|
502
|
+
output_id: metadata.output_id || null,
|
|
503
|
+
output_source: 'manual_attach',
|
|
504
|
+
dimensions: { width: metadata.width, height: metadata.height, format: metadata.format },
|
|
505
|
+
local_only: true
|
|
506
|
+
});
|
|
507
|
+
}
|
|
437
508
|
const ledger = {
|
|
438
509
|
schema: 'sks.image-ux-generated-review-ledger.v2',
|
|
439
510
|
schema_version: 2,
|
|
@@ -444,6 +515,7 @@ async function attachGeneratedReviewImage(root, dir, contract, imagePath, opts =
|
|
|
444
515
|
...metadata,
|
|
445
516
|
source_screen_id: 'screen-1',
|
|
446
517
|
status: 'generated',
|
|
518
|
+
imagegen_response_artifact: opts.responseArtifact || (response || opts.realGenerated === true ? IMAGE_UX_REVIEW_GPT_IMAGE_2_RESPONSE_ARTIFACT : null),
|
|
447
519
|
image_voxel_relation: 'generated_callout_review_of',
|
|
448
520
|
callout_extraction_status: opts.mock ? 'succeeded' : 'pending',
|
|
449
521
|
callouts: opts.mock ? [{
|
|
@@ -455,7 +527,7 @@ async function attachGeneratedReviewImage(root, dir, contract, imagePath, opts =
|
|
|
455
527
|
title: 'Mock fixture callout',
|
|
456
528
|
detail: 'Mock fixture callout for schema validation.',
|
|
457
529
|
fix_action: 'Apply targeted UI adjustment, then recapture and re-review.',
|
|
458
|
-
status: opts.mock ? '
|
|
530
|
+
status: opts.mock ? 'mock' : 'open',
|
|
459
531
|
source: opts.mock ? 'mock_fixture' : 'real_gpt_image_2_callout',
|
|
460
532
|
confidence: opts.mock ? 0.5 : 0.82,
|
|
461
533
|
extraction_provider: 'mock_fixture',
|
|
@@ -466,19 +538,122 @@ async function attachGeneratedReviewImage(root, dir, contract, imagePath, opts =
|
|
|
466
538
|
severity_visible: true,
|
|
467
539
|
callout_number_visible: true,
|
|
468
540
|
text_ocr_confidence: 0.5,
|
|
469
|
-
fix_verification_status: '
|
|
541
|
+
fix_verification_status: opts.mock ? 'mock' : 'not_rechecked',
|
|
470
542
|
post_fix_recheck_issue_id: null
|
|
471
543
|
}] : []
|
|
472
544
|
}],
|
|
473
545
|
generated_count: 1,
|
|
474
546
|
required_count: 1,
|
|
475
547
|
blockers: [],
|
|
476
|
-
passed:
|
|
548
|
+
passed: metadata.real_generated === true && opts.mock !== true,
|
|
477
549
|
contract_hash: contract.sealed_hash || null
|
|
478
550
|
};
|
|
479
551
|
await writeJsonAtomic(path.join(dir, IMAGE_UX_REVIEW_GENERATED_REVIEW_LEDGER_ARTIFACT), ledger);
|
|
480
552
|
return ledger;
|
|
481
553
|
}
|
|
554
|
+
async function readImagegenResponse(dir) {
|
|
555
|
+
return readJson(path.join(dir, IMAGE_UX_REVIEW_GPT_IMAGE_2_RESPONSE_ARTIFACT), null).catch(() => null);
|
|
556
|
+
}
|
|
557
|
+
async function enforceImageUxRuntimeGate(dir, gate = {}, opts = {}) {
|
|
558
|
+
const inventory = await readJson(path.join(dir, IMAGE_UX_REVIEW_SCREEN_INVENTORY_ARTIFACT), null);
|
|
559
|
+
const issueLedger = await readJson(path.join(dir, IMAGE_UX_REVIEW_ISSUE_LEDGER_ARTIFACT), null);
|
|
560
|
+
const response = await readJson(path.join(dir, IMAGE_UX_REVIEW_GPT_IMAGE_2_RESPONSE_ARTIFACT), null);
|
|
561
|
+
const blockers = new Set(Array.isArray(gate?.blockers) ? gate.blockers.map(String) : []);
|
|
562
|
+
const sourceScreens = Array.isArray(inventory?.source_screens) ? inventory.source_screens : [];
|
|
563
|
+
if (!opts.mock) {
|
|
564
|
+
if (sourceScreens.length === 0)
|
|
565
|
+
blockers.add('no_source_screenshots_for_imagegen_review');
|
|
566
|
+
for (const screen of sourceScreens) {
|
|
567
|
+
const width = Number(screen?.width || screen?.original_resolution?.width || 0);
|
|
568
|
+
const height = Number(screen?.height || screen?.original_resolution?.height || 0);
|
|
569
|
+
if (screen?.status !== 'captured')
|
|
570
|
+
blockers.add(`source_screenshot_unreadable:${screen?.id || 'unknown'}`);
|
|
571
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width < 64 || height < 64)
|
|
572
|
+
blockers.add(`source_screenshot_below_min_resolution:${screen?.id || 'unknown'}`);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
const issues = Array.isArray(issueLedger?.issues) ? issueLedger.issues : [];
|
|
576
|
+
if (issues.some((issue) => issue?.extraction_provider === 'mock_fixture' || issue?.source === 'mock_fixture'))
|
|
577
|
+
blockers.add('mock_issue_extraction_cannot_pass_gate');
|
|
578
|
+
if (opts.mock)
|
|
579
|
+
blockers.add('image_ux_mock_mode_cannot_claim_real');
|
|
580
|
+
const responseEvidence = await validateImagegenResponseEvidence(response, dir);
|
|
581
|
+
for (const blocker of responseEvidence.blockers)
|
|
582
|
+
blockers.add(blocker);
|
|
583
|
+
const nextBlockers = [...blockers];
|
|
584
|
+
const codexGenerated = responseEvidence.ok === true && gate?.gpt_image_2_callout_generated === true;
|
|
585
|
+
const passed = gate?.passed === true && codexGenerated && nextBlockers.length === 0;
|
|
586
|
+
return {
|
|
587
|
+
...gate,
|
|
588
|
+
passed,
|
|
589
|
+
ok: passed,
|
|
590
|
+
status: passed ? 'passed' : 'blocked',
|
|
591
|
+
gpt_image_2_callout_generated: codexGenerated,
|
|
592
|
+
generated_image_evidence: responseEvidence.ok === true,
|
|
593
|
+
imagegen_response_evidence: responseEvidence,
|
|
594
|
+
source_screenshot_min_resolution_passed: sourceScreens.length > 0 && sourceScreens.every((screen) => Number(screen?.width || 0) >= 64 && Number(screen?.height || 0) >= 64),
|
|
595
|
+
issue_ledger_real_extraction: issues.length > 0 && issues.every((issue) => issue?.extraction_provider !== 'mock_fixture' && issue?.source !== 'mock_fixture'),
|
|
596
|
+
blockers: nextBlockers
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
async function validateImagegenResponseEvidence(response = null, dir = process.cwd()) {
|
|
600
|
+
const blockers = [];
|
|
601
|
+
if (!response || typeof response !== 'object') {
|
|
602
|
+
return { ok: false, blockers: ['imagegen_response_artifact_missing'] };
|
|
603
|
+
}
|
|
604
|
+
if (response.schema !== 'sks.image-ux-gpt-image-2-response.v1')
|
|
605
|
+
blockers.push('imagegen_response_schema_invalid');
|
|
606
|
+
if (response.ok !== true || response.status !== 'generated')
|
|
607
|
+
blockers.push(response.blocker || 'imagegen_response_not_generated');
|
|
608
|
+
const evidenceClass = String(response.evidence_class || '');
|
|
609
|
+
if (!evidenceClass)
|
|
610
|
+
blockers.push('imagegen_response_evidence_class_missing');
|
|
611
|
+
if (evidenceClass === 'mock_fixture')
|
|
612
|
+
blockers.push('imagegen_response_mock_fixture_not_full_evidence');
|
|
613
|
+
if (evidenceClass === 'non_codex_api_fallback')
|
|
614
|
+
blockers.push('imagegen_response_non_codex_api_fallback_not_full_evidence');
|
|
615
|
+
if (evidenceClass && evidenceClass !== 'codex_app_imagegen')
|
|
616
|
+
blockers.push(`imagegen_response_evidence_class_not_codex_app:${evidenceClass}`);
|
|
617
|
+
const source = String(response.output_source || '');
|
|
618
|
+
if (!['manual_attach', 'auto_discovered_generated_images'].includes(source))
|
|
619
|
+
blockers.push('imagegen_response_output_source_invalid');
|
|
620
|
+
const outputPath = String(response.output_image_path || '');
|
|
621
|
+
const expectedSha = String(response.output_sha256 || response.output_image_sha256 || '');
|
|
622
|
+
if (!outputPath)
|
|
623
|
+
blockers.push('imagegen_response_output_path_missing');
|
|
624
|
+
if (!expectedSha)
|
|
625
|
+
blockers.push('imagegen_response_output_sha256_missing');
|
|
626
|
+
if (outputPath) {
|
|
627
|
+
try {
|
|
628
|
+
const root = rootFromMissionDir(dir);
|
|
629
|
+
const absolute = path.isAbsolute(outputPath) ? outputPath : path.resolve(root, outputPath);
|
|
630
|
+
const actualSha = await sha256File(absolute);
|
|
631
|
+
if (expectedSha && actualSha !== expectedSha)
|
|
632
|
+
blockers.push('imagegen_response_output_sha256_mismatch');
|
|
633
|
+
const dims = await imageDimensions(absolute);
|
|
634
|
+
if (!Number.isFinite(Number(dims.width)) || !Number.isFinite(Number(dims.height)) || Number(dims.width) <= 0 || Number(dims.height) <= 0) {
|
|
635
|
+
blockers.push('imagegen_response_output_dimensions_invalid');
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
catch {
|
|
639
|
+
blockers.push('imagegen_response_output_file_unreadable');
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return {
|
|
643
|
+
ok: blockers.length === 0,
|
|
644
|
+
provider: response.provider || null,
|
|
645
|
+
evidence_class: evidenceClass || null,
|
|
646
|
+
output_source: source || null,
|
|
647
|
+
output_image_path: outputPath || null,
|
|
648
|
+
output_sha256: expectedSha || null,
|
|
649
|
+
blockers: [...new Set(blockers)]
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
function rootFromMissionDir(dir) {
|
|
653
|
+
const marker = `${path.sep}.sneakoscope${path.sep}missions${path.sep}`;
|
|
654
|
+
const idx = String(dir).indexOf(marker);
|
|
655
|
+
return idx >= 0 ? String(dir).slice(0, idx) : process.cwd();
|
|
656
|
+
}
|
|
482
657
|
function nextActionForGate(gate = {}) {
|
|
483
658
|
const blockers = gate?.blockers || [];
|
|
484
659
|
if (blockers.includes('missing_generated_annotated_review_images'))
|