feat(ci): two conventions become gates (improvise-w8ih, improvise-4ktt)
The stamp gate is scripts/assemble-stamp.sh, taking FILE PATTERN pairs, and scripts/assemble-stamp-test.sh is its check_the_checker. Deleting the final `test -z "$missing"` makes four of its eight cases fail; before the extraction that same deletion was invisible, both misses printing while assemble.sh exited 0. It is a separate script because exercising it inside assemble.sh would need a fabricated web/pkg, which is a second answer to "what does the site assemble from" (improvise-vvl3). Wired into the `build` job, first, because it needs nothing and guards a step in that job. web/tests/bundle_freedom.test.js refuses a flat web/tests/ file that names the bundle directory -- the constraint keeping the `js` job at seconds rather than ~4m30s, stated in prose and checked by nothing. It scans its own filename too, so it cannot become the place a violation hides, and its companion asserts web/tests/bundle/ still holds a test that DOES use the bundle: a scoping rule is uninteresting if nothing falls outside it. Both faults were injected and watched to fail; evidence in context/test-evidence/tooling.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
+9
-27
@@ -71,33 +71,15 @@ sedi "s|'improvise_worker_server_bg\.wasm'|'improvise_worker_server_bg.wasm?v=${
|
||||
|
||||
# One `grep` over all four files succeeds when ANY one of them matches, so
|
||||
# three failed substitutions could still produce a "successful" assembly under
|
||||
# `set -e` (found by Copilot on PR #24). These checks are the only guard
|
||||
# against the generated glue changing shape, so each stamped reference is
|
||||
# verified on its own and names itself when it is missing.
|
||||
#
|
||||
# `stamped` RECORDS rather than exits, and the gate below is what fails the
|
||||
# build. Exiting on the first failure named one file and never reached the
|
||||
# rest, so a shape change that broke two stamps cost two wasm-pack rebuilds to
|
||||
# diagnose -- the slowest loop in this repo (improvise-x4wv). The gate is the
|
||||
# whole guard: without it every failure prints and the assembly succeeds, which
|
||||
# is the check-that-does-not-check this whole file is full of fixes for.
|
||||
missing=""
|
||||
stamped() {
|
||||
if grep -q "$2" "$1"; then
|
||||
grep -n "$2" "$1"
|
||||
else
|
||||
echo "assemble: $1 is missing the cache-bust stamp: $2" >&2
|
||||
missing="${missing} $1"
|
||||
fi
|
||||
}
|
||||
stamped "$app/app.js" "pkg/improvise_wasm_client.js?v=${token}"
|
||||
stamped "$app/worker.js" "worker-pkg/improvise_worker_server.js?v=${token}"
|
||||
stamped "$app/pkg/improvise_wasm_client.js" "improvise_wasm_client_bg.wasm?v=${token}"
|
||||
stamped "$app/worker-pkg/improvise_worker_server.js" "improvise_worker_server_bg.wasm?v=${token}"
|
||||
test -z "$missing" || {
|
||||
echo "assemble: refusing to ship; unstamped:${missing}" >&2
|
||||
exit 1
|
||||
}
|
||||
# `set -e` (found by Copilot on PR #24). Each stamped reference is therefore
|
||||
# verified on its own, by scripts/assemble-stamp.sh -- which is a separate
|
||||
# script so its refusals can be exercised without fabricating a web/pkg
|
||||
# (improvise-w8ih). Its argument is FILE PATTERN, four times.
|
||||
sh "$root/scripts/assemble-stamp.sh" \
|
||||
"$app/app.js" "pkg/improvise_wasm_client.js?v=${token}" \
|
||||
"$app/worker.js" "worker-pkg/improvise_worker_server.js?v=${token}" \
|
||||
"$app/pkg/improvise_wasm_client.js" "improvise_wasm_client_bg.wasm?v=${token}" \
|
||||
"$app/worker-pkg/improvise_worker_server.js" "improvise_worker_server_bg.wasm?v=${token}"
|
||||
|
||||
# Every relative import the two entry points make must have been copied. The
|
||||
# cp list above is a second answer to "what ships", and a missing sibling is a
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// The `js` CI job must never need a built wasm bundle. See
|
||||
// context/code/clients.md; the split is what keeps it seconds, not ~4m30s.
|
||||
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync, readdirSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const dir = fileURLToPath(new URL(".", import.meta.url));
|
||||
|
||||
/// Built by concatenation so this file carries no literal of the thing it
|
||||
/// forbids, and is therefore checked by itself rather than exempt from itself.
|
||||
const FORBIDDEN = "p" + "kg";
|
||||
|
||||
/// Comments may name the directory — that is what the header above does. Only
|
||||
/// what the code reaches for is a dependency, so strip comments first, exactly
|
||||
/// as render_surface.test.js does.
|
||||
const code = (name) =>
|
||||
readFileSync(dir + name, "utf8")
|
||||
.replace(/\/\*[\s\S]*?\*\//g, " ")
|
||||
.replace(/(^|[^:"'`])\/\/.*$/gm, "$1");
|
||||
|
||||
test("no test in web/tests/ reaches for a built bundle", () => {
|
||||
const siblings = readdirSync(dir).filter((f) => f.endsWith(".test.js"));
|
||||
assert.ok(siblings.length > 1, `found ${siblings.length} test files — the glob moved`);
|
||||
assert.ok(siblings.includes("bundle_freedom.test.js"), "this file must check itself");
|
||||
|
||||
const offenders = siblings.filter((f) => code(f).includes(FORBIDDEN));
|
||||
assert.deepEqual(
|
||||
offenders,
|
||||
[],
|
||||
`these belong in web/tests/bundle/, which the browser job runs: ${offenders}`,
|
||||
);
|
||||
});
|
||||
|
||||
test("the subdirectory that MAY use a bundle is not the one being checked", () => {
|
||||
// Reading it proves the exemption is a real directory rather than a
|
||||
// convention nobody kept, and that this check is scoped to the flat listing.
|
||||
const nested = readdirSync(dir + "bundle").filter((f) => f.endsWith(".test.js"));
|
||||
assert.ok(nested.length > 0, "web/tests/bundle/ is empty — the split lost its other half");
|
||||
assert.ok(
|
||||
nested.some((f) => readFileSync(dir + "bundle/" + f, "utf8").includes(FORBIDDEN)),
|
||||
"no bundle test reaches for a bundle, so this check has nothing to be scoped against",
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user