test(04-04): the BA7/BA8 drift gates + the search-tree GEO3 pin + the destination-preload capture leg

- BA7: the shipped JS must carry EVERY committed gazetteer id (the
  web half of bot/web id-set parity, T-04-39) — RED against the
  pre-gazetteer bundle, green after the resolver lands in the build
- BA8: the shipped JS carries NO deep-link crypto (JS assets only —
  the official Telegram SDK is external, D-11/T-04-40)
- no-storage: explicit web/src/search memory-only + no-crypto pin
- capture.mjs: the ARAHARAH-DEST signal race + the 'dest' wait mode
  (state=resolved asserted, then the rendered card's text is waited
  on — the card mounts at live, T-04-42) + the shell-dest-preload
  leg; 8/8 expected captures
This commit is contained in:
araharah-executor
2026-10-24 01:38:24 +08:00
parent c2d78b0c8f
commit 747eeb7b34
3 changed files with 106 additions and 6 deletions
+41
View File
@@ -24,6 +24,17 @@
* BA5 pointed there would invert the gate it exists to enforce.
* BA6 no emitted HTML carries the runner page's /api/session or
* /api/location-fallback fetch stubs (same dead-code-elimination proof)
* BA7 the shipped JS carries EVERY gazetteer id from the committed
* dataset (search/src/data/kl-gazetteer.json) — the WEB half of the
* bot/web id-set parity gate (T-04-39): a stale web bundle ships
* without an id the bot just deep-linked, and the webview could
* never resolve it
* BA8 the shipped JS carries NO deep-link crypto (createHmac,
* crypto.subtle, sha256, HMAC() — the deep link is a plain public id
* (D-11, T-04-40). Scans the JS ASSETS only, never the HTML: the
* OFFICIAL Telegram SDK script is loaded EXTERNALLY from
* telegram.org (not bundled) and may contain crypto internals of
* its own.
*
* If web/dist does not exist, every case fails with a build-first message.
*/
@@ -33,6 +44,7 @@ import { join } from "node:path";
import { fileURLToPath } from "node:url";
import path from "node:path";
import { test } from "./harness.mjs";
import gazetteer from "../../search/src/data/kl-gazetteer.json" with { type: "json" };
const WEB = path.join(fileURLToPath(new URL(import.meta.url)), "..", "..");
const DIST = join(WEB, "dist");
@@ -133,3 +145,32 @@ test("BA6 production HTML carries NO runner-page fetch stub endpoints", () => {
);
}
});
test("BA7 the shipped bundle carries EVERY gazetteer id (the bot/web id-set parity gate, T-04-39)", () => {
assert.ok(existsSync(DIST_ASSETS), claimBuildFirst().message);
const bundle = jsFiles
.filter((f) => f.startsWith(DIST_ASSETS))
.map((f) => readFileSync(f, "utf8"))
.join("");
assert.ok(gazetteer.entries.length >= 30, `scanned a real dataset (found ${gazetteer.entries.length} entries)`);
for (const entry of gazetteer.entries) {
assert.ok(
bundle.includes(entry.id),
`gazetteer id "${entry.id}" is MISSING from the shipped web bundle — a stale bundle the webview cannot resolve against (T-04-39); ids are never renamed, only added`,
);
}
});
test("BA8 the shipped bundle carries NO deep-link crypto (D-11, T-04-40)", () => {
assert.ok(existsSync(DIST_ASSETS), claimBuildFirst().message);
const bundle = jsFiles
.filter((f) => f.startsWith(DIST_ASSETS))
.map((f) => readFileSync(f, "utf8"))
.join("");
for (const token of ["createHmac", "crypto.subtle", "sha256", "HMAC("]) {
assert.ok(
!bundle.includes(token),
`"${token}" found in a web/dist JS asset — the deep link is a PLAIN public id, no crypto anywhere in the path (D-11)`,
);
}
});
+26 -1
View File
@@ -12,7 +12,7 @@
* tokens appear — code occurrences only.
*/
import { strict as assert } from "node:assert";
import { readFileSync, readdirSync, statSync } from "node:fs";
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { test } from "./harness.mjs";
@@ -77,3 +77,28 @@ test("GEO3 web/src/session/store.ts assigns nothing to any storage object (the D
// ...and keeps the named TTL constant the client revalidates against (D-03).
assert.ok(code.includes("SESSION_TTL_SECONDS = 900"), "the 900s TTL mirror by name is present");
});
test("GEO3 web/src/search/ holds no persistence surface and no deep-link crypto", () => {
// The ONBD-02 tree (04-04): the resolved destination is user context and
// stays MEMORY-ONLY (GEO-03/D-07), and the deep-link path is a plain
// public id with NO crypto (D-11). The whole-tree GEO3 gate above already
// walks this directory; this explicit case pins the new tree + the
// no-crypto law so a future file there fails HERE, by name.
const searchDir = path.join(SRC, "search");
assert.ok(existsSync(searchDir), "web/src/search exists (the ONBD-02 resolver tree)");
for (const file of listFiles(searchDir, [".ts"])) {
const code = codeText(file);
for (const banned of BANNED) {
assert.ok(
!code.includes(banned),
`${path.relative(process.cwd(), file)} references ${banned} — GEO-03 violated (web/src/search must stay memory-only)`,
);
}
for (const token of ["createHmac", "crypto.subtle", "sha256"]) {
assert.ok(
!code.includes(token),
`${path.relative(process.cwd(), file)} references ${token} — D-11 forbids crypto in the deep-link path`,
);
}
}
});