test: record blocked workbench preflight journey
Host commander merge after personal review. PR #225 is clean against current main and preserves the current-main-safe part of stale PR #213: when deployment identity preflight blocks, the Code Agent browser journey is recorded as blocked/not_sent instead of omitted or misread as a successful POST. This is validation/smoke hardening only; no live mutation, no Code Agent POST, no Secret access, and no M3/M4/M5 acceptance claim.
This commit is contained in:
@@ -41,6 +41,7 @@ const requiredMilestoneIds = ["M0", "M1", "M2", "M3", "M4", "M5"];
|
||||
const evidenceLevels = new Set(["SOURCE", "LOCAL", "DRY-RUN", "DEV-LIVE", "BLOCKED"]);
|
||||
const devCloudWorkbenchRuntimeIdentityMaxSkewMs = 15 * 60 * 1000;
|
||||
const syntheticAcceptedCodeAgentModels = new Set(["gpt-5"]);
|
||||
const deploymentPreflightCodeAgentErrorCode = "deployment_identity_preflight";
|
||||
const requiredValidationCommands = [
|
||||
"node --check scripts/validate-dev-gate-report.mjs",
|
||||
"node scripts/validate-dev-gate-report.mjs"
|
||||
@@ -1553,15 +1554,18 @@ function assertDevCloudWorkbenchDeploymentPreflight(report, label, checks) {
|
||||
for (const requiredCheck of [
|
||||
"live-runtime-current-main",
|
||||
"live-http-html",
|
||||
"live-web-assets-current-main"
|
||||
"live-web-assets-current-main",
|
||||
"live-code-agent-browser-journey"
|
||||
]) {
|
||||
assert.ok(checks.has(requiredCheck), `${label}.checks missing ${requiredCheck}`);
|
||||
}
|
||||
|
||||
const runtimeCheck = checks.get("live-runtime-current-main");
|
||||
const webAssetCheck = checks.get("live-web-assets-current-main");
|
||||
const journey = checks.get("live-code-agent-browser-journey");
|
||||
assert.ok(["pass", "blocked"].includes(runtimeCheck.status), `${label}.live-runtime-current-main.status`);
|
||||
assert.ok(["pass", "blocked"].includes(webAssetCheck.status), `${label}.live-web-assets-current-main.status`);
|
||||
assert.equal(journey.status, "blocked", `${label}.live-code-agent-browser-journey.status`);
|
||||
assert.ok(
|
||||
runtimeCheck.status === "blocked" || webAssetCheck.status === "blocked",
|
||||
`${label}.deployment preflight requires runtime or web asset drift`
|
||||
@@ -1613,6 +1617,7 @@ function assertDevCloudWorkbenchDeploymentPreflight(report, label, checks) {
|
||||
report.webAssetIdentity,
|
||||
`${label}.live-web-assets-current-main.observations`
|
||||
);
|
||||
assertDevCloudWorkbenchDeploymentPreflightJourney(report, label, journey);
|
||||
|
||||
assertBlockers(report.blockers, `${label}.blockers`);
|
||||
if (runtimeCheck.status === "blocked") {
|
||||
@@ -1641,6 +1646,53 @@ function assertDevCloudWorkbenchDeploymentPreflight(report, label, checks) {
|
||||
assertString(report.safety.statement, `${label}.safety.statement`);
|
||||
}
|
||||
|
||||
function assertDevCloudWorkbenchDeploymentPreflightJourney(report, label, journey) {
|
||||
assertStringArray(journey.evidence, `${label}.live-code-agent-browser-journey.evidence`, { minLength: 3 });
|
||||
assert.ok(
|
||||
journey.evidence.includes("POST /v1/agent/chat not sent"),
|
||||
`${label}.live-code-agent-browser-journey.evidence missing not_sent proof`
|
||||
);
|
||||
assertObject(journey.observations, `${label}.live-code-agent-browser-journey.observations`);
|
||||
assertObject(journey.observations.request, `${label}.live-code-agent-browser-journey.request`);
|
||||
assert.equal(journey.observations.request.method, "POST", `${label}.live-code-agent-browser-journey.request.method`);
|
||||
assert.equal(journey.observations.request.status, "not_sent", `${label}.live-code-agent-browser-journey.request.status`);
|
||||
assert.equal(journey.observations.request.urlPath, "/v1/agent/chat", `${label}.live-code-agent-browser-journey.request.urlPath`);
|
||||
assertObject(journey.observations.response, `${label}.live-code-agent-browser-journey.response`);
|
||||
assert.equal(journey.observations.response.status, "failed", `${label}.live-code-agent-browser-journey.response.status`);
|
||||
assert.equal(journey.observations.response.hasReply, false, `${label}.live-code-agent-browser-journey.response.hasReply`);
|
||||
assertObject(journey.observations.response.error, `${label}.live-code-agent-browser-journey.response.error`);
|
||||
assert.equal(
|
||||
journey.observations.response.error.code,
|
||||
deploymentPreflightCodeAgentErrorCode,
|
||||
`${label}.live-code-agent-browser-journey.response.error.code`
|
||||
);
|
||||
for (const field of ["provider", "model", "backend", "traceId"]) {
|
||||
assert.equal(journey.observations.response[field], "not_observed", `${label}.live-code-agent-browser-journey.response.${field}`);
|
||||
}
|
||||
assertObject(journey.observations.classification, `${label}.live-code-agent-browser-journey.classification`);
|
||||
assert.equal(journey.observations.classification.status, "blocked", `${label}.live-code-agent-browser-journey.classification.status`);
|
||||
assert.equal(
|
||||
journey.observations.classification.reason,
|
||||
deploymentPreflightCodeAgentErrorCode,
|
||||
`${label}.live-code-agent-browser-journey.classification.reason`
|
||||
);
|
||||
assert.equal(
|
||||
journey.observations.classification.codeAgentBrowserJourneySkipped,
|
||||
true,
|
||||
`${label}.live-code-agent-browser-journey.classification.codeAgentBrowserJourneySkipped`
|
||||
);
|
||||
const journeyText = JSON.stringify(journey.observations);
|
||||
assert.equal(
|
||||
/"status"\s*:\s*200|completed|provider_unavailable|OPENAI_API_KEY/u.test(journeyText),
|
||||
false,
|
||||
`${label}.live-code-agent-browser-journey must not retain sent, completed, or secret-dependent evidence during deployment preflight`
|
||||
);
|
||||
assert.ok(
|
||||
report.blockers.some((blocker) => blocker.scope === "live-code-agent-browser-journey"),
|
||||
`${label}.blockers must include live-code-agent-browser-journey`
|
||||
);
|
||||
}
|
||||
|
||||
function assertDevCloudWorkbenchIdentity(report, label) {
|
||||
assertObject(report.sourceIdentity, `${label}.sourceIdentity`);
|
||||
for (const field of ["status", "source", "commitId", "shortCommitId", "ref", "worktreeState", "reportCommitId", "summary"]) {
|
||||
|
||||
Reference in New Issue
Block a user