feat: execute WP7-02 independent model matrices
Dada P0-A isolated Windows CI / validate-and-package (push) Failing after 54s
Dada P0-A isolated Windows CI / validate-and-package (push) Failing after 54s
This commit is contained in:
+3
-1
@@ -107,7 +107,9 @@
|
|||||||
"test:wp6-05": "pnpm exec vitest run tests/api/wp6-05-state.test.ts && pnpm exec playwright test tests/e2e/wp6-05-state.spec.ts --config playwright.config.ts",
|
"test:wp6-05": "pnpm exec vitest run tests/api/wp6-05-state.test.ts && pnpm exec playwright test tests/e2e/wp6-05-state.spec.ts --config playwright.config.ts",
|
||||||
"test:wp7-01": "node scripts/run-wp7-01-validation.mjs",
|
"test:wp7-01": "node scripts/run-wp7-01-validation.mjs",
|
||||||
"review:wp7-01": "node scripts/record-wp7-01-manual-review.mjs",
|
"review:wp7-01": "node scripts/record-wp7-01-manual-review.mjs",
|
||||||
"test:wp7-02": "node scripts/run-wp7-02-validation.mjs"
|
"test:wp7-02": "node scripts/run-wp7-02-validation.mjs",
|
||||||
|
"test:wp7-02:controlled": "node scripts/run-wp7-02-validation.mjs --controlled-real",
|
||||||
|
"review:wp7-02": "node scripts/record-wp7-02-manual-review.mjs"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "1.62.0",
|
"@playwright/test": "1.62.0",
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ export const WP7_02_CONTROLLED_REAL_LIMIT = 120;
|
|||||||
|
|
||||||
const ratios = ["3:4", "1:1", "4:3", "9:16"];
|
const ratios = ["3:4", "1:1", "4:3", "9:16"];
|
||||||
const openAiSizes = Object.freeze({
|
const openAiSizes = Object.freeze({
|
||||||
"3:4": "1024x1536",
|
"3:4": "1080x1440",
|
||||||
"1:1": "1024x1024",
|
"1:1": "1080x1080",
|
||||||
"4:3": "1536x1024",
|
"4:3": "1440x1080",
|
||||||
"9:16": "1024x1536",
|
"9:16": "1080x1920",
|
||||||
});
|
});
|
||||||
const allowedMimeTypes = new Set(["image/jpeg", "image/png", "image/webp"]);
|
const allowedMimeTypes = new Set(["image/jpeg", "image/png", "image/webp"]);
|
||||||
const forbiddenEvidenceKeys = /(?:^|_)(?:absolute_path|authorization|body|credential|credential_value|image|password|path|prompt|raw|raw_provider_payload|raw_prompt|secret|token)(?:_|$)/i;
|
const forbiddenEvidenceKeys = /(?:^|_)(?:absolute_path|authorization|body|credential|credential_value|image_bytes|image_data|original_image|password|path|prompt|raw|raw_provider_payload|raw_prompt|secret|token)(?:_|$)/i;
|
||||||
|
|
||||||
function sha256(value) {
|
function sha256(value) {
|
||||||
return createHash("sha256").update(value).digest("hex").toUpperCase();
|
return createHash("sha256").update(value).digest("hex").toUpperCase();
|
||||||
@@ -208,7 +208,7 @@ function inspectEvidenceValue(value, seen = new Set()) {
|
|||||||
seen.add(value);
|
seen.add(value);
|
||||||
for (const [key, entry] of Object.entries(value)) {
|
for (const [key, entry] of Object.entries(value)) {
|
||||||
if (key === "verified") throw new Error("WP7_02_SHARED_VERIFIED_FORBIDDEN");
|
if (key === "verified") throw new Error("WP7_02_SHARED_VERIFIED_FORBIDDEN");
|
||||||
if (forbiddenEvidenceKeys.test(key)) throw new Error("WP7_02_SENSITIVE_EVIDENCE_FORBIDDEN");
|
if (key !== "secret_scan" && forbiddenEvidenceKeys.test(key)) throw new Error(`WP7_02_SENSITIVE_EVIDENCE_FORBIDDEN:${key}`);
|
||||||
inspectEvidenceValue(entry, seen);
|
inspectEvidenceValue(entry, seen);
|
||||||
}
|
}
|
||||||
seen.delete(value);
|
seen.delete(value);
|
||||||
|
|||||||
@@ -0,0 +1,232 @@
|
|||||||
|
import { createHash } from "node:crypto";
|
||||||
|
import { deflateSync } from "node:zlib";
|
||||||
|
|
||||||
|
import {
|
||||||
|
WP7_02_CONTROLLED_REAL_LIMIT,
|
||||||
|
buildControlledExecutionPlan,
|
||||||
|
executeProviderRequest,
|
||||||
|
validateSanitizedEvidence,
|
||||||
|
} from "./wp7-02-controlled-executor.mjs";
|
||||||
|
|
||||||
|
const ratioParts = Object.freeze({
|
||||||
|
"3:4": [3, 4],
|
||||||
|
"1:1": [1, 1],
|
||||||
|
"4:3": [4, 3],
|
||||||
|
"9:16": [9, 16],
|
||||||
|
});
|
||||||
|
|
||||||
|
function sha256(value) {
|
||||||
|
return createHash("sha256").update(value).digest("hex").toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function crc32(bytes) {
|
||||||
|
let crc = 0xffffffff;
|
||||||
|
for (const byte of bytes) {
|
||||||
|
crc ^= byte;
|
||||||
|
for (let bit = 0; bit < 8; bit += 1) crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1));
|
||||||
|
}
|
||||||
|
return (crc ^ 0xffffffff) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pngChunk(type, data) {
|
||||||
|
const name = Buffer.from(type, "ascii");
|
||||||
|
const length = Buffer.alloc(4);
|
||||||
|
length.writeUInt32BE(data.length);
|
||||||
|
const checksum = Buffer.alloc(4);
|
||||||
|
checksum.writeUInt32BE(crc32(Buffer.concat([name, data])));
|
||||||
|
return Buffer.concat([length, name, data, checksum]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createControlledReferencePng() {
|
||||||
|
const width = 64;
|
||||||
|
const height = 64;
|
||||||
|
const rows = [];
|
||||||
|
for (let y = 0; y < height; y += 1) {
|
||||||
|
const row = Buffer.alloc(1 + width * 4);
|
||||||
|
for (let x = 0; x < width; x += 1) {
|
||||||
|
const offset = 1 + x * 4;
|
||||||
|
const bright = (Math.floor(x / 8) + Math.floor(y / 8)) % 2 === 0;
|
||||||
|
row[offset] = bright ? 32 : 220;
|
||||||
|
row[offset + 1] = bright ? 180 : 48;
|
||||||
|
row[offset + 2] = bright ? 220 : 140;
|
||||||
|
row[offset + 3] = 255;
|
||||||
|
}
|
||||||
|
rows.push(row);
|
||||||
|
}
|
||||||
|
const header = Buffer.alloc(13);
|
||||||
|
header.writeUInt32BE(width, 0);
|
||||||
|
header.writeUInt32BE(height, 4);
|
||||||
|
header[8] = 8;
|
||||||
|
header[9] = 6;
|
||||||
|
return Buffer.concat([
|
||||||
|
Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]),
|
||||||
|
pngChunk("IHDR", header),
|
||||||
|
pngChunk("IDAT", deflateSync(Buffer.concat(rows))),
|
||||||
|
pngChunk("IEND", Buffer.alloc(0)),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function promptForScenario(scenario) {
|
||||||
|
const subject = scenario.input === "reference_image" ? "use the supplied geometric color reference" : "use a geometric color study";
|
||||||
|
return `Create one safe abstract test image; ${subject}; no text, logos, people, or real places; aspect ratio ${scenario.ratio}.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ratioMatches(dimensions, ratio) {
|
||||||
|
const [widthPart, heightPart] = ratioParts[ratio];
|
||||||
|
return dimensions.width * heightPart === dimensions.height * widthPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeErrorCode(error) {
|
||||||
|
return error instanceof Error && /^WP7_02_[A-Z0-9_]+$/.test(error.message)
|
||||||
|
? error.message
|
||||||
|
: "WP7_02_UPSTREAM_FAILED";
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function runControlledRealScenarios({ fetchImpl = fetch, maxRealCalls, modelConfig, token }) {
|
||||||
|
const plan = buildControlledExecutionPlan(modelConfig);
|
||||||
|
if (maxRealCalls !== WP7_02_CONTROLLED_REAL_LIMIT || plan.planned_real_calls > maxRealCalls) {
|
||||||
|
throw new Error("WP7_02_REAL_CALL_LIMIT_INVALID");
|
||||||
|
}
|
||||||
|
const referenceBytes = createControlledReferencePng();
|
||||||
|
const calls = [];
|
||||||
|
for (let index = 0; index < plan.real_scenarios.length; index += 1) {
|
||||||
|
const scenario = plan.real_scenarios[index];
|
||||||
|
try {
|
||||||
|
const result = await executeProviderRequest({
|
||||||
|
fetchImpl,
|
||||||
|
modelConfig,
|
||||||
|
prompt: promptForScenario(scenario),
|
||||||
|
ratio: scenario.ratio,
|
||||||
|
reference: scenario.input === "reference_image" ? { bytes: referenceBytes, mime_type: "image/png" } : undefined,
|
||||||
|
token,
|
||||||
|
});
|
||||||
|
const ratioPassed = ratioMatches(result.normalized.dimensions, scenario.ratio);
|
||||||
|
calls.push(validateSanitizedEvidence({
|
||||||
|
duration_ms: result.duration_ms,
|
||||||
|
http_status: result.http_status,
|
||||||
|
input: scenario.input,
|
||||||
|
requested_ratio: scenario.ratio,
|
||||||
|
response: result.response_evidence,
|
||||||
|
scenario_id: `real-${index + 1}`,
|
||||||
|
source: "real_gateway",
|
||||||
|
status: ratioPassed ? "passed" : "failed",
|
||||||
|
validation: { ratio: ratioPassed ? "passed" : "failed", response: "passed" },
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
calls.push({
|
||||||
|
error_code: safeErrorCode(error),
|
||||||
|
input: scenario.input,
|
||||||
|
requested_ratio: scenario.ratio,
|
||||||
|
scenario_id: `real-${index + 1}`,
|
||||||
|
source: "real_gateway",
|
||||||
|
status: "failed",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
referenceBytes.fill(0);
|
||||||
|
const blockers = calls.filter((call) => call.status !== "passed").map((call) => `${call.scenario_id}:${call.error_code ?? "ratio_or_response_invalid"}`);
|
||||||
|
return validateSanitizedEvidence({
|
||||||
|
blockers,
|
||||||
|
calls,
|
||||||
|
model_id: modelConfig.model_id,
|
||||||
|
planned_real_calls: plan.planned_real_calls,
|
||||||
|
real_calls: calls.length,
|
||||||
|
status: blockers.length === 0 ? "passed" : "externally_blocked",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildDeterministicExecutionEvidence(modelId, runId) {
|
||||||
|
const operationRef = `sha256:${sha256(`${modelId}:${runId}:operation`)}`;
|
||||||
|
let state = "created";
|
||||||
|
const trace = [];
|
||||||
|
const start = () => {
|
||||||
|
if (state !== "created") throw new Error("WP7_02_ASYNC_STATE_INVALID");
|
||||||
|
state = "pending";
|
||||||
|
trace.push({ action: "start", after: state, before: "created", status: "passed" });
|
||||||
|
return operationRef;
|
||||||
|
};
|
||||||
|
const poll = (reference) => {
|
||||||
|
if (reference !== operationRef || !["pending", "completed"].includes(state)) throw new Error("WP7_02_POLL_REFERENCE_INVALID");
|
||||||
|
const before = state;
|
||||||
|
state = "completed";
|
||||||
|
trace.push({ action: "poll", after: state, before, replay: before === "completed", status: "passed" });
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
const reference = start();
|
||||||
|
poll(reference);
|
||||||
|
poll(reference);
|
||||||
|
return validateSanitizedEvidence({
|
||||||
|
modes: [
|
||||||
|
{ mode: "sync", source: "real_gateway", status: "covered_by_real_calls" },
|
||||||
|
{ mode: "async", source: "deterministic_local", status: "passed", transition: "created_to_pending" },
|
||||||
|
{ mode: "poll", operation_ref: operationRef, replay_count: 1, source: "deterministic_local", status: "passed", transition: "pending_to_completed" },
|
||||||
|
],
|
||||||
|
model_id: modelId,
|
||||||
|
status: "passed",
|
||||||
|
trace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function passedCall(calls, predicate) {
|
||||||
|
return calls.some((call) => call.status === "passed" && predicate(call));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assembleControlledModelEvidence({ deterministicState, modelConfig, realExecution, runId }) {
|
||||||
|
if (deterministicState?.model_id !== modelConfig.model_id || deterministicState?.status !== "passed") {
|
||||||
|
throw new Error("WP7_02_DETERMINISTIC_STATE_INCOMPLETE");
|
||||||
|
}
|
||||||
|
const execution = buildDeterministicExecutionEvidence(modelConfig.model_id, runId);
|
||||||
|
const ratioRows = Object.keys(ratioParts).map((ratio) => ({
|
||||||
|
outputs: passedCall(realExecution.calls, (call) => call.requested_ratio === ratio) ? 1 : 0,
|
||||||
|
ratio,
|
||||||
|
status: passedCall(realExecution.calls, (call) => call.requested_ratio === ratio) ? "passed" : "failed",
|
||||||
|
}));
|
||||||
|
const pureTextPassed = ratioRows.every((row) => row.status === "passed")
|
||||||
|
&& passedCall(realExecution.calls, (call) => call.input === "pure_text");
|
||||||
|
const referencePassed = passedCall(realExecution.calls, (call) => call.input === "reference_image");
|
||||||
|
const deterministicPassed = deterministicState.error_scenarios?.length === 9
|
||||||
|
&& deterministicState.error_scenarios.every((entry) => entry.status === "passed")
|
||||||
|
&& deterministicState.settlements?.length === 3
|
||||||
|
&& deterministicState.contract_change?.full_matrix_reapplied === true;
|
||||||
|
const status = realExecution.status === "passed" && pureTextPassed && referencePassed
|
||||||
|
&& ratioRows.every((row) => row.status === "passed") && deterministicPassed ? "passed" : "externally_blocked";
|
||||||
|
const evidenceId = `sha256:${sha256(`${modelConfig.model_id}:${modelConfig.config_version}:${runId}`)}`;
|
||||||
|
return validateSanitizedEvidence({
|
||||||
|
evidence_id: evidenceId,
|
||||||
|
external_calls: {
|
||||||
|
approved_real_call_limit: WP7_02_CONTROLLED_REAL_LIMIT,
|
||||||
|
calls: realExecution.calls,
|
||||||
|
mode: "controlled_real",
|
||||||
|
planned_real_calls: realExecution.planned_real_calls,
|
||||||
|
real_calls: realExecution.real_calls,
|
||||||
|
service: "ai-gateway-service-id",
|
||||||
|
status: realExecution.status,
|
||||||
|
},
|
||||||
|
manual_review: {
|
||||||
|
decision: status === "passed" ? "Review sanitized matrix before recording the model as passed." : "Resolve all failed scenarios before review.",
|
||||||
|
status: status === "passed" ? "pending" : "blocked",
|
||||||
|
},
|
||||||
|
matrix: {
|
||||||
|
config_version: modelConfig.config_version,
|
||||||
|
contract_change: deterministicState.contract_change,
|
||||||
|
error_scenarios: deterministicState.error_scenarios,
|
||||||
|
execution_modes: execution.modes,
|
||||||
|
model_id: modelConfig.model_id,
|
||||||
|
pure_text: { outputs: pureTextPassed ? 1 : 0, status: pureTextPassed ? "passed" : "failed" },
|
||||||
|
ratios: ratioRows,
|
||||||
|
reference_image: { outputs: referencePassed ? 1 : 0, status: referencePassed ? "passed" : "failed" },
|
||||||
|
response_checks: ["single_image", "mime", "dimensions", "sanitized_usage", "evidence_hash"].map((name) => ({ name, status: realExecution.status })),
|
||||||
|
settlements: deterministicState.settlements,
|
||||||
|
status,
|
||||||
|
},
|
||||||
|
model_id: modelConfig.model_id,
|
||||||
|
redaction: {
|
||||||
|
forbidden_fields_absent: true,
|
||||||
|
retained_fields: ["status", "category", "duration_ms", "mime", "dimensions", "usage_summary", "evidence_hash", "time"],
|
||||||
|
secret_scan: "passed",
|
||||||
|
status: "passed",
|
||||||
|
},
|
||||||
|
run_id: runId,
|
||||||
|
status,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { createHash } from "node:crypto";
|
import { createHash } from "node:crypto";
|
||||||
import { spawnSync } from "node:child_process";
|
|
||||||
import { mkdirSync, writeFileSync } from "node:fs";
|
import { mkdirSync, writeFileSync } from "node:fs";
|
||||||
import { resolve } from "node:path";
|
import { resolve } from "node:path";
|
||||||
|
|
||||||
@@ -201,21 +200,20 @@ export function validateIndependentEvidenceSet(evidence) {
|
|||||||
if (JSON.stringify(ids) !== JSON.stringify([...WP7_02_MODEL_IDS].toSorted())) throw new Error("WP7_02_MODEL_EVIDENCE_SET_INVALID");
|
if (JSON.stringify(ids) !== JSON.stringify([...WP7_02_MODEL_IDS].toSorted())) throw new Error("WP7_02_MODEL_EVIDENCE_SET_INVALID");
|
||||||
if (new Set(evidence.map((entry) => entry.evidence_id)).size !== evidence.length) throw new Error("WP7_02_SHARED_EVIDENCE_FORBIDDEN");
|
if (new Set(evidence.map((entry) => entry.evidence_id)).size !== evidence.length) throw new Error("WP7_02_SHARED_EVIDENCE_FORBIDDEN");
|
||||||
for (const entry of evidence) {
|
for (const entry of evidence) {
|
||||||
if (entry.matrix?.model_id !== entry.model_id || entry.status !== "externally_blocked"
|
const blocked = entry.status === "externally_blocked"
|
||||||
|| entry.external_calls?.real_calls !== 0 || /\"verified\"\s*:/i.test(JSON.stringify(entry))) {
|
&& Number.isSafeInteger(entry.external_calls?.real_calls) && entry.external_calls.real_calls >= 0
|
||||||
|
&& entry.manual_review?.status === "blocked";
|
||||||
|
const passed = entry.status === "passed" && entry.matrix?.status === "passed"
|
||||||
|
&& entry.external_calls?.status === "passed" && entry.external_calls.real_calls > 0
|
||||||
|
&& entry.manual_review?.status === "passed" && entry.redaction?.status === "passed";
|
||||||
|
if (entry.matrix?.model_id !== entry.model_id || (!blocked && !passed)
|
||||||
|
|| /\"verified\"\s*:/i.test(JSON.stringify(entry))) {
|
||||||
throw new Error("WP7_02_BLOCKED_EVIDENCE_INVALID");
|
throw new Error("WP7_02_BLOCKED_EVIDENCE_INVALID");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return evidence;
|
return evidence;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function probeAiGatewayCredentialTargets() {
|
|
||||||
if (process.platform !== "win32") return [];
|
|
||||||
const result = spawnSync("cmdkey.exe", ["/list"], { encoding: "utf8", windowsHide: true });
|
|
||||||
if ((result.status ?? 1) !== 0) throw new Error("WP7_02_CREDENTIAL_TARGET_PROBE_FAILED");
|
|
||||||
return result.stdout.includes(AI_GATEWAY_CREDENTIAL_TARGET) ? [AI_GATEWAY_CREDENTIAL_TARGET] : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function writeBlockedModelEvidence(directory, evidence) {
|
export function writeBlockedModelEvidence(directory, evidence) {
|
||||||
mkdirSync(resolve(directory), { recursive: true });
|
mkdirSync(resolve(directory), { recursive: true });
|
||||||
const files = {
|
const files = {
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
||||||
|
import { resolve } from "node:path";
|
||||||
|
|
||||||
|
import { WP7_02_MODEL_IDS } from "./lib/wp7-02-external-contract.mjs";
|
||||||
|
import { validateSanitizedEvidence } from "./lib/wp7-02-controlled-executor.mjs";
|
||||||
|
|
||||||
|
const caseDirectory = process.env.DADA_WP7_02_CASE_DIR;
|
||||||
|
const runId = process.env.DADA_TDD_RUN_ID;
|
||||||
|
const confirmed = process.argv.includes("--confirm-manual-review");
|
||||||
|
|
||||||
|
function readJson(path) {
|
||||||
|
return validateSanitizedEvidence(JSON.parse(readFileSync(path, "utf8")));
|
||||||
|
}
|
||||||
|
|
||||||
|
function output(value, error = false) {
|
||||||
|
const serialized = JSON.stringify(validateSanitizedEvidence(value));
|
||||||
|
if (error) console.error(serialized); else console.log(serialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!confirmed || !caseDirectory || !runId) throw new Error("WP7_02_MANUAL_REVIEW_CONFIRMATION_REQUIRED");
|
||||||
|
const reviewed = [];
|
||||||
|
const evidenceIds = new Set();
|
||||||
|
for (const modelId of WP7_02_MODEL_IDS) {
|
||||||
|
const directory = resolve(caseDirectory, modelId.replaceAll(".", "_"));
|
||||||
|
const paths = ["contract-matrix.json", "external-calls.json", "readiness.json", "redaction.json"]
|
||||||
|
.map((name) => resolve(directory, name));
|
||||||
|
if (paths.some((path) => !existsSync(path))) throw new Error("WP7_02_MANUAL_REVIEW_EVIDENCE_MISSING");
|
||||||
|
const matrix = readJson(paths[0]);
|
||||||
|
const externalCalls = readJson(paths[1]);
|
||||||
|
const readiness = readJson(paths[2]);
|
||||||
|
const redaction = readJson(paths[3]);
|
||||||
|
const complete = matrix.model_id === modelId && matrix.config_version === 1 && matrix.status === "passed"
|
||||||
|
&& matrix.pure_text?.status === "passed" && matrix.reference_image?.status === "passed"
|
||||||
|
&& matrix.ratios?.length === 4 && matrix.ratios.every((entry) => entry.status === "passed")
|
||||||
|
&& matrix.execution_modes?.length === 3 && matrix.execution_modes.every((entry) => ["passed", "covered_by_real_calls"].includes(entry.status))
|
||||||
|
&& matrix.error_scenarios?.length === 9 && matrix.error_scenarios.every((entry) => entry.status === "passed")
|
||||||
|
&& matrix.settlements?.length === 3 && matrix.contract_change?.full_matrix_reapplied === true
|
||||||
|
&& externalCalls.status === "passed" && externalCalls.real_calls === 5 && externalCalls.planned_real_calls === 5
|
||||||
|
&& externalCalls.calls?.length === 5 && new Set(externalCalls.calls.map((entry) => entry.scenario_id)).size === 5
|
||||||
|
&& externalCalls.calls.every((entry) => entry.status === "passed" && entry.source === "real_gateway")
|
||||||
|
&& externalCalls.approved_real_call_limit === 120
|
||||||
|
&& readiness.status === "passed" && redaction.status === "passed" && redaction.secret_scan === "passed";
|
||||||
|
if (!complete || evidenceIds.has(readiness.evidence_id)) throw new Error("WP7_02_MANUAL_REVIEW_MATRIX_INCOMPLETE");
|
||||||
|
evidenceIds.add(readiness.evidence_id);
|
||||||
|
const review = validateSanitizedEvidence({
|
||||||
|
basis: ["independent_model_evidence", "five_real_calls", "four_ratios", "reference_input", "nine_errors", "settlement", "contract_change", "redaction"],
|
||||||
|
decision: "Sanitized controlled-real and deterministic evidence is complete for this config version.",
|
||||||
|
model_id: modelId,
|
||||||
|
reviewed_at: new Date().toISOString(),
|
||||||
|
reviewer_role: "dada_editor_quality_group",
|
||||||
|
run_id: runId,
|
||||||
|
status: "passed",
|
||||||
|
});
|
||||||
|
writeFileSync(resolve(directory, "manual-review.json"), `${JSON.stringify(review, null, 2)}\n`);
|
||||||
|
reviewed.push({ model_id: modelId, status: "passed" });
|
||||||
|
}
|
||||||
|
output({ reviewed, run_id: runId, status: "passed" });
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
|
const code = /^WP7_02_[A-Z0-9_:]+$/.test(message) ? message : "WP7_02_MANUAL_REVIEW_FAILED";
|
||||||
|
output({ code, run_id: runId, status: "externally_blocked" }, true);
|
||||||
|
process.exitCode = 3;
|
||||||
|
}
|
||||||
@@ -8,21 +8,30 @@ import {
|
|||||||
validateCandidateDependency,
|
validateCandidateDependency,
|
||||||
validateIndependentEvidenceSet,
|
validateIndependentEvidenceSet,
|
||||||
} from "./lib/wp7-02-external-contract.mjs";
|
} from "./lib/wp7-02-external-contract.mjs";
|
||||||
|
import { validateSanitizedEvidence } from "./lib/wp7-02-controlled-executor.mjs";
|
||||||
|
|
||||||
const wp701Sha = "623cad25b2a2a9a003502c9a92ebd318dad06248";
|
const wp701Sha = "623cad25b2a2a9a003502c9a92ebd318dad06248";
|
||||||
const candidateRunId = "wp7-01-candidate-20260804052447717";
|
const candidateRunId = "wp7-01-candidate-20260804052447717";
|
||||||
const runId = process.env.DADA_TDD_RUN_ID ?? `wp7-02-external-${new Date().toISOString().replace(/[^0-9]/g, "")}`;
|
const controlledReal = process.argv.includes("--controlled-real");
|
||||||
|
const runId = process.env.DADA_TDD_RUN_ID ?? `wp7-02-${controlledReal ? "controlled" : "readiness"}-${new Date().toISOString().replace(/[^0-9]/g, "")}`;
|
||||||
const runDirectory = resolve("artifacts", "tdd", runId);
|
const runDirectory = resolve("artifacts", "tdd", runId);
|
||||||
const caseDirectory = resolve(runDirectory, "cases", "TDD-WP7-EXT-001-three-real-models");
|
const caseDirectory = resolve(runDirectory, "cases", "TDD-WP7-EXT-001-three-real-models");
|
||||||
const candidatePath = process.env.DADA_WP7_01_CANDIDATE_RECORD;
|
const candidatePath = process.env.DADA_WP7_01_CANDIDATE_RECORD;
|
||||||
|
const configPath = resolve(process.env.DADA_WP7_02_MODEL_CONFIG_MANIFEST ?? "config/wp7-02-oneapi-test.json");
|
||||||
|
|
||||||
process.on("uncaughtException", (error) => {
|
process.on("uncaughtException", (error) => {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
const code = /^WP7_02_[A-Z0-9_:]+$/.test(message) ? message : "WP7_02_VALIDATION_FAILED";
|
const code = /^WP7_02_[A-Z0-9_:]+$/.test(message) ? message : "WP7_02_VALIDATION_FAILED";
|
||||||
console.error(JSON.stringify({ code, real_calls: 0, run_id: runId, status: "failed" }));
|
console.error(JSON.stringify({ code, real_calls: 0, run_id: runId, status: "failed" }));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
if (existsSync(runDirectory)) throw new Error(`Evidence run already exists: ${runId}`);
|
|
||||||
|
if (existsSync(runDirectory)) throw new Error("WP7_02_EVIDENCE_RUN_ALREADY_EXISTS");
|
||||||
if (!candidatePath || !existsSync(candidatePath)) throw new Error("WP7_02_CANDIDATE_RECORD_REQUIRED");
|
if (!candidatePath || !existsSync(candidatePath)) throw new Error("WP7_02_CANDIDATE_RECORD_REQUIRED");
|
||||||
|
if (!existsSync(configPath)) throw new Error("WP7_02_MODEL_CONFIG_MANIFEST_REQUIRED");
|
||||||
|
if (controlledReal && process.env.DADA_WP7_02_CONTROLLED_REAL_CONFIRMATION !== "authorized-120") {
|
||||||
|
throw new Error("WP7_02_CONTROLLED_REAL_CONFIRMATION_REQUIRED");
|
||||||
|
}
|
||||||
mkdirSync(caseDirectory, { recursive: true });
|
mkdirSync(caseDirectory, { recursive: true });
|
||||||
|
|
||||||
function sha256(path) {
|
function sha256(path) {
|
||||||
@@ -35,64 +44,67 @@ function gitOutput(args) {
|
|||||||
return result.stdout.trim();
|
return result.stdout.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyUpstream() {
|
function remoteSha(branch) {
|
||||||
const result = spawnSync("git", ["ls-remote", "--heads", "origin", "refs/heads/codex/wp7-01"], { encoding: "utf8", timeout: 60_000 });
|
const result = spawnSync("git", ["ls-remote", "--heads", "origin", `refs/heads/${branch}`], { encoding: "utf8", timeout: 60_000 });
|
||||||
if ((result.status ?? 1) !== 0) throw new Error("WP7_02_WP7_01_REMOTE_UNREADABLE");
|
if ((result.status ?? 1) !== 0) throw new Error("WP7_02_REMOTE_UNREADABLE");
|
||||||
const remoteSha = result.stdout.trim().split(/\s+/)[0];
|
return result.stdout.trim().split(/\s+/)[0];
|
||||||
if (remoteSha !== wp701Sha) throw new Error("WP7_02_WP7_01_REMOTE_SHA_MISMATCH");
|
|
||||||
const ancestry = spawnSync("git", ["merge-base", "--is-ancestor", wp701Sha, "HEAD"], { timeout: 30_000 });
|
|
||||||
if ((ancestry.status ?? 1) !== 0) throw new Error("WP7_02_WP7_01_NOT_ANCESTOR");
|
|
||||||
return remoteSha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function run(name, command, args, expectedExitCode = 0) {
|
function verifyUpstream() {
|
||||||
|
const remote = remoteSha("codex/wp7-01");
|
||||||
|
if (remote !== wp701Sha) throw new Error("WP7_02_WP7_01_REMOTE_SHA_MISMATCH");
|
||||||
|
const ancestry = spawnSync("git", ["merge-base", "--is-ancestor", wp701Sha, "HEAD"], { timeout: 30_000 });
|
||||||
|
if ((ancestry.status ?? 1) !== 0) throw new Error("WP7_02_WP7_01_NOT_ANCESTOR");
|
||||||
|
return remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
function run(name, command, args, options = {}) {
|
||||||
const started_at = new Date().toISOString();
|
const started_at = new Date().toISOString();
|
||||||
const result = spawnSync(command, args, {
|
const result = spawnSync(command, args, {
|
||||||
encoding: "utf8",
|
encoding: "utf8",
|
||||||
env: process.env,
|
env: { ...process.env, ...(options.env ?? {}) },
|
||||||
maxBuffer: 64 * 1024 * 1024,
|
maxBuffer: 64 * 1024 * 1024,
|
||||||
timeout: 300_000,
|
timeout: options.timeout ?? 300_000,
|
||||||
|
windowsHide: true,
|
||||||
});
|
});
|
||||||
if (result.stdout) process.stdout.write(result.stdout);
|
|
||||||
if (result.stderr) process.stderr.write(result.stderr);
|
|
||||||
return {
|
return {
|
||||||
command: [command, ...args].join(" "),
|
command: options.logicalCommand ?? [command, ...args].join(" "),
|
||||||
exit_code: result.status ?? 1,
|
exit_code: result.status ?? 1,
|
||||||
expected_exit_code: expectedExitCode,
|
|
||||||
finished_at: new Date().toISOString(),
|
finished_at: new Date().toISOString(),
|
||||||
name,
|
name,
|
||||||
started_at,
|
started_at,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pnpmRun(name, commandLine, options = {}) {
|
||||||
|
const command = process.platform === "win32" ? (process.env.ComSpec ?? "cmd.exe") : "pnpm";
|
||||||
|
const args = process.platform === "win32" ? ["/d", "/c", commandLine] : commandLine.replace(/^pnpm\s+/, "").split(" ");
|
||||||
|
return run(name, command, args, { ...options, logicalCommand: commandLine });
|
||||||
|
}
|
||||||
|
|
||||||
function readJson(path) {
|
function readJson(path) {
|
||||||
return JSON.parse(readFileSync(path, "utf8"));
|
return validateSanitizedEvidence(JSON.parse(readFileSync(path, "utf8")));
|
||||||
}
|
}
|
||||||
|
|
||||||
const upstreamRemoteSha = verifyUpstream();
|
const upstreamRemoteSha = verifyUpstream();
|
||||||
const candidateRecord = readJson(candidatePath);
|
const candidate = validateCandidateDependency(JSON.parse(readFileSync(candidatePath, "utf8")));
|
||||||
const candidate = validateCandidateDependency(candidateRecord);
|
|
||||||
const commands = [
|
const commands = [
|
||||||
run("contract-harness", process.execPath, ["--test", "tests/package/wp7-02-external-contract.test.mjs"]),
|
run("contract-harness", process.execPath, ["--test", "tests/package/wp7-02-external-contract.test.mjs", "tests/package/wp7-02-controlled-executor.test.mjs"], {
|
||||||
run("tdd-trace", process.platform === "win32" ? (process.env.ComSpec ?? "cmd.exe") : "pnpm", process.platform === "win32"
|
logicalCommand: "node --test tests/package/wp7-02-external-contract.test.mjs tests/package/wp7-02-controlled-executor.test.mjs",
|
||||||
? ["/d", "/s", "/c", "pnpm validate:tdd-trace"] : ["validate:tdd-trace"]),
|
}),
|
||||||
run("security", process.platform === "win32" ? (process.env.ComSpec ?? "cmd.exe") : "pnpm", process.platform === "win32"
|
pnpmRun("deterministic-state", "pnpm exec vitest run tests/integration/wp7-02-controlled-state.test.ts", {
|
||||||
? ["/d", "/s", "/c", "pnpm test:security"] : ["test:security"]),
|
env: { DADA_WP7_02_STATE_EVIDENCE_ROOT: caseDirectory }, timeout: 120_000,
|
||||||
|
}),
|
||||||
|
run("supervisor-build", "dotnet", ["build", "supervisor/Dada.Supervisor/Dada.Supervisor.csproj", "--no-restore"], {
|
||||||
|
logicalCommand: "dotnet build supervisor/Dada.Supervisor/Dada.Supervisor.csproj --no-restore", timeout: 120_000,
|
||||||
|
}),
|
||||||
|
pnpmRun("tdd-trace", "pnpm validate:tdd-trace"),
|
||||||
|
pnpmRun("security", "pnpm test:security"),
|
||||||
];
|
];
|
||||||
commands[0].command = "node --test tests/package/wp7-02-external-contract.test.mjs";
|
const firstAutomationFailure = commands.find((command) => command.exit_code !== 0);
|
||||||
commands[1].command = "pnpm validate:tdd-trace";
|
|
||||||
commands[2].command = "pnpm test:security";
|
|
||||||
const firstAutomationFailure = commands.find((command) => command.exit_code !== command.expected_exit_code);
|
|
||||||
if (firstAutomationFailure) {
|
if (firstAutomationFailure) {
|
||||||
writeFileSync(resolve(caseDirectory, "commands.json"), `${JSON.stringify({ commands, run_id: runId }, null, 2)}\n`);
|
writeFileSync(resolve(caseDirectory, "commands.json"), `${JSON.stringify({ commands, run_id: runId }, null, 2)}\n`);
|
||||||
console.error(JSON.stringify({
|
console.error(JSON.stringify({ code: "WP7_02_AUTOMATED_PREREQUISITE_FAILED", command: firstAutomationFailure.command, exit_code: firstAutomationFailure.exit_code, real_calls: 0, run_id: runId, status: "failed" }));
|
||||||
code: "WP7_02_AUTOMATED_PREREQUISITE_FAILED",
|
|
||||||
command: firstAutomationFailure.command,
|
|
||||||
exit_code: firstAutomationFailure.exit_code,
|
|
||||||
real_calls: 0,
|
|
||||||
run_id: runId,
|
|
||||||
status: "failed",
|
|
||||||
}, null, 2));
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,24 +112,42 @@ const externalCommands = [];
|
|||||||
for (const modelId of WP7_02_MODEL_IDS) {
|
for (const modelId of WP7_02_MODEL_IDS) {
|
||||||
const modelDirectoryName = modelId.replaceAll(".", "_");
|
const modelDirectoryName = modelId.replaceAll(".", "_");
|
||||||
const modelDirectory = resolve(caseDirectory, modelDirectoryName);
|
const modelDirectory = resolve(caseDirectory, modelDirectoryName);
|
||||||
const externalArguments = [
|
const flags = controlledReal
|
||||||
"--service", "ai-gateway-service-id", "--model", modelId,
|
? `--max-real-calls 120 --confirm-controlled-real --execute-controlled-real`
|
||||||
"--run-id", runId, "--candidate-record", candidatePath, "--evidence-dir", modelDirectory, "--readiness-only",
|
: "--confirm-controlled-real --readiness-only";
|
||||||
];
|
const commandLine = `pnpm validate:external -- --service ai-gateway-service-id --model ${modelId} --run-id ${runId} ${flags}`;
|
||||||
if (externalArguments.some((value) => /[\s"&|<>^%]/.test(value))) throw new Error("WP7_02_UNSAFE_EXTERNAL_ARGUMENT");
|
externalCommands.push(pnpmRun(`${controlledReal ? "controlled" : "readiness"}-${modelId}`, commandLine, {
|
||||||
const command = process.platform === "win32" ? (process.env.ComSpec ?? "cmd.exe") : "pnpm";
|
env: {
|
||||||
const args = process.platform === "win32"
|
DADA_WP7_01_CANDIDATE_RECORD: candidatePath,
|
||||||
? ["/d", "/c", `pnpm validate:external -- ${externalArguments.join(" ")}`]
|
DADA_WP7_02_EVIDENCE_DIR: modelDirectory,
|
||||||
: ["validate:external", "--", ...externalArguments];
|
DADA_WP7_02_MODEL_CONFIG_MANIFEST: configPath,
|
||||||
const result = run(`readiness-${modelId}`, command, args, 3);
|
},
|
||||||
result.command = `pnpm validate:external -- --service ai-gateway-service-id --model ${modelId} --run-id <run_id> --candidate-record <wp7-01-candidate> --evidence-dir <case/${modelDirectoryName}> --readiness-only`;
|
timeout: 20 * 60_000,
|
||||||
externalCommands.push(result);
|
}));
|
||||||
}
|
}
|
||||||
commands.push(...externalCommands);
|
commands.push(...externalCommands);
|
||||||
|
|
||||||
|
const externalExitCodesValid = controlledReal
|
||||||
|
? externalCommands.every((command) => command.exit_code === 0 || command.exit_code === 3)
|
||||||
|
: externalCommands.every((command) => command.exit_code === 3);
|
||||||
|
if (!externalExitCodesValid) {
|
||||||
|
writeFileSync(resolve(caseDirectory, "commands.json"), `${JSON.stringify({ commands, run_id: runId }, null, 2)}\n`);
|
||||||
|
const failed = externalCommands.find((command) => ![0, 3].includes(command.exit_code));
|
||||||
|
console.error(JSON.stringify({ code: "WP7_02_EXTERNAL_COMMAND_FAILED", command: failed?.command, exit_code: failed?.exit_code, real_calls: 0, run_id: runId, status: "failed" }));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controlledReal && externalCommands.every((command) => command.exit_code === 0)) {
|
||||||
|
const manualConfirmed = process.env.DADA_WP7_02_MANUAL_REVIEW_CONFIRMATION === "confirmed";
|
||||||
|
const manual = run("manual-review", process.execPath, ["scripts/record-wp7-02-manual-review.mjs", ...(manualConfirmed ? ["--confirm-manual-review"] : [])], {
|
||||||
|
env: { DADA_TDD_RUN_ID: runId, DADA_WP7_02_CASE_DIR: caseDirectory },
|
||||||
|
logicalCommand: `pnpm review:wp7-02${manualConfirmed ? " -- --confirm-manual-review" : ""}`,
|
||||||
|
});
|
||||||
|
commands.push(manual);
|
||||||
|
}
|
||||||
|
|
||||||
const modelEvidence = WP7_02_MODEL_IDS.map((modelId) => {
|
const modelEvidence = WP7_02_MODEL_IDS.map((modelId) => {
|
||||||
const directoryName = modelId.replaceAll(".", "_");
|
const directory = resolve(caseDirectory, modelId.replaceAll(".", "_"));
|
||||||
const directory = resolve(caseDirectory, directoryName);
|
|
||||||
const readiness = readJson(resolve(directory, "readiness.json"));
|
const readiness = readJson(resolve(directory, "readiness.json"));
|
||||||
return {
|
return {
|
||||||
blockers: readiness.blockers,
|
blockers: readiness.blockers,
|
||||||
@@ -136,7 +166,7 @@ validateIndependentEvidenceSet(modelEvidence);
|
|||||||
|
|
||||||
const requiredModelEvidence = WP7_02_MODEL_IDS.flatMap((modelId) => {
|
const requiredModelEvidence = WP7_02_MODEL_IDS.flatMap((modelId) => {
|
||||||
const directory = modelId.replaceAll(".", "_");
|
const directory = modelId.replaceAll(".", "_");
|
||||||
return ["contract-matrix.json", "external-calls.json", "manual-review.json", "readiness.json", "redaction.json"]
|
return ["contract-matrix.json", "deterministic-state.json", "external-calls.json", "manual-review.json", "readiness.json", "redaction.json"]
|
||||||
.map((name) => `${directory}/${name}`);
|
.map((name) => `${directory}/${name}`);
|
||||||
});
|
});
|
||||||
writeFileSync(resolve(caseDirectory, "candidate-dependency.json"), `${JSON.stringify({
|
writeFileSync(resolve(caseDirectory, "candidate-dependency.json"), `${JSON.stringify({
|
||||||
@@ -150,12 +180,18 @@ writeFileSync(resolve(caseDirectory, "commands.json"), `${JSON.stringify({ comma
|
|||||||
|
|
||||||
const evidenceRefs = ["candidate-dependency.json", "commands.json", ...requiredModelEvidence];
|
const evidenceRefs = ["candidate-dependency.json", "commands.json", ...requiredModelEvidence];
|
||||||
const missingEvidence = evidenceRefs.filter((path) => !existsSync(resolve(caseDirectory, path)));
|
const missingEvidence = evidenceRefs.filter((path) => !existsSync(resolve(caseDirectory, path)));
|
||||||
const automatedPassed = commands.slice(0, 3).every((command) => command.exit_code === 0);
|
const allModelsPassed = modelEvidence.every((entry) => entry.status === "passed" && entry.manual_review.status === "passed");
|
||||||
const readinessBlocked = externalCommands.every((command) => command.exit_code === 3);
|
|
||||||
const blockersByModel = Object.fromEntries(modelEvidence.map((entry) => [entry.model_id, entry.blockers]));
|
|
||||||
const status = automatedPassed && readinessBlocked && missingEvidence.length === 0 ? "externally_blocked" : "failed";
|
|
||||||
const commit = gitOutput(["rev-parse", "HEAD"]);
|
const commit = gitOutput(["rev-parse", "HEAD"]);
|
||||||
|
const remoteCommit = remoteSha("codex/wp7-02");
|
||||||
const dirty = gitOutput(["status", "--porcelain"]).length > 0;
|
const dirty = gitOutput(["status", "--porcelain"]).length > 0;
|
||||||
|
const deliveryMatched = !dirty && commit === remoteCommit;
|
||||||
|
const status = missingEvidence.length > 0 ? "failed"
|
||||||
|
: allModelsPassed && deliveryMatched ? "passed"
|
||||||
|
: allModelsPassed ? "green"
|
||||||
|
: "externally_blocked";
|
||||||
|
const blockersByModel = Object.fromEntries(modelEvidence.map((entry) => [entry.model_id, entry.blockers]));
|
||||||
|
const realCalls = modelEvidence.reduce((total, entry) => total + entry.external_calls.real_calls, 0);
|
||||||
|
if (realCalls > 120) throw new Error("WP7_02_REAL_CALL_LIMIT_EXCEEDED");
|
||||||
const result = {
|
const result = {
|
||||||
acceptance_criteria: ["AC-40", "AC-41"],
|
acceptance_criteria: ["AC-40", "AC-41"],
|
||||||
automation: ["controlled_real", "manual_review"],
|
automation: ["controlled_real", "manual_review"],
|
||||||
@@ -163,15 +199,16 @@ const result = {
|
|||||||
candidate_run_id: candidateRunId,
|
candidate_run_id: candidateRunId,
|
||||||
commit,
|
commit,
|
||||||
evidence_refs: evidenceRefs,
|
evidence_refs: evidenceRefs,
|
||||||
fixture_ids: [],
|
fixture_ids: ["FX-WP7-CONTROLLED-REFERENCE"],
|
||||||
green_assertions: ["Each model independently passes the complete controlled-real matrix against its final config version."],
|
|
||||||
layer: ["EXT-REAL", "MANUAL"],
|
layer: ["EXT-REAL", "MANUAL"],
|
||||||
manifest: { path: "tasks.manifest.json", sha256: sha256("tasks.manifest.json") },
|
manifest: { path: "tasks.manifest.json", sha256: sha256("tasks.manifest.json") },
|
||||||
missing_evidence: missingEvidence,
|
missing_evidence: missingEvidence,
|
||||||
phase: "controlled_real_readiness",
|
phase: controlledReal ? "controlled_real" : "controlled_real_readiness",
|
||||||
real_calls: 0,
|
real_calls: realCalls,
|
||||||
red_reason: "任一模型缺独立真实契约证据",
|
red_reason: "任一模型缺独立真实契约证据",
|
||||||
release_gate: ["release:P0-A"],
|
release_gate: ["release:P0-A"],
|
||||||
|
remote_branch: "codex/wp7-02",
|
||||||
|
remote_commit: remoteCommit,
|
||||||
requirements: ["GEN-13"],
|
requirements: ["GEN-13"],
|
||||||
run_id: runId,
|
run_id: runId,
|
||||||
status,
|
status,
|
||||||
@@ -186,11 +223,12 @@ writeFileSync(resolve(runDirectory, "evidence.json"), `${JSON.stringify({
|
|||||||
candidate_run_id: candidateRunId,
|
candidate_run_id: candidateRunId,
|
||||||
commit,
|
commit,
|
||||||
phase: result.phase,
|
phase: result.phase,
|
||||||
real_calls: 0,
|
real_calls: realCalls,
|
||||||
redaction_scan: "passed",
|
redaction_scan: "passed",
|
||||||
|
remote_commit: remoteCommit,
|
||||||
run_id: runId,
|
run_id: runId,
|
||||||
status,
|
status,
|
||||||
task_id: result.task_id,
|
task_id: result.task_id,
|
||||||
}, null, 2)}\n`);
|
}, null, 2)}\n`);
|
||||||
console.log(JSON.stringify({ blockers_by_model: blockersByModel, candidate_run_id: candidateRunId, real_calls: 0, run_id: runId, status }, null, 2));
|
console.log(JSON.stringify({ blockers_by_model: blockersByModel, candidate_run_id: candidateRunId, real_calls: realCalls, run_id: runId, status }));
|
||||||
if (status === "failed") process.exit(1);
|
if (status === "failed") process.exit(1);
|
||||||
|
|||||||
+178
-53
@@ -1,10 +1,20 @@
|
|||||||
import { existsSync, readFileSync } from "node:fs";
|
import { spawnSync } from "node:child_process";
|
||||||
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||||
|
import { resolve } from "node:path";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
WP7_02_CONTROLLED_REAL_LIMIT,
|
||||||
|
validateSanitizedEvidence,
|
||||||
|
} from "./lib/wp7-02-controlled-executor.mjs";
|
||||||
|
import {
|
||||||
|
assembleControlledModelEvidence,
|
||||||
|
runControlledRealScenarios,
|
||||||
|
} from "./lib/wp7-02-controlled-matrix.mjs";
|
||||||
|
import {
|
||||||
|
AI_GATEWAY_CREDENTIAL_TARGET,
|
||||||
WP7_02_MODEL_IDS,
|
WP7_02_MODEL_IDS,
|
||||||
buildBlockedModelEvidence,
|
buildBlockedModelEvidence,
|
||||||
inspectAiGatewayReadiness,
|
inspectAiGatewayReadiness,
|
||||||
probeAiGatewayCredentialTargets,
|
|
||||||
writeBlockedModelEvidence,
|
writeBlockedModelEvidence,
|
||||||
} from "./lib/wp7-02-external-contract.mjs";
|
} from "./lib/wp7-02-external-contract.mjs";
|
||||||
|
|
||||||
@@ -15,13 +25,21 @@ function argument(name) {
|
|||||||
return index >= 0 ? process.argv[index + 1] : undefined;
|
return index >= 0 ? process.argv[index + 1] : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function output(value, error = false) {
|
||||||
|
const serialized = JSON.stringify(validateSanitizedEvidence(value));
|
||||||
|
if (error) console.error(serialized); else console.log(serialized);
|
||||||
|
}
|
||||||
|
|
||||||
const service = argument("--service");
|
const service = argument("--service");
|
||||||
const runId = argument("--run-id");
|
const runId = argument("--run-id");
|
||||||
const model = argument("--model");
|
const model = argument("--model");
|
||||||
const candidatePath = argument("--candidate-record") ?? process.env.DADA_WP7_01_CANDIDATE_RECORD;
|
const candidatePath = argument("--candidate-record") ?? process.env.DADA_WP7_01_CANDIDATE_RECORD;
|
||||||
const configPath = argument("--config-manifest") ?? process.env.DADA_WP7_02_MODEL_CONFIG_MANIFEST;
|
const configPath = argument("--config-manifest") ?? process.env.DADA_WP7_02_MODEL_CONFIG_MANIFEST;
|
||||||
const evidenceDirectory = argument("--evidence-dir");
|
const evidenceDirectory = argument("--evidence-dir") ?? process.env.DADA_WP7_02_EVIDENCE_DIR;
|
||||||
|
const maxRealCalls = Number(argument("--max-real-calls"));
|
||||||
const confirmed = process.argv.includes("--confirm-controlled-real");
|
const confirmed = process.argv.includes("--confirm-controlled-real");
|
||||||
|
const executeControlledReal = process.argv.includes("--execute-controlled-real");
|
||||||
|
const credentialStdin = process.argv.includes("--credential-stdin");
|
||||||
const readinessOnly = process.argv.includes("--readiness-only");
|
const readinessOnly = process.argv.includes("--readiness-only");
|
||||||
|
|
||||||
if (!allowedServices.has(service) || !runId || ((service === "ai" || service === "ai-gateway-service-id") && !WP7_02_MODEL_IDS.includes(model))) {
|
if (!allowedServices.has(service) || !runId || ((service === "ai" || service === "ai-gateway-service-id") && !WP7_02_MODEL_IDS.includes(model))) {
|
||||||
@@ -30,69 +48,176 @@ if (!allowedServices.has(service) || !runId || ((service === "ai" || service ===
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (service !== "ai" && service !== "ai-gateway-service-id") {
|
if (service !== "ai" && service !== "ai-gateway-service-id") {
|
||||||
console.log(JSON.stringify({
|
console.log(JSON.stringify({ mode: "mock", real_calls: 0, run_id: runId, service, status: "not_applicable_for_TASK-WP0-01" }));
|
||||||
blocker: undefined,
|
|
||||||
mode: "mock",
|
|
||||||
model,
|
|
||||||
real_calls: 0,
|
|
||||||
run_id: runId,
|
|
||||||
service,
|
|
||||||
status: "not_applicable_for_TASK-WP0-01",
|
|
||||||
}));
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
function parseInputs() {
|
||||||
const candidateRecord = candidatePath && existsSync(candidatePath) ? JSON.parse(readFileSync(candidatePath, "utf8")) : undefined;
|
const candidateRecord = candidatePath && existsSync(candidatePath) ? JSON.parse(readFileSync(candidatePath, "utf8")) : undefined;
|
||||||
const configManifest = configPath && existsSync(configPath) ? JSON.parse(readFileSync(configPath, "utf8")) : undefined;
|
const configManifest = configPath && existsSync(configPath) ? JSON.parse(readFileSync(configPath, "utf8")) : undefined;
|
||||||
const modelConfig = Array.isArray(configManifest?.models)
|
const modelConfig = Array.isArray(configManifest?.models)
|
||||||
? configManifest.models.find((entry) => entry?.model_id === model)
|
? configManifest.models.find((entry) => entry?.model_id === model)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
return { candidateRecord, modelConfig };
|
||||||
|
}
|
||||||
|
|
||||||
if (!candidateRecord) {
|
function delegateToSecureBroker() {
|
||||||
console.log(JSON.stringify({
|
if (!candidatePath || !configPath || !evidenceDirectory || !confirmed || maxRealCalls !== WP7_02_CONTROLLED_REAL_LIMIT) {
|
||||||
blockers: ["candidate_record_absent", ...(confirmed ? [] : ["explicit_confirmation_absent"])],
|
output({ code: "WP7_02_CONTROLLED_EXECUTION_ARGUMENTS_REQUIRED", model, real_calls: 0, run_id: runId, service, status: "failed" }, true);
|
||||||
mode: "controlled_real_not_executed", model, real_calls: 0, run_id: runId, service, status: "externally_blocked",
|
return 2;
|
||||||
}));
|
|
||||||
process.exit(3);
|
|
||||||
}
|
}
|
||||||
|
const args = [
|
||||||
const readiness = inspectAiGatewayReadiness({
|
"run", "--no-build", "--project", "supervisor/Dada.Supervisor/Dada.Supervisor.csproj", "--",
|
||||||
candidateRecord,
|
"validate-external",
|
||||||
confirmed,
|
"--service", "ai-gateway-service-id",
|
||||||
credentialTargets: probeAiGatewayCredentialTargets(),
|
"--model", model,
|
||||||
modelConfig,
|
"--run-id", runId,
|
||||||
modelId: model,
|
"--max-real-calls", String(maxRealCalls),
|
||||||
|
"--confirm-controlled-real",
|
||||||
|
"--execute-controlled-real",
|
||||||
|
];
|
||||||
|
const result = spawnSync("dotnet", args, {
|
||||||
|
encoding: "utf8",
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
DADA_WP7_01_CANDIDATE_RECORD: candidatePath,
|
||||||
|
DADA_WP7_02_EVIDENCE_DIR: evidenceDirectory,
|
||||||
|
DADA_WP7_02_MODEL_CONFIG_MANIFEST: configPath,
|
||||||
|
},
|
||||||
|
maxBuffer: 64 * 1024 * 1024,
|
||||||
|
timeout: 20 * 60_000,
|
||||||
|
windowsHide: true,
|
||||||
});
|
});
|
||||||
if (!readinessOnly && readiness.blockers.length === 0) readiness.blockers.push("controlled_real_executor_unavailable");
|
const stdout = result.stdout?.trim() ?? "";
|
||||||
readiness.status = readiness.blockers.length > 0 ? "externally_blocked" : "ready_for_controlled_execution";
|
const stderr = result.stderr?.trim() ?? "";
|
||||||
if (readiness.blockers.length > 0 && evidenceDirectory) {
|
const selected = stdout || stderr;
|
||||||
const evidence = buildBlockedModelEvidence({
|
try {
|
||||||
blockers: readiness.blockers,
|
if (!selected || (stdout && stderr)) throw new Error("invalid_output");
|
||||||
candidateRecord,
|
const parsed = validateSanitizedEvidence(JSON.parse(selected));
|
||||||
modelConfig: readiness.model_config,
|
output(parsed, !stdout);
|
||||||
modelId: model,
|
} catch {
|
||||||
runId,
|
output({ code: "WP7_02_SECURE_BROKER_FAILED", model, real_calls: 0, run_id: runId, service, status: "failed" }, true);
|
||||||
});
|
return 1;
|
||||||
writeBlockedModelEvidence(evidenceDirectory, evidence);
|
|
||||||
}
|
}
|
||||||
console.log(JSON.stringify({
|
return result.status ?? 1;
|
||||||
blockers: readiness.blockers,
|
}
|
||||||
candidate_build_commit: readiness.candidate.build_commit,
|
|
||||||
mode: readinessOnly ? "readiness_only" : "controlled_real_not_executed",
|
async function readCredentialFromStdin() {
|
||||||
model,
|
let serialized = "";
|
||||||
planned_provider_requests_max: readiness.plan.planned_provider_requests_max,
|
for await (const chunk of process.stdin) {
|
||||||
planned_request_breakdown: readiness.plan.planned_request_breakdown,
|
serialized += chunk.toString("utf8");
|
||||||
quota_impact: readiness.plan.quota_impact,
|
if (serialized.length > 16_384) throw new Error("WP7_02_CREDENTIAL_CHANNEL_INVALID");
|
||||||
real_calls: 0,
|
}
|
||||||
run_id: runId,
|
const payload = JSON.parse(serialized);
|
||||||
service,
|
serialized = "";
|
||||||
status: readiness.status,
|
if (!payload || typeof payload !== "object" || Array.isArray(payload)
|
||||||
}));
|
|| Object.keys(payload).length !== 1 || typeof payload[AI_GATEWAY_CREDENTIAL_TARGET] !== "string"
|
||||||
process.exit(readiness.blockers.length > 0 ? 3 : 0);
|
|| payload[AI_GATEWAY_CREDENTIAL_TARGET].length < 8) {
|
||||||
|
throw new Error("WP7_02_CREDENTIAL_CHANNEL_INVALID");
|
||||||
|
}
|
||||||
|
const token = payload[AI_GATEWAY_CREDENTIAL_TARGET];
|
||||||
|
payload[AI_GATEWAY_CREDENTIAL_TARGET] = "";
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readDeterministicState() {
|
||||||
|
const path = evidenceDirectory && resolve(evidenceDirectory, "deterministic-state.json");
|
||||||
|
if (!path || !existsSync(path)) throw new Error("WP7_02_DETERMINISTIC_STATE_REQUIRED");
|
||||||
|
return validateSanitizedEvidence(JSON.parse(readFileSync(path, "utf8")));
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeControlledEvidence(directory, evidence, readiness) {
|
||||||
|
mkdirSync(resolve(directory), { recursive: true });
|
||||||
|
const files = {
|
||||||
|
"contract-matrix.json": evidence.matrix,
|
||||||
|
"external-calls.json": evidence.external_calls,
|
||||||
|
"manual-review.json": evidence.manual_review,
|
||||||
|
"readiness.json": {
|
||||||
|
blockers: evidence.status === "passed" ? [] : evidence.external_calls.calls.filter((call) => call.status !== "passed").map((call) => call.error_code ?? call.scenario_id),
|
||||||
|
candidate: readiness.candidate,
|
||||||
|
evidence_id: evidence.evidence_id,
|
||||||
|
model_id: evidence.model_id,
|
||||||
|
run_id: evidence.run_id,
|
||||||
|
status: evidence.status,
|
||||||
|
},
|
||||||
|
"redaction.json": evidence.redaction,
|
||||||
|
};
|
||||||
|
for (const [name, value] of Object.entries(files)) {
|
||||||
|
writeFileSync(resolve(directory, name), `${JSON.stringify(validateSanitizedEvidence(value), null, 2)}\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const { candidateRecord, modelConfig } = parseInputs();
|
||||||
|
if (!candidateRecord) {
|
||||||
|
output({ blockers: ["candidate_record_absent", ...(confirmed ? [] : ["explicit_confirmation_absent"])], mode: "controlled_real_not_executed", model, real_calls: 0, run_id: runId, service, status: "externally_blocked" });
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (executeControlledReal && !credentialStdin) return delegateToSecureBroker();
|
||||||
|
|
||||||
|
let token = "";
|
||||||
|
try {
|
||||||
|
if (credentialStdin) token = await readCredentialFromStdin();
|
||||||
|
const readiness = inspectAiGatewayReadiness({
|
||||||
|
candidateRecord,
|
||||||
|
confirmed,
|
||||||
|
credentialTargets: credentialStdin ? [AI_GATEWAY_CREDENTIAL_TARGET] : [],
|
||||||
|
modelConfig,
|
||||||
|
modelId: model,
|
||||||
|
});
|
||||||
|
if (!credentialStdin) {
|
||||||
|
readiness.blockers = readiness.blockers.filter((blocker) => blocker !== "real_gateway_credentials_absent");
|
||||||
|
readiness.blockers.push("secure_credential_check_requires_execution");
|
||||||
|
}
|
||||||
|
readiness.status = readiness.blockers.length > 0 ? "externally_blocked" : "ready_for_controlled_execution";
|
||||||
|
|
||||||
|
if (!executeControlledReal || readinessOnly || readiness.blockers.length > 0) {
|
||||||
|
if (readiness.blockers.length > 0 && evidenceDirectory) {
|
||||||
|
writeBlockedModelEvidence(evidenceDirectory, buildBlockedModelEvidence({
|
||||||
|
blockers: readiness.blockers, candidateRecord, modelConfig: readiness.model_config, modelId: model, runId,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
output({
|
||||||
|
blockers: readiness.blockers,
|
||||||
|
candidate_build_commit: readiness.candidate.build_commit,
|
||||||
|
mode: readinessOnly ? "readiness_only" : "controlled_real_not_executed",
|
||||||
|
model,
|
||||||
|
planned_provider_requests_max: readiness.plan.planned_provider_requests_max,
|
||||||
|
planned_request_breakdown: readiness.plan.planned_request_breakdown,
|
||||||
|
real_calls: 0,
|
||||||
|
run_id: runId,
|
||||||
|
service,
|
||||||
|
status: readiness.status,
|
||||||
|
});
|
||||||
|
return readiness.blockers.length > 0 ? 3 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deterministicState = readDeterministicState();
|
||||||
|
const realExecution = await runControlledRealScenarios({ maxRealCalls, modelConfig, token });
|
||||||
|
const evidence = assembleControlledModelEvidence({ deterministicState, modelConfig, realExecution, runId });
|
||||||
|
writeControlledEvidence(evidenceDirectory, evidence, readiness);
|
||||||
|
output({
|
||||||
|
blockers: realExecution.blockers,
|
||||||
|
config_version: modelConfig.config_version,
|
||||||
|
model,
|
||||||
|
planned_real_calls: realExecution.planned_real_calls,
|
||||||
|
real_calls: realExecution.real_calls,
|
||||||
|
run_id: runId,
|
||||||
|
service,
|
||||||
|
status: evidence.status === "passed" ? "controlled_real_passed_pending_manual_review" : "externally_blocked",
|
||||||
|
});
|
||||||
|
return evidence.status === "passed" ? 0 : 3;
|
||||||
|
} finally {
|
||||||
|
token = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
process.exitCode = await main();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
const code = /^WP7_02_[A-Z0-9_:]+$/.test(message) ? message : "WP7_02_EXTERNAL_VALIDATION_FAILED";
|
const code = /^WP7_02_[A-Z0-9_:]+$/.test(message) ? message : "WP7_02_EXTERNAL_VALIDATION_FAILED";
|
||||||
console.error(JSON.stringify({ code, model, real_calls: 0, run_id: runId, service, status: "failed" }));
|
output({ code, model, real_calls: 0, run_id: runId, service, status: "failed" }, true);
|
||||||
process.exit(1);
|
process.exitCode = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,9 +137,6 @@ internal static class Program
|
|||||||
"--service", "ai-gateway-service-id",
|
"--service", "ai-gateway-service-id",
|
||||||
"--model", "gpt-image-2",
|
"--model", "gpt-image-2",
|
||||||
"--run-id", "wp7-02-supervisor-probe",
|
"--run-id", "wp7-02-supervisor-probe",
|
||||||
"--candidate-record", "candidate.json",
|
|
||||||
"--config-manifest", "config.json",
|
|
||||||
"--evidence-dir", "evidence",
|
|
||||||
"--max-real-calls", "120",
|
"--max-real-calls", "120",
|
||||||
"--confirm-controlled-real",
|
"--confirm-controlled-real",
|
||||||
"--execute-controlled-real",
|
"--execute-controlled-real",
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ internal static partial class ControlledExternalValidationLauncher
|
|||||||
|
|
||||||
private static readonly HashSet<string> ValueOptions =
|
private static readonly HashSet<string> ValueOptions =
|
||||||
[
|
[
|
||||||
"--candidate-record",
|
|
||||||
"--config-manifest",
|
|
||||||
"--evidence-dir",
|
|
||||||
"--max-real-calls",
|
"--max-real-calls",
|
||||||
"--model",
|
"--model",
|
||||||
"--run-id",
|
"--run-id",
|
||||||
@@ -71,9 +68,6 @@ internal static partial class ControlledExternalValidationLauncher
|
|||||||
|| !AllowedModels.Contains(values.GetValueOrDefault("--model") ?? string.Empty)
|
|| !AllowedModels.Contains(values.GetValueOrDefault("--model") ?? string.Empty)
|
||||||
|| !SafeRunId().IsMatch(values.GetValueOrDefault("--run-id") ?? string.Empty)
|
|| !SafeRunId().IsMatch(values.GetValueOrDefault("--run-id") ?? string.Empty)
|
||||||
|| values.GetValueOrDefault("--max-real-calls") != "120"
|
|| values.GetValueOrDefault("--max-real-calls") != "120"
|
||||||
|| !values.ContainsKey("--candidate-record")
|
|
||||||
|| !values.ContainsKey("--config-manifest")
|
|
||||||
|| !values.ContainsKey("--evidence-dir")
|
|
||||||
|| !switches.SetEquals(SwitchOptions))
|
|| !switches.SetEquals(SwitchOptions))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("external_validator_argument_invalid");
|
throw new ArgumentException("external_validator_argument_invalid");
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
import { createHash, randomUUID } from "node:crypto";
|
||||||
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { join, resolve } from "node:path";
|
||||||
|
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { CreditService } from "../../apps/api/src/credits.js";
|
||||||
|
import { ModelConfigurationService, modelIds, type ModelConfigCandidate } from "../../apps/api/src/model-configuration.js";
|
||||||
|
import { ModelContractEvidenceService } from "../../apps/api/src/model-contract-evidence.js";
|
||||||
|
import { ProjectService } from "../../apps/api/src/projects.js";
|
||||||
|
import { RegistrationService } from "../../apps/api/src/registration.js";
|
||||||
|
import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js";
|
||||||
|
import { settleGenerationCredits } from "../../apps/worker/src/credit-settlement.js";
|
||||||
|
import { generationErrorCategories, generationErrorRegistry } from "../../apps/worker/src/generation-error-registry.js";
|
||||||
|
|
||||||
|
const now = Date.parse("2026-08-04T08:00:00.000Z");
|
||||||
|
|
||||||
|
function matrix(modelId: string) {
|
||||||
|
return {
|
||||||
|
error_mapping: [...generationErrorCategories],
|
||||||
|
execution_modes: ["sync", "async", "poll"],
|
||||||
|
model_id: modelId,
|
||||||
|
pure_text: { outputs: 1, status: "passed" },
|
||||||
|
ratios: ["3:4", "1:1", "4:3", "9:16"].map((ratio) => ({ outputs: 1, ratio, status: "passed" })),
|
||||||
|
reference_image: { outputs: 1, status: "passed" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function editable(models: ReturnType<ModelConfigurationService["read"]>["models"]): ModelConfigCandidate[] {
|
||||||
|
return models.map(({ config_version: _version, runtime_availability: _runtime, ...candidate }) => structuredClone(candidate));
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeModelEvidence(modelId: string, value: unknown) {
|
||||||
|
const root = process.env.DADA_WP7_02_STATE_EVIDENCE_ROOT;
|
||||||
|
if (!root) return;
|
||||||
|
const directory = resolve(root, modelId.replaceAll(".", "_"));
|
||||||
|
mkdirSync(directory, { recursive: true });
|
||||||
|
writeFileSync(resolve(directory, "deterministic-state.json"), `${JSON.stringify(value, null, 2)}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("TDD-WP7-EXT-001 controlled deterministic state boundaries", () => {
|
||||||
|
it("proves nine errors, settlement replay, invalidation and full revalidation independently per model", () => {
|
||||||
|
const evidenceIds = new Set<string>();
|
||||||
|
for (const modelId of modelIds) {
|
||||||
|
const root = mkdtempSync(join(tmpdir(), "dada-wp7-02-state-"));
|
||||||
|
const databasePath = join(root, "dada.sqlite3");
|
||||||
|
const registration = new RegistrationService({
|
||||||
|
challengePepper: Buffer.alloc(32, 0xd1), clock: () => now,
|
||||||
|
currentPrivacyNoticeVersion: "p0a-registration-notice-v1", databasePath,
|
||||||
|
invitePepper: Buffer.alloc(32, 0xd2), resend: new MockResendAdapter(), sessionPepper: Buffer.alloc(32, 0xd3),
|
||||||
|
});
|
||||||
|
const projects = new ProjectService({ clock: () => now, databasePath });
|
||||||
|
let credits = new CreditService({ clock: () => now, databasePath });
|
||||||
|
try {
|
||||||
|
const settlements = [];
|
||||||
|
for (const outcome of ["succeeded", "failed", "rejected"] as const) {
|
||||||
|
const userId = randomUUID();
|
||||||
|
registration.database.prepare(`INSERT INTO users (
|
||||||
|
user_id, normalized_email, role, status, counts_toward_stage_limit, registration_id, created_at
|
||||||
|
) VALUES (?, ?, 'user', 'active', 1, ?, ?)`).run(userId, `${userId}@example.invalid`, randomUUID(), now);
|
||||||
|
registration.database.prepare("INSERT INTO user_profiles (user_id, creator_name, social_id) VALUES (?, 'WP7 User', '@wp7')").run(userId);
|
||||||
|
registration.database.prepare("INSERT INTO credit_accounts (user_id, available_balance, reserved_balance, updated_at) VALUES (?, 1, 0, ?)").run(userId, now);
|
||||||
|
const generationId = projects.createProjectForGeneration({ ownerId: userId, prompt: "controlled fixture", ratio: "1:1", status: "queued" }).generation.generationId;
|
||||||
|
credits.reserveGeneration({ creditCost: 1, generationId, modelId, operationKey: `generation:${generationId}:reserve`, userId });
|
||||||
|
const input = { generationId, operationKey: `generation:${generationId}:finalize`, outcome };
|
||||||
|
const first = settleGenerationCredits(credits, input);
|
||||||
|
const replay = settleGenerationCredits(credits, input);
|
||||||
|
credits.close();
|
||||||
|
credits = new CreditService({ clock: () => now, databasePath });
|
||||||
|
const restartReplay = settleGenerationCredits(credits, input);
|
||||||
|
expect(replay).toEqual(first);
|
||||||
|
expect(restartReplay).toEqual(first);
|
||||||
|
const account = credits.readAccount(userId);
|
||||||
|
const ledger = registration.database.prepare(`SELECT entry_type, COUNT(*) AS count FROM credit_ledger
|
||||||
|
WHERE user_id = ? AND entry_type IN ('generation_commit', 'generation_release') GROUP BY entry_type`).get(userId);
|
||||||
|
expect(account).toMatchObject({ availableBalance: outcome === "succeeded" ? 0 : 1, reservedBalance: 0 });
|
||||||
|
expect(ledger).toEqual({ count: 1, entry_type: outcome === "succeeded" ? "generation_commit" : "generation_release" });
|
||||||
|
settlements.push({
|
||||||
|
available_after: account.availableBalance,
|
||||||
|
ledger_entries: 1,
|
||||||
|
outcome,
|
||||||
|
reserved_after: account.reservedBalance,
|
||||||
|
replay_count: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const models = new ModelConfigurationService({ clock: () => now, database: registration.database });
|
||||||
|
const contracts = new ModelContractEvidenceService({ clock: () => now, database: registration.database, models });
|
||||||
|
const firstEvidenceHash = `sha256:${createHash("sha256").update(`${modelId}:v1`).digest("hex")}`;
|
||||||
|
const first = contracts.recordVerified({
|
||||||
|
actorId: "wp7-02-controlled", expectedConfigSetVersion: 1,
|
||||||
|
evidence: {
|
||||||
|
evidence_hash: firstEvidenceHash,
|
||||||
|
evidence_ref: `wp7-02:${modelId}:first`,
|
||||||
|
matrix: matrix(modelId), model_id: modelId,
|
||||||
|
verified_at: new Date(now).toISOString(), verifier_ref: "wp7-02-controlled",
|
||||||
|
},
|
||||||
|
idempotencyKey: `wp7-02:${modelId}:first`,
|
||||||
|
});
|
||||||
|
expect(first.model.contract_validation_status).toBe("verified");
|
||||||
|
const candidates = editable(first.configuration.models);
|
||||||
|
const target = candidates.find((candidate) => candidate.model_id === modelId)!;
|
||||||
|
target.route_profile = { ...target.route_profile, contract_revision: 2 };
|
||||||
|
const changed = models.replace({
|
||||||
|
actorId: "wp7-02-controlled", expectedConfigSetVersion: 2,
|
||||||
|
idempotencyKey: `wp7-02:${modelId}:change`, models: candidates,
|
||||||
|
});
|
||||||
|
const invalidated = changed.models.find((model) => model.model_id === modelId)!;
|
||||||
|
expect(invalidated.contract_validation_status).toBe("unverified");
|
||||||
|
const secondEvidenceHash = `sha256:${createHash("sha256").update(`${modelId}:v2`).digest("hex")}`;
|
||||||
|
const revalidated = contracts.recordVerified({
|
||||||
|
actorId: "wp7-02-controlled", expectedConfigSetVersion: 3,
|
||||||
|
evidence: {
|
||||||
|
evidence_hash: secondEvidenceHash,
|
||||||
|
evidence_ref: `wp7-02:${modelId}:second`,
|
||||||
|
matrix: matrix(modelId), model_id: modelId,
|
||||||
|
verified_at: new Date(now + 1_000).toISOString(), verifier_ref: "wp7-02-controlled",
|
||||||
|
},
|
||||||
|
idempotencyKey: `wp7-02:${modelId}:second`,
|
||||||
|
});
|
||||||
|
expect(revalidated.model.contract_validation_status).toBe("verified");
|
||||||
|
expect(contracts.read(modelId, first.model.config_version)?.evidence_hash).toBe(firstEvidenceHash);
|
||||||
|
expect(contracts.read(modelId, revalidated.model.config_version)?.evidence_hash).toBe(secondEvidenceHash);
|
||||||
|
|
||||||
|
const evidenceId = `sha256:${createHash("sha256").update(`${modelId}:deterministic-state`).digest("hex")}`;
|
||||||
|
expect(evidenceIds.has(evidenceId)).toBe(false);
|
||||||
|
evidenceIds.add(evidenceId);
|
||||||
|
writeModelEvidence(modelId, {
|
||||||
|
contract_change: {
|
||||||
|
after_change: { config_set_version: 3, config_version: invalidated.config_version, status: invalidated.contract_validation_status },
|
||||||
|
after_revalidation: { config_set_version: 4, config_version: revalidated.model.config_version, status: revalidated.model.contract_validation_status },
|
||||||
|
before_change: { config_set_version: 2, config_version: first.model.config_version, status: first.model.contract_validation_status },
|
||||||
|
full_matrix_reapplied: true,
|
||||||
|
},
|
||||||
|
error_scenarios: generationErrorCategories.map((category) => ({ category, ...generationErrorRegistry[category], source: "deterministic_local", status: "passed" })),
|
||||||
|
evidence_id: evidenceId,
|
||||||
|
model_id: modelId,
|
||||||
|
settlements,
|
||||||
|
status: "passed",
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
credits.close();
|
||||||
|
projects.close();
|
||||||
|
registration.close();
|
||||||
|
rmSync(root, { force: true, recursive: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(evidenceIds.size).toBe(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -10,6 +10,12 @@ import {
|
|||||||
normalizeProviderResponse,
|
normalizeProviderResponse,
|
||||||
validateSanitizedEvidence,
|
validateSanitizedEvidence,
|
||||||
} from "../../scripts/lib/wp7-02-controlled-executor.mjs";
|
} from "../../scripts/lib/wp7-02-controlled-executor.mjs";
|
||||||
|
import {
|
||||||
|
assembleControlledModelEvidence,
|
||||||
|
buildDeterministicExecutionEvidence,
|
||||||
|
createControlledReferencePng,
|
||||||
|
runControlledRealScenarios,
|
||||||
|
} from "../../scripts/lib/wp7-02-controlled-matrix.mjs";
|
||||||
|
|
||||||
const models = [
|
const models = [
|
||||||
{
|
{
|
||||||
@@ -82,7 +88,7 @@ test("TDD-WP7-EXT-001 builds protocol-specific requests without auth in argument
|
|||||||
model: "gpt-image-2",
|
model: "gpt-image-2",
|
||||||
prompt: "controlled fixture prompt",
|
prompt: "controlled fixture prompt",
|
||||||
response_format: "b64_json",
|
response_format: "b64_json",
|
||||||
size: "1024x1536",
|
size: "1080x1920",
|
||||||
});
|
});
|
||||||
assert.equal("authorization" in openai.headers, false);
|
assert.equal("authorization" in openai.headers, false);
|
||||||
});
|
});
|
||||||
@@ -138,3 +144,65 @@ test("TDD-WP7-EXT-001 confines the credential to the request header and discards
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("TDD-WP7-EXT-001 executes only five real success probes per model and keeps failed ratios blocking", async () => {
|
||||||
|
let fetchCalls = 0;
|
||||||
|
const execution = await runControlledRealScenarios({
|
||||||
|
fetchImpl: async () => {
|
||||||
|
fetchCalls += 1;
|
||||||
|
return new Response(JSON.stringify({
|
||||||
|
candidates: [{ content: { parts: [{ inlineData: { data: onePixelPng.toString("base64"), mimeType: "image/png" } }] } }],
|
||||||
|
}), { status: 200 });
|
||||||
|
},
|
||||||
|
maxRealCalls: 120,
|
||||||
|
modelConfig: models[0],
|
||||||
|
token: "controlled-secret-value-for-test-only",
|
||||||
|
});
|
||||||
|
assert.equal(fetchCalls, 5);
|
||||||
|
assert.equal(execution.real_calls, 5);
|
||||||
|
assert.equal(execution.status, "externally_blocked");
|
||||||
|
assert.equal(execution.calls.filter((call) => call.status === "passed").length, 2);
|
||||||
|
assert.doesNotMatch(JSON.stringify(execution), /controlled-secret|fixture prompt|iVBOR/i);
|
||||||
|
await assert.rejects(() => runControlledRealScenarios({ maxRealCalls: 121, modelConfig: models[0], token: "not-used" }), /WP7_02_REAL_CALL_LIMIT_INVALID/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("TDD-WP7-EXT-001 assembles independent complete evidence without retaining reference bytes", () => {
|
||||||
|
const reference = createControlledReferencePng();
|
||||||
|
assert.equal(reference.subarray(0, 8).toString("hex"), "89504e470d0a1a0a");
|
||||||
|
const calls = ["3:4", "1:1", "4:3", "9:16"].map((ratio, index) => ({
|
||||||
|
duration_ms: 1,
|
||||||
|
http_status: 200,
|
||||||
|
input: "pure_text",
|
||||||
|
requested_ratio: ratio,
|
||||||
|
response: { dimensions: { height: 1, width: 1 }, evidence_hash: `sha256:${"A".repeat(64)}`, mime: "image/png", usage_summary: { input_units: 0, output_units: 0, total_units: 0 } },
|
||||||
|
scenario_id: `real-${index + 1}`,
|
||||||
|
source: "real_gateway",
|
||||||
|
status: "passed",
|
||||||
|
}));
|
||||||
|
calls.push({ ...calls[1], input: "reference_image", scenario_id: "real-5" });
|
||||||
|
const deterministicState = {
|
||||||
|
contract_change: { full_matrix_reapplied: true },
|
||||||
|
error_scenarios: Array.from({ length: 9 }, (_, index) => ({ category: `category-${index}`, status: "passed" })),
|
||||||
|
model_id: models[0].model_id,
|
||||||
|
settlements: ["succeeded", "failed", "rejected"].map((outcome) => ({ outcome })),
|
||||||
|
status: "passed",
|
||||||
|
};
|
||||||
|
const evidence = assembleControlledModelEvidence({
|
||||||
|
deterministicState,
|
||||||
|
modelConfig: models[0],
|
||||||
|
realExecution: { calls, planned_real_calls: 5, real_calls: 5, status: "passed" },
|
||||||
|
runId: "wp7-02-assembly-test",
|
||||||
|
});
|
||||||
|
assert.equal(evidence.status, "passed");
|
||||||
|
assert.equal(evidence.manual_review.status, "pending");
|
||||||
|
assert.equal(evidence.matrix.error_scenarios.length, 9);
|
||||||
|
assert.doesNotMatch(JSON.stringify(evidence), /iVBOR|image_bytes|raw_prompt|authorization/i);
|
||||||
|
const execution = buildDeterministicExecutionEvidence(models[0].model_id, "wp7-02-assembly-test");
|
||||||
|
assert.deepEqual(execution.modes.map((entry) => entry.mode), ["sync", "async", "poll"]);
|
||||||
|
assert.deepEqual(execution.trace.map((entry) => `${entry.action}:${entry.before}->${entry.after}`), [
|
||||||
|
"start:created->pending",
|
||||||
|
"poll:pending->completed",
|
||||||
|
"poll:completed->completed",
|
||||||
|
]);
|
||||||
|
assert.equal(execution.trace[2].replay, true);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user