Advance M7 workflows and release operations
This commit is contained in:
58
tools/web/check-operations-diagnostics.mjs
Normal file
58
tools/web/check-operations-diagnostics.mjs
Normal file
@@ -0,0 +1,58 @@
|
||||
import assert from "node:assert/strict";
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const sourcePath = path.join(repoRoot, "docs/web/operations-diagnostics.json");
|
||||
const diagnostics = JSON.parse(fs.readFileSync(sourcePath, "utf8"));
|
||||
const contract = JSON.parse(fs.readFileSync(path.join(repoRoot, "docs/web/deployment-contract.json"), "utf8"));
|
||||
const guide = fs.readFileSync(path.join(repoRoot, "docs/web/DEPLOYMENT.md"), "utf8");
|
||||
const requiredDomains = ["mime", "range", "isolation", "hash", "quota", "worker", "gpu"];
|
||||
|
||||
assert.equal(diagnostics.schemaVersion, 1);
|
||||
assert.equal(diagnostics.product, contract.product);
|
||||
assert.deepEqual(diagnostics.entries.map((entry) => entry.domain).sort(), [...requiredDomains].sort());
|
||||
assert.equal(new Set(diagnostics.entries.map((entry) => entry.id)).size, requiredDomains.length);
|
||||
const allSignals = diagnostics.entries.flatMap((entry) => entry.signals);
|
||||
assert.equal(new Set(allSignals).size, allSignals.length, "diagnostic signals must be unambiguous");
|
||||
|
||||
for (const entry of diagnostics.entries) {
|
||||
assert.match(entry.id, /^OPS-[A-Z]+$/);
|
||||
for (const name of ["signals", "checks", "expected", "recovery"]) {
|
||||
assert.ok(Array.isArray(entry[name]) && entry[name].length > 0, `${entry.id} omits ${name}`);
|
||||
assert.ok(entry[name].every((value) => typeof value === "string" && value.length > 0), `${entry.id} has an empty ${name}`);
|
||||
}
|
||||
assert.ok(typeof entry.dataSafety === "string" && entry.dataSafety.length > 0, `${entry.id} omits dataSafety`);
|
||||
assert.ok(guide.toLowerCase().includes(`| ${entry.domain}`), `${entry.id} is absent from DEPLOYMENT.md`);
|
||||
}
|
||||
|
||||
const byDomain = Object.fromEntries(diagnostics.entries.map((entry) => [entry.domain, entry]));
|
||||
for (const mime of [contract.mimeTypes[".wasm"], contract.mimeTypes[".js"], contract.mimeTypes[".json"]]) {
|
||||
assert.ok(byDomain.mime.expected.some((value) => value.includes(mime)), `MIME diagnostics omit ${mime}`);
|
||||
}
|
||||
for (const status of [contract.rangeRequests.satisfiedStatus, contract.rangeRequests.unsatisfiedStatus, 200]) {
|
||||
assert.ok(byDomain.range.expected.some((value) => value.includes(String(status))), `range diagnostics omit ${status}`);
|
||||
}
|
||||
for (const [name, value] of Object.entries(contract.responseHeaders.allResponses)) {
|
||||
assert.ok(byDomain.isolation.expected.some((item) => item.includes(name) && item.includes(value)), `isolation diagnostics omit ${name}`);
|
||||
}
|
||||
assert.ok(byDomain.hash.expected.some((value) => value.includes("no fallback") && value.includes("no project open")));
|
||||
assert.ok(byDomain.quota.dataSafety.includes("Never delete"));
|
||||
assert.ok(byDomain.worker.dataSafety.includes("late Worker output"));
|
||||
assert.ok(byDomain.gpu.dataSafety.includes("must not rewrite"));
|
||||
|
||||
const report = {
|
||||
schemaVersion: 1,
|
||||
task: "M6-17D",
|
||||
status: "READY",
|
||||
sourceSha256: crypto.createHash("sha256").update(fs.readFileSync(sourcePath)).digest("hex"),
|
||||
domains: requiredDomains,
|
||||
entries: diagnostics.entries.length,
|
||||
signals: allSignals.length,
|
||||
};
|
||||
const reportRoot = path.join(repoRoot, "release/operations-reports");
|
||||
fs.mkdirSync(reportRoot, { recursive: true });
|
||||
fs.writeFileSync(path.join(reportRoot, "diagnostics.json"), `${JSON.stringify(report, null, 2)}\n`);
|
||||
process.stdout.write(`operations-diagnostics-ok domains=${requiredDomains.join(",")} signals=${allSignals.length} source=${report.sourceSha256}\n`);
|
||||
Reference in New Issue
Block a user