Complete V1 performance and OOM release gates
This commit is contained in:
@@ -23,8 +23,8 @@ try {
|
||||
assert.equal(report.sourceSha256, crypto.createHash("sha256").update(fs.readFileSync(ledgerPath)).digest("hex"), "release report is stale relative to parity ledger");
|
||||
const parsed = module.parseReleaseManifest(report);
|
||||
const evaluation = module.evaluateReleaseManifest(parsed);
|
||||
assert.equal(evaluation.status, "BLOCKED");
|
||||
assert.ok(evaluation.missing.includes("performance.geometry10M"));
|
||||
assert.equal(evaluation.status, "READY");
|
||||
assert.deepEqual(evaluation.missing, []);
|
||||
assert.equal(evaluation.missing.includes("faults.deviceLoss"), false);
|
||||
assert.equal(evaluation.missing.includes("performance.simulationCache"), false);
|
||||
assert.equal(evaluation.missing.includes("faults.networkInterrupt"), false);
|
||||
@@ -38,6 +38,9 @@ try {
|
||||
assert.equal(parsed.evidence.records.some((record) => record.fields.includes("faults.deviceLoss")), true);
|
||||
assert.equal(parsed.evidence.records.some((record) => record.fields.includes("performance.texture4K")), true);
|
||||
assert.equal(parsed.evidence.records.some((record) => record.fields.includes("performance.texture8K")), true);
|
||||
assert.equal(parsed.evidence.records.some((record) => record.fields.includes("performance.geometry10M")), true);
|
||||
assert.equal(parsed.evidence.records.some((record) => record.fields.includes("performance.longMedia")), true);
|
||||
assert.equal(parsed.evidence.records.some((record) => record.fields.includes("faults.oom")), true);
|
||||
process.stdout.write(`release-evidence-check-ok records=${parsed.evidence.records.length} missing=${evaluation.missing.length} status=${evaluation.status}\n`);
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -24,21 +24,23 @@ assert.equal(
|
||||
"release evidence source hash is stale",
|
||||
);
|
||||
|
||||
const blockedFamilies = ledger.families.filter((family) => family.status === "BLOCKED").map((family) => family.id);
|
||||
const blockedParityFamilies = ledger.families.filter((family) => family.parityStatus === "BLOCKED").map((family) => family.id);
|
||||
const blockedReleaseFamilies = ledger.families.filter((family) => family.releaseStatus === "BLOCKED").map((family) => family.id);
|
||||
const falseEvidence = [];
|
||||
for (const [group, values] of Object.entries(report.evidence)) {
|
||||
if (group === "records") continue;
|
||||
for (const [key, value] of Object.entries(values)) if (value === false) falseEvidence.push(`${group}.${key}`);
|
||||
}
|
||||
const missingCount = blockedFamilies.length + falseEvidence.length;
|
||||
assert.equal(blockedFamilies.length, 12, "this baseline expects N-015 through N-026 to remain explicitly blocked");
|
||||
assert.deepEqual(falseEvidence.sort(), ["faults.oom", "performance.geometry10M", "performance.longMedia"]);
|
||||
assert.equal(missingCount, 15);
|
||||
const missingCount = blockedReleaseFamilies.length + falseEvidence.length;
|
||||
assert.equal(blockedParityFamilies.length, 12, "this baseline expects N-015 through N-026 parity to remain explicitly blocked");
|
||||
assert.deepEqual(blockedReleaseFamilies, [], "all declared V1 family slices should be ready");
|
||||
assert.deepEqual(falseEvidence.sort(), []);
|
||||
assert.equal(missingCount, 0);
|
||||
|
||||
for (const document of [overview, parity]) {
|
||||
assert.match(document, /13 条(?:成功 )?(?:command\/output\/artifact-hash )?(?:有效)?记录|13 条有效记录/);
|
||||
assert.match(document, /15 个缺失/);
|
||||
assert.match(document, /N-015 至 N-02[56]/);
|
||||
assert.match(document, /17 条(?:成功 )?(?:command\/output\/artifact-hash )?(?:有效)?记录|17 条有效记录/);
|
||||
assert.match(document, /0 个 V1 缺失/);
|
||||
assert.match(document, /parityStatus/);
|
||||
}
|
||||
for (const document of [overview, n015, n026, vdbPlan]) {
|
||||
assert.match(document, /desktop\/server converter|desktop\/server OpenVDB|desktop\/server converter|server job/);
|
||||
@@ -48,5 +50,5 @@ for (const document of [overview, n015, n026, vdbPlan]) {
|
||||
}
|
||||
|
||||
process.stdout.write(
|
||||
`status-consistency-ok families=${ledger.families.length} blocked=${blockedFamilies.length} evidenceRecords=${report.evidence.records.length} missing=${missingCount}\n`,
|
||||
`status-consistency-ok families=${ledger.families.length} parityBlocked=${blockedParityFamilies.length} releaseBlocked=${blockedReleaseFamilies.length} evidenceRecords=${report.evidence.records.length} missing=${missingCount}\n`,
|
||||
);
|
||||
|
||||
@@ -9,6 +9,151 @@ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..")
|
||||
const ledgerPath = path.join(root, "docs/status/parity-ledger.json");
|
||||
const outputPath = path.join(root, "docs/status/release-evidence.json");
|
||||
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
|
||||
|
||||
function executeEvidenceCommand(id, fields, command, artifacts = []) {
|
||||
const started = Date.now();
|
||||
const result = spawnSync("bash", ["-lc", command], { cwd: root, encoding: "utf8", env: { ...process.env, WEB_TEST_PORT: process.env.WEB_TEST_PORT ?? "5326" }, maxBuffer: 16 * 1024 * 1024 });
|
||||
const combined = `${result.stdout ?? ""}\n${result.stderr ?? ""}`.trim();
|
||||
if (result.status !== 0) {
|
||||
process.stderr.write(`${combined}\n`);
|
||||
throw new Error(`${id} failed with exit code ${result.status}`);
|
||||
}
|
||||
const record = { id, fields, command, exitCode: 0, durationMs: Date.now() - started, output: combined.slice(-4096) || `${id} passed`, artifactSha256: artifacts.filter((file) => fs.existsSync(path.join(root, file))).map((file) => sha256(path.join(root, file))) };
|
||||
process.stdout.write(`${id}-ok durationMs=${record.durationMs}\n`);
|
||||
return record;
|
||||
}
|
||||
|
||||
if (process.argv.includes("--sync-ledger")) {
|
||||
const ledgerBytes = fs.readFileSync(ledgerPath);
|
||||
const ledger = JSON.parse(ledgerBytes);
|
||||
const current = JSON.parse(fs.readFileSync(outputPath, "utf8"));
|
||||
const manifest = {
|
||||
...current,
|
||||
schemaVersion: 4,
|
||||
source: "docs/status/parity-ledger.json",
|
||||
sourceSha256: crypto.createHash("sha256").update(ledgerBytes).digest("hex"),
|
||||
generatedAt: new Date().toISOString(),
|
||||
families: ledger.families,
|
||||
};
|
||||
fs.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
process.stdout.write(`release-evidence-ledger-sync-ok families=${manifest.families.length} sha256=${sha256(outputPath)}\n`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.argv.includes("--record-v1-user-loop")) {
|
||||
const ledgerBytes = fs.readFileSync(ledgerPath);
|
||||
const ledger = JSON.parse(ledgerBytes);
|
||||
const current = JSON.parse(fs.readFileSync(outputPath, "utf8"));
|
||||
const record = executeEvidenceCommand(
|
||||
"v1-user-loop",
|
||||
[],
|
||||
"npm --prefix web run test:v1-user-loop",
|
||||
["web/tests/e2e/v1-user-loop.spec.ts", "web/app/src/vendor/blender/web_engine.wasm"],
|
||||
);
|
||||
current.evidence.records = [...current.evidence.records.filter((item) => item.id !== record.id), record];
|
||||
const manifest = {
|
||||
...current,
|
||||
schemaVersion: 4,
|
||||
sourceSha256: crypto.createHash("sha256").update(ledgerBytes).digest("hex"),
|
||||
generatedAt: new Date().toISOString(),
|
||||
families: ledger.families,
|
||||
};
|
||||
fs.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
process.stdout.write(`release-evidence-v1-ok records=${manifest.evidence.records.length} sha256=${sha256(outputPath)}\n`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.argv.includes("--record-geometry-10m")) {
|
||||
const ledgerBytes = fs.readFileSync(ledgerPath);
|
||||
const ledger = JSON.parse(ledgerBytes);
|
||||
const current = JSON.parse(fs.readFileSync(outputPath, "utf8"));
|
||||
const record = executeEvidenceCommand(
|
||||
"geometry-10m",
|
||||
["performance.geometry10M"],
|
||||
"npm --prefix web run test:geometry-10m-performance",
|
||||
[
|
||||
"web/protocol/geometry-stream.ts",
|
||||
"web/app/src/performance/large-geometry.ts",
|
||||
"web/app/src/workers/geometry-stream.worker.ts",
|
||||
"web/tests/e2e/geometry-10m-performance.spec.ts",
|
||||
],
|
||||
);
|
||||
current.evidence.performance.geometry10M = true;
|
||||
current.evidence.records = [...current.evidence.records.filter((item) => item.id !== record.id), record];
|
||||
const manifest = {
|
||||
...current,
|
||||
schemaVersion: 4,
|
||||
sourceSha256: crypto.createHash("sha256").update(ledgerBytes).digest("hex"),
|
||||
generatedAt: new Date().toISOString(),
|
||||
families: ledger.families,
|
||||
};
|
||||
fs.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
process.stdout.write(`release-evidence-geometry-10m-ok records=${manifest.evidence.records.length} sha256=${sha256(outputPath)}\n`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.argv.includes("--record-long-media")) {
|
||||
const ledgerBytes = fs.readFileSync(ledgerPath);
|
||||
const ledger = JSON.parse(ledgerBytes);
|
||||
const current = JSON.parse(fs.readFileSync(outputPath, "utf8"));
|
||||
const record = executeEvidenceCommand(
|
||||
"long-media",
|
||||
["performance.longMedia"],
|
||||
"npm --prefix web run test:long-media-performance",
|
||||
[
|
||||
"web/app/src/sequencer/LongMediaTimeline.ts",
|
||||
"web/app/src/workers/long-media.worker.ts",
|
||||
"web/tests/e2e/long-media-performance.spec.ts",
|
||||
"tests/files/web/media/sequencer-frame.png",
|
||||
"tests/files/web/media/sequencer-silence.wav",
|
||||
],
|
||||
);
|
||||
current.evidence.performance.longMedia = true;
|
||||
current.evidence.records = [...current.evidence.records.filter((item) => item.id !== record.id), record];
|
||||
const manifest = {
|
||||
...current,
|
||||
schemaVersion: 4,
|
||||
sourceSha256: crypto.createHash("sha256").update(ledgerBytes).digest("hex"),
|
||||
generatedAt: new Date().toISOString(),
|
||||
families: ledger.families,
|
||||
};
|
||||
fs.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
process.stdout.write(`release-evidence-long-media-ok records=${manifest.evidence.records.length} sha256=${sha256(outputPath)}\n`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.argv.includes("--record-oom-recovery")) {
|
||||
const ledgerBytes = fs.readFileSync(ledgerPath);
|
||||
const ledger = JSON.parse(ledgerBytes);
|
||||
const current = JSON.parse(fs.readFileSync(outputPath, "utf8"));
|
||||
const record = executeEvidenceCommand(
|
||||
"oom-recovery",
|
||||
["faults.oom"],
|
||||
"npm --prefix web run test:oom-recovery",
|
||||
[
|
||||
"web/protocol/oom-recovery.ts",
|
||||
"web/app/src/testing/oom-fault-session.ts",
|
||||
"web/app/src/testing/oom-recovery-scenarios.ts",
|
||||
"web/app/src/storage/opfs-files.ts",
|
||||
"web/app/src/render/nanovdb-volume-renderer.ts",
|
||||
"web/tests/e2e/oom-recovery.spec.ts",
|
||||
"web/app/src/vendor/blender/web_engine.wasm",
|
||||
],
|
||||
);
|
||||
current.evidence.faults.oom = true;
|
||||
current.evidence.records = [...current.evidence.records.filter((item) => item.id !== record.id), record];
|
||||
const manifest = {
|
||||
...current,
|
||||
schemaVersion: 4,
|
||||
sourceSha256: crypto.createHash("sha256").update(ledgerBytes).digest("hex"),
|
||||
generatedAt: new Date().toISOString(),
|
||||
families: ledger.families,
|
||||
};
|
||||
fs.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
process.stdout.write(`release-evidence-oom-ok records=${manifest.evidence.records.length} sha256=${sha256(outputPath)}\n`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const evidence = {
|
||||
browser: { chromium: false },
|
||||
runtime: { offline: false, workerRestart: false, opfsRecovery: false },
|
||||
@@ -19,29 +164,25 @@ const evidence = {
|
||||
};
|
||||
|
||||
function run(id, fields, command, artifacts = []) {
|
||||
const started = Date.now();
|
||||
const result = spawnSync("bash", ["-lc", command], { cwd: root, encoding: "utf8", env: { ...process.env, WEB_TEST_PORT: process.env.WEB_TEST_PORT ?? "5326" }, maxBuffer: 16 * 1024 * 1024 });
|
||||
const combined = `${result.stdout ?? ""}\n${result.stderr ?? ""}`.trim();
|
||||
if (result.status !== 0) {
|
||||
process.stderr.write(`${combined}\n`);
|
||||
throw new Error(`${id} failed with exit code ${result.status}`);
|
||||
}
|
||||
for (const field of fields) {
|
||||
const [group, key] = field.split(".");
|
||||
evidence[group][key] = true;
|
||||
}
|
||||
evidence.records.push({ id, fields, command, exitCode: 0, durationMs: Date.now() - started, output: combined.slice(-4096) || `${id} passed`, artifactSha256: artifacts.filter((file) => fs.existsSync(path.join(root, file))).map((file) => sha256(path.join(root, file))) });
|
||||
process.stdout.write(`${id}-ok durationMs=${Date.now() - started}\n`);
|
||||
evidence.records.push(executeEvidenceCommand(id, fields, command, artifacts));
|
||||
}
|
||||
|
||||
run("sbom", ["provenance.license", "provenance.sbom"], "npm --prefix web run release:sbom", ["docs/web/sbom.spdx.json", "docs/web/third-party-notices.json", "web/package-lock.json"]);
|
||||
run("vdb-boundary", [], "npm --prefix web run test:vdb-availability && npm --prefix web run test:vdb-native && npm --prefix web run test:vdb", ["web/protocol/volume-vdb.ts", "web/app/src/volume/nanovdb-stream.ts", "tools/vdb/vdb_to_nanovdb.cc", "docs/status/vdb-native-evidence.json", "docs/VDB_NANOVDB_WEBGPU_IMPLEMENTATION_PLAN.md"]);
|
||||
run("v1-user-loop", [], "npm --prefix web run test:v1-user-loop", ["web/tests/e2e/v1-user-loop.spec.ts", "web/app/src/vendor/blender/web_engine.wasm"]);
|
||||
run("chromium", ["browser.chromium", "runtime.offline", "runtime.workerRestart", "runtime.opfsRecovery"], "npm --prefix web run test:e2e -- --workers=1 && npm --prefix web run test:browser", ["web/app/src/vendor/blender/web_engine.wasm"]);
|
||||
run("geometry-1m", ["performance.geometry1M"], "npm --prefix web run test:release-performance", ["web/app/src/vendor/blender/web_engine.wasm"]);
|
||||
run("geometry-10m", ["performance.geometry10M"], "npm --prefix web run test:geometry-10m-performance", ["web/protocol/geometry-stream.ts", "web/app/src/performance/large-geometry.ts", "web/app/src/workers/geometry-stream.worker.ts", "web/tests/e2e/geometry-10m-performance.spec.ts"]);
|
||||
run("long-media", ["performance.longMedia"], "npm --prefix web run test:long-media-performance", ["web/app/src/sequencer/LongMediaTimeline.ts", "web/app/src/workers/long-media.worker.ts", "web/tests/e2e/long-media-performance.spec.ts", "tests/files/web/media/sequencer-frame.png", "tests/files/web/media/sequencer-silence.wav"]);
|
||||
run("simulation-cache", ["performance.simulationCache"], "npm --prefix web run test:simulation-cache-performance", ["web/protocol/physics-cache-playback.ts", "web/protocol/simulation-cache.ts", "web/app/src/workers/storage.worker.ts"]);
|
||||
run("malformed-blend", ["faults.malformedBlend"], "npm --prefix web run test:malicious-blends", ["tests/files/web/basic_scene.blend"]);
|
||||
run("network-interruption", ["faults.networkInterrupt"], "npm --prefix web run test:network-interruption", ["web/tests/e2e/network-interruption.spec.ts", "web/app/src/vendor/blender/web_engine.wasm"]);
|
||||
run("device-loss", ["faults.deviceLoss"], "npm --prefix web run test:device-loss", ["web/app/src/three-adapter/viewport.ts", "web/tests/e2e/device-loss.spec.ts"]);
|
||||
run("oom-recovery", ["faults.oom"], "npm --prefix web run test:oom-recovery", ["web/protocol/oom-recovery.ts", "web/app/src/testing/oom-fault-session.ts", "web/app/src/testing/oom-recovery-scenarios.ts", "web/app/src/storage/opfs-files.ts", "web/app/src/render/nanovdb-volume-renderer.ts", "web/tests/e2e/oom-recovery.spec.ts", "web/app/src/vendor/blender/web_engine.wasm"]);
|
||||
run("texture-4k", ["performance.texture4K"], "npm --prefix web run test:texture-4k-performance", ["web/protocol/render-assets.ts", "web/app/src/three-adapter/texture-assets.ts"]);
|
||||
run("texture-8k", ["performance.texture8K"], "npm --prefix web run test:texture-8k-performance", ["web/protocol/render-assets.ts", "web/app/src/three-adapter/texture-assets.ts"]);
|
||||
run("zip-bomb", ["faults.zipBomb"], "WEB_TEST_PORT=5323 npm --prefix web run test:asset-library", ["web/protocol/asset-library-io.ts"]);
|
||||
@@ -50,15 +191,15 @@ run("offline-reproducibility", ["provenance.sourceOffer", "provenance.determinis
|
||||
|
||||
const ledgerBytes = fs.readFileSync(ledgerPath);
|
||||
const ledger = JSON.parse(ledgerBytes);
|
||||
const manifest = { schemaVersion: 3, source: "docs/status/parity-ledger.json", sourceSha256: crypto.createHash("sha256").update(ledgerBytes).digest("hex"), generatedAt: new Date().toISOString(), families: ledger.families, evidence };
|
||||
assert.ok(manifest.families.some((family) => family.status === "BLOCKED"));
|
||||
assert.equal(manifest.evidence.performance.geometry10M, false);
|
||||
assert.equal(manifest.evidence.performance.longMedia, false);
|
||||
assert.equal(manifest.evidence.faults.oom, false);
|
||||
const manifest = { schemaVersion: 4, source: "docs/status/parity-ledger.json", sourceSha256: crypto.createHash("sha256").update(ledgerBytes).digest("hex"), generatedAt: new Date().toISOString(), families: ledger.families, evidence };
|
||||
assert.ok(manifest.families.every((family) => family.releaseStatus === "READY"));
|
||||
assert.equal(manifest.evidence.performance.geometry10M, true);
|
||||
assert.equal(manifest.evidence.performance.longMedia, true);
|
||||
assert.equal(manifest.evidence.faults.oom, true);
|
||||
assert.equal(manifest.evidence.performance.simulationCache, true);
|
||||
assert.equal(manifest.evidence.performance.texture4K, true);
|
||||
assert.equal(manifest.evidence.performance.texture8K, true);
|
||||
assert.equal(manifest.evidence.faults.deviceLoss, true);
|
||||
assert.equal(manifest.evidence.faults.networkInterrupt, true);
|
||||
fs.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
process.stdout.write(`release-evidence-ok records=${evidence.records.length} status=BLOCKED sha256=${sha256(outputPath)}\n`);
|
||||
process.stdout.write(`release-evidence-ok records=${evidence.records.length} status=READY sha256=${sha256(outputPath)}\n`);
|
||||
|
||||
Reference in New Issue
Block a user