feat(06-04): /api/route engine-A arm + http-source backend #2 — Bearer-gated, honest-null, RP re-pinned (GREEN)

- bot/src/routing/worker-router.ts: module-scope per-env graph memo (1 R2 GET per
  cold isolate, shared with the 06-07 cron arm via loadGraph), snap+A*+deriveSteps,
  claim-gated 401 / 4096-cap 413 / V5 bbox 400, 200-null on every miss class,
  ONE best route (no alternatives), category-only logs
- webhook.ts: /api/route arm delegating to handleRoute (405 non-POST)
- config.ts: ROAD_GRAPH: R2Bucket — first R2 binding (never a KV namespace, GE5)
- wrangler.jsonc: r2_buckets ROAD_GRAPH -> araharah-graphs with the fork law comment
- routing/src/http-source.ts: createHttpRoutingSource — slug-guard-first, fail-honest
  (throw/non-200/malformed/null-body -> null), defensive RouteResult validation;
  exported from index.ts; ladder note: backend #2 LIVE
- A7 re-pinned (06-01 named 06-04 as the owner of createHttpRoutingSource)
- test-side fix during GREEN: the R2 fake hands decodeGraph an exact ArrayBuffer
  (Node Buffers are views; encodeGraph output is already an ArrayBuffer)
- bot 103 passed / routing 65 passed; both typechecks clean
This commit is contained in:
araharah-executor
2026-10-24 13:27:02 +08:00
parent 0abe64e734
commit 020eb92058
8 changed files with 376 additions and 16 deletions
+6 -8
View File
@@ -27,8 +27,9 @@
* (0,-90)->left / (0,90)->right cases; the
* compass-consistent reading is pinned here)
* A7 public surface — index.ts exposes the engine-A exports;
* createHttpRoutingSource is NOT here yet
* (plan 04 adds it)
* createHttpRoutingSource is LIVE (re-pinned
* by 06-04, the plan that added it — the
* original pin named this plan as the owner)
* A8 structural — no `new Map(` in astar.ts (allocation-free
* hot loop: typed arrays only)
*
@@ -251,7 +252,7 @@ test("A6 classifyTurn pins — compass convention: negative bearing delta = left
assert.equal(classifyTurn(350, 80), "right", "90 deg across north is a right");
});
test("A7 public surface — index.ts exposes engine A; createHttpRoutingSource is NOT here yet", async () => {
test("A7 public surface — index.ts exposes engine A + the engine-a HTTP source (re-pinned 06-04)", async () => {
const mod = await import("../src/index.ts");
for (const name of [
"decodeGraph",
@@ -266,14 +267,11 @@ test("A7 public surface — index.ts exposes engine A; createHttpRoutingSource i
"TURN_STRAIGHT_MAX_DEG",
"TURN_SLIGHT_MAX_DEG",
"TURN_UTURN_MIN_DEG",
"createHttpRoutingSource",
]) {
assert.notEqual(mod[name], undefined, `index.ts must export ${name}`);
}
assert.equal(
mod.createHttpRoutingSource,
undefined,
"createHttpRoutingSource belongs to plan 04 — NOT this plan",
);
assert.equal(typeof mod.createHttpRoutingSource, "function", "backend #2's client seam is live (D-01, 06-04)");
});
test("A8 structural — no `new Map(` in astar.ts (typed arrays only in the hot loop)", () => {