chore: sync the frontend template from 4dc033c to 8157ad4

The product was materialized from the template at `4dc033c` and has stayed
on it through 43 template commits, so it was missing all three rounds of
adapter remediation — including files it never had, such as the shared
`abortable-operation` primitive and the `exact-snapshot` decoder that
later fixes are written against. Taking only the newest round was not
possible for that reason: the delta is coherent only as a whole.

The product had not touched `src/adapters` at all since materialization,
so the 140-file delta applied with a three-way merge and no conflicts.
`package.json` was the single overlap and merged cleanly: the product owns
`name`, the template contributed `check:adapter-inventory`,
`check:remediation-ledger` and the image-resolve-signal type fixture.
All 24 product-owned files — README, index.html, CI workflow, i18n
catalog, home page, generated schemas, evidence scripts, component and
visual snapshots — are byte-identical to `main`.

`template.lock.json` now pins the synced revision and tree.

Verified in this repository, not inherited from the template: six type
projects, lint, nine gates (adapter inventory, remediation ledger,
registries, diagnostics, realtime boundaries, architecture, browser
file/storage boundaries, optional recipes, documentation), the production
build, and 2,054 of 2,073 tests. The 19 failures are all in
`tests/unit/ci-artifact-contract.test.ts` and are the same pre-existing
sandbox RLIMIT, EMFILE, umask and `/tmp` permission behaviour the template
records; four suites that failed once under parallel load pass in
isolation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-08-15 12:04:58 +09:00
co-authored by Claude Opus 5
parent 002ba3624e
commit 4bff9ca151
142 changed files with 23010 additions and 1544 deletions
+202
View File
@@ -0,0 +1,202 @@
import { readFile } from "node:fs/promises";
import { readFileSync } from "node:fs";
import path from "node:path";
import { spawnSync } from "node:child_process";
import { CACHEABLE_ASSET_CONTENT_TYPES } from "../src/contracts/service-worker-static-manifest.ts";
/**
* GOV-01 / SW-RR-03. Structural gates for facts that a hand-maintained document
* cannot keep true.
*
* The adapter review inventory claimed 118/118 while the tree held 119 files,
* so a whole adapter was outside every review's coverage without anything
* failing. And the Service Worker asset generator and the shared manifest
* decoder each carried their own extension table, so a build could emit an
* asset the runtime contract then refused. Both are now equalities this script
* checks rather than numbers someone has to remember to update.
*/
const INVENTORY_PATH = "docs/reviews/adapters/INVENTORY.md";
const GENERATOR_PATH = "scripts/generate-service-worker-assets.ts";
function trackedAdapterFiles(): readonly string[] {
const listed = spawnSync("git", ["ls-files", "src/adapters"], {
encoding: "utf8",
});
if (listed.status !== 0) {
throw new Error(`git ls-files failed: ${listed.stderr}`);
}
return listed.stdout.split("\n").filter(Boolean).sort();
}
function inventoryRows(markdown: string): readonly string[] {
const rows: string[] = [];
for (const line of markdown.split("\n")) {
const match = /^\|\s*\d+\s*\|\s*`([^`]+)`\s*\|/u.exec(line);
if (match?.[1]) rows.push(match[1]);
}
return rows;
}
function reportDifference(
label: string,
expected: readonly string[],
actual: readonly string[],
): readonly string[] {
const missing = expected.filter((value) => !actual.includes(value));
const extra = actual.filter((value) => !expected.includes(value));
const problems: string[] = [];
for (const value of missing) problems.push(`${label}: missing ${value}`);
for (const value of extra) problems.push(`${label}: unexpected ${value}`);
return problems;
}
async function main(): Promise<void> {
const problems: string[] = [];
const tracked = trackedAdapterFiles();
const markdown = await readFile(INVENTORY_PATH, "utf8");
const listed = inventoryRows(markdown);
problems.push(...reportDifference("adapter inventory", tracked, listed));
if (listed.length !== new Set(listed).size) {
problems.push("adapter inventory: duplicate row");
}
const total = /: \*\*(\d+)\/(\d+)\*\*/u.exec(markdown);
if (
!total ||
Number(total[1]) !== tracked.length ||
Number(total[2]) !== tracked.length
) {
problems.push(
`adapter inventory: total does not equal ${tracked.length} tracked files`,
);
}
// SW-RR-03. The generator must read the shared table rather than declare one.
const generator = await readFile(GENERATOR_PATH, "utf8");
if (!generator.includes("CACHEABLE_ASSET_CONTENT_TYPES")) {
problems.push(
"service worker assets: generator does not use the shared extension table",
);
}
if (/const CACHEABLE_EXTENSIONS[^=]*=\s*Object\.freeze\(\{/u.test(generator)) {
problems.push(
"service worker assets: generator declares its own extension table",
);
}
for (const [extension, contentType] of Object.entries(
CACHEABLE_ASSET_CONTENT_TYPES,
)) {
if (!extension.startsWith(".") || contentType.length === 0) {
problems.push(`service worker assets: invalid table row ${extension}`);
}
}
// A fixture that links the repository's node_modules with a single directory
// symlink is destructive: pnpm running inside that fixture purges the modules
// directory it does not recognise, follows the link, and deletes the real
// dependencies mid-run. `linkFixtureNodeModules` is the only sanctioned form.
const sources = spawnSync(
"git",
["grep", "-n", "-e", 'symlink(', "--", "scripts", "tests"],
{ encoding: "utf8" },
);
if (sources.status === 0) {
for (const line of sources.stdout.split("\n").filter(Boolean)) {
if (!line.includes("node_modules")) continue;
if (line.startsWith("scripts/lib/fixture-node-modules.ts:")) continue;
problems.push(
`fixture node_modules: use linkFixtureNodeModules instead — ${line}`,
);
}
}
const linkedFixtures = spawnSync(
"git",
["grep", "-l", "linkFixtureNodeModules", "--", "scripts", "tests"],
{ encoding: "utf8" },
);
if (
linkedFixtures.status !== 0 ||
linkedFixtures.stdout.split("\n").filter(Boolean).length < 2
) {
problems.push(
"fixture node_modules: the shared linker has no callers, so it is not the sanctioned path",
);
}
// TR-RR-05 / GOV-04. Every consumer the re-review named must use the shared
// primitive, not merely one file somewhere. Checking `importers.length > 0`
// let an unrelated production import satisfy the gate while Image and
// Resumable kept their own diverging copies of the same mechanics — which is
// exactly how the four hand-written versions drifted apart in the first place.
const REQUIRED_ABORT_CONSUMERS: readonly string[] = [
"src/adapters/browser-transfer/presigned/presigned-capability-http-provider.ts",
"src/adapters/browser-transfer/presigned/presigned-transfer-executor.ts",
"src/adapters/browser-transfer/image-cdn/browser-image-probe.ts",
"src/adapters/browser-transfer/resumable-upload/fetch-json-transport.ts",
];
const primitiveImporters = spawnSync(
"git",
["grep", "-l", "platform/abortable-operation.ts", "--", "src"],
{ encoding: "utf8" },
);
const importers = (
primitiveImporters.status === 0 ? primitiveImporters.stdout : ""
)
.split("\n")
.filter(Boolean)
.filter((file) => !file.endsWith("platform/abortable-operation.ts"))
.sort();
const importerSet = new Set(importers);
const missingConsumers = REQUIRED_ABORT_CONSUMERS.filter(
(consumer) => !importerSet.has(consumer),
);
if (missingConsumers.length > 0) {
problems.push(
`abortable-operation: required consumers do not import the shared primitive: ${missingConsumers.join(
", ",
)}`,
);
}
// The importer must reach the primitive by a specifier that resolves to the
// primitive itself, so a same-named local helper cannot satisfy the gate.
const PRIMITIVE_PATH = path.resolve(
"src/adapters/platform/abortable-operation.ts",
);
for (const consumer of REQUIRED_ABORT_CONSUMERS) {
if (!importerSet.has(consumer)) continue;
const source = readFileSync(consumer, "utf8");
const specifiers = [
...source.matchAll(/from\s+"([^"]*platform\/abortable-operation\.ts)"/gu),
].map((match) => match[1] ?? "");
const resolved = specifiers.some(
(specifier) =>
path.resolve(path.dirname(consumer), specifier) === PRIMITIVE_PATH,
);
if (!resolved) {
problems.push(
`abortable-operation: ${consumer} does not resolve its import to the shared primitive`,
);
}
}
if (problems.length > 0) {
for (const problem of problems) console.error(problem);
process.exitCode = 1;
return;
}
// GOV-04. The exact importer set is part of the receipt, so a reviewer can
// see which consumers the gate actually verified rather than a bare count.
console.log(
`Adapter inventory: ${tracked.length} files PASS; ` +
`service worker asset table: ${
Object.keys(CACHEABLE_ASSET_CONTENT_TYPES).length
} shared extensions PASS; ` +
`fixture node_modules linking PASS; ` +
`shared abort primitive: ${importers.length} importers ` +
`(${importers.join(", ")}) PASS`,
);
}
await main();