fix(web): validate corrected startup HTTP and align generated schemas
This commit is contained in:
+20
-20
@@ -99,25 +99,6 @@
|
||||
"maxLength": 128,
|
||||
"minLength": 1
|
||||
},
|
||||
"Diagnostic": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"maxLength": 128,
|
||||
"minLength": 1
|
||||
},
|
||||
"explanation": {
|
||||
"type": "string",
|
||||
"maxLength": 2048,
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"code",
|
||||
"explanation"
|
||||
]
|
||||
},
|
||||
"FailureContext": {
|
||||
"description": "Common metadata is untrusted after deserialization. No audience label confers trust.",
|
||||
"type": "object",
|
||||
@@ -143,7 +124,7 @@
|
||||
"diagnostics": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/Diagnostic"
|
||||
"$ref": "#/$defs/FailureDiagnostic"
|
||||
},
|
||||
"maxItems": 8
|
||||
},
|
||||
@@ -165,6 +146,25 @@
|
||||
"supplementary_omitted"
|
||||
]
|
||||
},
|
||||
"FailureDiagnostic": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"maxLength": 128,
|
||||
"minLength": 1
|
||||
},
|
||||
"explanation": {
|
||||
"type": "string",
|
||||
"maxLength": 2048,
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"code",
|
||||
"explanation"
|
||||
]
|
||||
},
|
||||
"OperationContext": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -82,25 +82,6 @@
|
||||
"maxLength": 128,
|
||||
"minLength": 1
|
||||
},
|
||||
"Diagnostic": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"maxLength": 128,
|
||||
"minLength": 1
|
||||
},
|
||||
"explanation": {
|
||||
"type": "string",
|
||||
"maxLength": 2048,
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"code",
|
||||
"explanation"
|
||||
]
|
||||
},
|
||||
"FailureContext": {
|
||||
"description": "Common metadata is untrusted after deserialization. No audience label confers trust.",
|
||||
"type": "object",
|
||||
@@ -126,7 +107,7 @@
|
||||
"diagnostics": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/Diagnostic"
|
||||
"$ref": "#/$defs/FailureDiagnostic"
|
||||
},
|
||||
"maxItems": 8
|
||||
},
|
||||
@@ -148,6 +129,25 @@
|
||||
"supplementary_omitted"
|
||||
]
|
||||
},
|
||||
"FailureDiagnostic": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"maxLength": 128,
|
||||
"minLength": 1
|
||||
},
|
||||
"explanation": {
|
||||
"type": "string",
|
||||
"maxLength": 2048,
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"code",
|
||||
"explanation"
|
||||
]
|
||||
},
|
||||
"FailureEnvelope": {
|
||||
"description": "DTO/schema source only. Deserialization does not produce a ProjectedFailure.",
|
||||
"type": "object",
|
||||
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
WorkingDirectoryRemovalResponse,
|
||||
WorkingDirectorySource,
|
||||
WorkingDirectorySummary,
|
||||
} from "../../generated/workdir-api";
|
||||
} from "../../generated/workdir-api.ts";
|
||||
|
||||
const SUMMARY_KEYS = new Set([
|
||||
"working_directory_id",
|
||||
|
||||
@@ -6,12 +6,44 @@ import {
|
||||
stopOwnedProcesses,
|
||||
} from "../../../../tools/web-ux/src/processes.ts";
|
||||
import { startupFixture } from "../../src/lib/workspace/workers/startup-failure.test-fixtures.ts";
|
||||
import { verifyStartupHttpCaptures } from "../worker-startup-backend-contract.ts";
|
||||
|
||||
// production build + exact T812 HTTP fixtures。派生故障・操作結果はWeb試験用でありServer保証ではない。
|
||||
// beforeは旧production buildで同fixtureを撮影するためだけに明示選択し、afterの成功と混同しない。
|
||||
Deno.test("Worker failure cause, independent outcomes, keyboard details and safe reconciliation", async () => {
|
||||
const before = Deno.env.get("T813_PHASE") === "before";
|
||||
const phase = before ? "before-real-contract" : "after";
|
||||
const captureInput = Deno.env.get("T813_HTTP_CAPTURE_LOG");
|
||||
const captureLog = captureInput
|
||||
? await Deno.readTextFile(captureInput)
|
||||
: null;
|
||||
const captureSha256 = captureLog
|
||||
? Array.from(
|
||||
new Uint8Array(
|
||||
await crypto.subtle.digest(
|
||||
"SHA-256",
|
||||
new TextEncoder().encode(captureLog),
|
||||
),
|
||||
),
|
||||
).map((b) => b.toString(16).padStart(2, "0")).join("")
|
||||
: null;
|
||||
const captures = captureLog
|
||||
? (await verifyStartupHttpCaptures(captureLog)).captures
|
||||
: null;
|
||||
function fixture(name: Parameters<typeof startupFixture>[0]) {
|
||||
if (captures && (name === "denial" || name === "lost")) {
|
||||
const capture = captures.find((item) =>
|
||||
item.status === (name === "denial" ? 409 : 502)
|
||||
);
|
||||
assert(capture, "Expected both validated real HTTP captures");
|
||||
return JSON.parse(capture.body);
|
||||
}
|
||||
return startupFixture(name);
|
||||
}
|
||||
const phase = before
|
||||
? "before-real-contract"
|
||||
: captureInput
|
||||
? "after-connected"
|
||||
: "after";
|
||||
const scenarioPath =
|
||||
new URL("./optional-repository.json", import.meta.url).pathname;
|
||||
const scenario = await loadScenario(scenarioPath);
|
||||
@@ -115,7 +147,7 @@ Deno.test("Worker failure cause, independent outcomes, keyboard details and safe
|
||||
},
|
||||
});
|
||||
});
|
||||
let body = JSON.parse(JSON.stringify(startupFixture("denial")));
|
||||
let body = JSON.parse(JSON.stringify(fixture("denial")));
|
||||
await page.route("**/api/w/home-empty/workers", async (route) => {
|
||||
if (route.request().method() !== "POST") return route.continue();
|
||||
submissions++;
|
||||
@@ -144,7 +176,7 @@ Deno.test("Worker failure cause, independent outcomes, keyboard details and safe
|
||||
]
|
||||
) {
|
||||
body = JSON.parse(
|
||||
JSON.stringify(startupFixture(
|
||||
JSON.stringify(fixture(
|
||||
name === "lost"
|
||||
? "lost"
|
||||
: name === "rejected"
|
||||
@@ -294,8 +326,12 @@ Deno.test("Worker failure cause, independent outcomes, keyboard details and safe
|
||||
route: "/w/home-empty/workers/new",
|
||||
persona: "synthetic owner",
|
||||
name,
|
||||
captureInput,
|
||||
captureSha256,
|
||||
fixture: ["denial", "lost"].includes(name)
|
||||
? "T812 exact real HTTP body"
|
||||
? captureInput
|
||||
? "forwarded exact T812 corrected-source HTTP capture"
|
||||
: "T812 exact real HTTP body"
|
||||
: "synthetic derivative/fault",
|
||||
width,
|
||||
theme: colorScheme,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// 実認可・Runtime・保存を通したRust connected試験の公開HTTP捕捉だけを受ける。
|
||||
// Web送信/受信/表示modelへの接続であり、このprocess自体は認可や保存を代替証明しない。
|
||||
import { buildCreateWorkspaceWorkerRequest } from "../src/lib/workspace/sidebar/worker-launch.ts";
|
||||
import type { CreateWorkspaceWorkerRequest } from "../src/lib/generated/worker-launch-api.ts";
|
||||
import {
|
||||
submitWorkerLaunch,
|
||||
workerLaunchNeedsReconciliation,
|
||||
@@ -14,17 +14,18 @@ export async function verifyStartupHttpCaptures(log: string) {
|
||||
if (new TextEncoder().encode(log).length > maxLogBytes) {
|
||||
throw new Error("Startup capture log exceeds the test input limit");
|
||||
}
|
||||
const request = buildCreateWorkspaceWorkerRequest({
|
||||
const request: CreateWorkspaceWorkerRequest = {
|
||||
runtime_id: "embedded",
|
||||
display_name: "HTTP contract check",
|
||||
profile: "",
|
||||
subjektiv_subject_id: "",
|
||||
initial_text: "",
|
||||
profile: null,
|
||||
ticket_assignment: null,
|
||||
initial_submit: [],
|
||||
workdir_attachments: [],
|
||||
working_directory_repository_key: "",
|
||||
working_directory_selector: "HEAD",
|
||||
});
|
||||
feature_connections: {},
|
||||
control_operation_id: null,
|
||||
};
|
||||
const cases = new Set<string>();
|
||||
const captures: { status: number; contentType: string; body: string }[] = [];
|
||||
let records = 0;
|
||||
for (const line of log.split("\n")) {
|
||||
if (!line.includes(marker)) continue;
|
||||
@@ -99,6 +100,7 @@ export async function verifyStartupHttpCaptures(log: string) {
|
||||
"Web cause presentation or uncertain-result gating differs from the connected HTTP result",
|
||||
);
|
||||
}
|
||||
captures.push({ status: Number(status), contentType, body });
|
||||
records++;
|
||||
}
|
||||
if (!cases.has("denial") || !cases.has("response_lost")) {
|
||||
@@ -106,7 +108,7 @@ export async function verifyStartupHttpCaptures(log: string) {
|
||||
"Missing real denial or response-loss Startup HTTP capture",
|
||||
);
|
||||
}
|
||||
return { records, cases: cases.size };
|
||||
return { records, cases: cases.size, captures };
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
|
||||
Reference in New Issue
Block a user