test(06-06): failing envelope-flow suite G9-G12 — minimize POST/resume GET/trip-end DELETE + the composed-ladder gate (RED)

- G9 minimize POST: EXACTLY the frozen six-field snapshot (id/chat_id/
  created_at are server-minted), keepalive:true (the minimize race),
  the Bearer header; a live envelope is never double-minted
- G10 DELETE with the stored id on activated (the cron pauses —
  structural) AND at teardown (the D-14 active sweep, idempotent)
- G11 ?g= resume: GUIDE // RESUMING + gantry + projected numbers, the
  watch armed, the line drawn; the first fix flips live ON_ROUTE through
  the machine's own resuming path; the ?g= envelope deletes at teardown
- G12 main.ts composition gate: createHttpRoutingSource + the
  '?? (await' ladder, the UUID-validated ?g= carrier, the
  activated/deactivated wiring, the guidance-aware camera pose, the
  no-double-consult guard, zero env reads
This commit is contained in:
araharah-executor
2026-10-24 15:19:35 +08:00
parent 14e8dfcdd9
commit 6448e31a29
+169
View File
@@ -967,6 +967,8 @@ function steppedDeps(opts = {}) {
guidanceChanges: 0, guidanceChanges: 0,
sourceCalls: [], sourceCalls: [],
followModes: [], followModes: [],
fetches: [],
fetchMode: "ok", // "ok" | "404" — the idempotent-delete tolerance flip
}; };
// every source.route call is recorded (the exactly-one-request gates) // every source.route call is recorded (the exactly-one-request gates)
const baseRoute = deps.source.route.bind(deps.source); const baseRoute = deps.source.route.bind(deps.source);
@@ -995,6 +997,18 @@ function steppedDeps(opts = {}) {
}; };
deps.nowMs = () => guide.now; deps.nowMs = () => guide.now;
deps.findGantry = (banner) => findByClass(banner, "guide-gantry"); deps.findGantry = (banner) => findByClass(banner, "guide-gantry");
// the envelope endpoint + an injectable recording fetch (the stubFetch of
// the plan's acceptance) — every envelope call lands in guide.fetches
deps.endpoint = "/api/guidance";
deps.bearer = () => "test-token";
deps.fetchImpl = async (url, init = {}) => {
guide.fetches.push({ url, init });
if (String(init.method) === "DELETE" && guide.fetchMode === "404") {
return { ok: false, status: 404, json: async () => ({ error: "not_found" }) };
}
if (String(init.method) === "DELETE") return { ok: true, status: 200, json: async () => ({}) };
return { ok: true, status: 201, json: async () => ({ id: "0c0ffee0-0000-4000-8000-000000000000" }) };
};
deps.onGuidanceChange = () => { deps.onGuidanceChange = () => {
guide.guidanceChanges += 1; guide.guidanceChanges += 1;
}; };
@@ -1308,3 +1322,158 @@ test("G8 arrival — the machine's arrival effect runs the same teardown", async
assert.equal(controller.guidancePhase, "ended", "the ended phase exposes to the BackButton graph"); assert.equal(controller.guidancePhase, "ended", "the ended phase exposes to the BackButton graph");
}); });
}); });
/* ============================================================
* 06-06 task 3 — the envelope flows + the composed ladder (G9..G12)
* ============================================================
* G9 minimize POST — the frozen six-field snapshot (id/chat_id/
* created_at are SERVER-minted), keepalive:true, the Bearer header;
* a live envelope is never double-minted
* G10 DELETE on activated (the cron pauses) AND at teardown, both with
* the stored id (the second is the idempotent one)
* G11 ?g= resume — RESUMING chrome with projected numbers, the watch
* armed, the line drawn; the first fix flips live ON_ROUTE
* G12 main.ts composition — the engine-a→fixture ladder, the ?g=
* UUID-validated carrier, the activated/deactivated wiring, the
* guidance-aware camera (structural, the code-constructed law)
*/
function stubFetch(log) {
return (url, init) => {
log.push({ url, init });
if (init.method === "POST") {
return Promise.resolve({ ok: true, json: () => Promise.resolve({ id: "env-1" }) });
}
return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
};
}
test("G9 minimize POST — the frozen six-field snapshot, keepalive, bearer; never double-minted", async () => {
await withDocumentAsync(async () => {
const calls = [];
const deps = steppedDeps();
deps.fetchImpl = stubFetch(calls);
deps.bearer = () => "tok-1";
const controller = createRouteController(deps);
await driveTo(deps, controller);
await withConsole(async () => {
await controller.onDeactivated();
return null;
});
const posts = calls.filter((c) => c.init.method === "POST");
assert.equal(posts.length, 1, "exactly one envelope POST");
const call = posts[0];
assert.equal(call.url, "/api/guidance");
assert.equal(call.init.keepalive, true, "the minimize race is belt-and-braces (keepalive)");
assert.equal(call.init.headers.authorization, "Bearer tok-1", "the memory-held token rides the header");
const body = JSON.parse(call.init.body);
assert.deepEqual(
Object.keys(body).sort(),
["destinationId", "destinationName", "distanceM", "durationS", "geometry", "startedAtSec"],
"EXACTLY the frozen six fields — id/chat_id/created_at are server-minted",
);
assert.equal(body.destinationId, DEST.id);
assert.equal(body.destinationName, DEST.name);
assert.equal(body.distanceM, 2000, "the selected route's summary distance");
assert.equal(body.durationS, 240);
assert.ok(Number.isInteger(body.startedAtSec) && body.startedAtSec > 0, "the trip-start anchor");
const { decodePolyline6 } = await import("@araharah/routing/src/index.ts");
assert.deepEqual(decodePolyline6(body.geometry), CORRIDOR_POINTS, "the geometry re-encodes the live model");
// a second minimize while the envelope is live does not double-mint
await controller.onDeactivated();
assert.equal(posts.length, 1, "the live envelope is not double-minted");
});
});
test("G10 DELETE on activated AND at teardown — both with the stored id (the second is idempotent)", async () => {
await withDocumentAsync(async () => {
const calls = [];
const deps = steppedDeps();
deps.fetchImpl = stubFetch(calls);
deps.bearer = () => "tok-1";
const controller = createRouteController(deps);
await driveTo(deps, controller);
await controller.onDeactivated(); // POST → id env-1 stored
await controller.onActivated(); // DELETE — the cron pauses (structural)
const deletes = calls.filter((c) => c.init.method === "DELETE");
assert.equal(deletes.length, 1, "activated deletes the envelope");
assert.equal(deletes[0].url, "/api/guidance?id=env-1");
// trip end deletes AGAIN with the same id — the server 404s it, tolerated
findByClass(deps.__recorded.shown.at(-1).card, "btn-secondary").click(); // END TRIP
await withConsole(async () => {
findByClass(deps.__recorded.shown.at(-1).card, "btn-primary").click(); // YES, ABANDON
return null;
});
await drain();
const deletesAfter = calls.filter((c) => c.init.method === "DELETE");
assert.equal(deletesAfter.length, 2, "teardown deletes the envelope (the D-14 active sweep)");
assert.equal(deletesAfter[1].url, "/api/guidance?id=env-1", "the SAME stored id — idempotent");
// a second teardown would not delete a third time (the id is consumed)
await controller.onDeactivated(); // no live trip → no mint
assert.equal(calls.filter((c) => c.init.method === "POST").length, 1, "no envelope without a live trip");
});
});
test("G11 ?g= resume — RESUMING chrome with projected numbers; the first fix flips live ON_ROUTE", async () => {
await withDocumentAsync(async () => {
const deps = steppedDeps();
const controller = createRouteController(deps);
const model = {
points: CORRIDOR_POINTS,
cumulative: CORRIDOR_CUMULATIVE,
steps: [],
destinationId: DEST.id,
destinationName: DEST.name,
};
const resumed = await withConsole(async () => {
controller.resume({ model, durationS: 240, projectedRemainingM: 1400, startedAtSec: 900, envelopeId: "env-9" });
return null;
});
assert.equal(controller.state, "route", "the resumed trip holds the route state");
assert.equal(controller.guidancePhase, "driving", "RESUMING is a driving phase — the confirm owns the exit");
assert.equal(deps.__guide.shellRoot.dataset.guidance, "active", "the strip compacts for the resumed trip");
assert.equal(guideRegister(deps), "GUIDE // RESUMING", "the projected register");
assert.ok(findByClass(guideBanner(deps), "guide-gantry") !== null, "the gantry rides the wait state");
assert.equal(guideDistance(deps), "1.4", "the projected remaining distance renders (RESUMING legally shows numbers)");
assert.equal(deps.__guide.watchStarted, 1, "the watch arms for the resumed trip");
const routeSwap = deps.__map.recorded.setData.find((s) => s.id === "route");
assert.equal(routeSwap.data.features[0].geometry.coordinates.length, 3, "the resumed line draws");
assert.ok(resumed.lines.some((l) => l.includes("ARAHARAH-GUIDE state=resuming")), "state=resuming logged");
// the first accepted fix flips to live ON_ROUTE (the machine's own path)
const live = await withConsole(async () => {
feed(600, { deps });
return null;
});
assert.equal(guideRegister(deps), "GUIDE // NEXT", "live ON_ROUTE after the first fix");
assert.equal(findByClass(guideBanner(deps), "guide-gantry"), null, "the gantry stopped on the live flip");
assert.ok(live.lines.some((l) => l.includes("ARAHARAH-GUIDE state=on_route")), "state=on_route logged");
// the resumed trip's envelope deletes at teardown (the ?g= id)
findByClass(deps.__recorded.shown.at(-1).card, "btn-secondary").click(); // END TRIP
await withConsole(async () => {
findByClass(deps.__recorded.shown.at(-1).card, "btn-primary").click(); // YES, ABANDON
return null;
});
assert.equal(controller.guidancePhase, "ended", "the resumed trip ends through the same confirm");
});
});
test("G12 main.ts composition — the ladder, the ?g= carrier, the envelope events, the guidance-aware camera", () => {
const mainCode = codeText(path.join(SRC, "main.ts"));
assert.ok(mainCode.includes("createHttpRoutingSource"), "backend #2 is code-constructed in main.ts");
assert.ok(/\?\? \(await /.test(mainCode), "the composed ladder: engine-a first, fixture fallback");
assert.ok(!mainCode.includes("process.env"), "no env reads — the backend selection is code-constructed (T-05-04)");
assert.ok(/get\("g"\)/.test(mainCode), "the ?g= carrier is read from the URL (the destination-preload pattern)");
assert.ok(
/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/.test(mainCode),
"the resume id is UUID-validated before any GET",
);
assert.ok(
/onEvent\("deactivated"/.test(mainCode) && /onEvent\("activated"/.test(mainCode),
"the envelope lifecycle rides Telegram's activated/deactivated events (T-06-06 guards)",
);
assert.ok(/\.onDeactivated\(\)/.test(mainCode) && /\.onActivated\(\)/.test(mainCode), "the controller's envelope flows are wired");
assert.ok(/guidancePhase === "driving"/.test(mainCode), "the chain's fix does not fight the guidance camera");
assert.ok(/GUIDANCE_CAMERA_PADDING/.test(mainCode), "recenter re-locks at the guidance pose");
assert.ok(/resumeId === null/.test(mainCode), "a resume boot never double-consults");
assert.ok(/kind: "callback"/.test(mainCode) || /kind: "hidden"/.test(mainCode), "the BackButton resolver walks the full graph");
});