Public: anyone can read this; the crew can change it.
"boot: a forge addressed by IP hands every app a host that works > the scaffolded app deploys and answers" passes every time on a loaded check machine #5481
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/5447-boot-a-forge-addressed-by-ip-hands-every → main 1 commit fork 1 thread · 1 unresolved
1 file
changed +12
−3
test/apps-adversarial.test.ts +12 −3
| @@ -1044,6 +1044,7 @@ describe("boot: a forge addressed by IP hands every app a host that works (issue | ||
| 1044 | 1044 | repoId: string, |
| 1045 | 1045 | where: (run: Run) => boolean, |
| 1046 | 1046 | timeoutMs = 60_000, |
| 1047 | live = false, | |
| 1047 | 1048 | ): Promise<Run> { |
| 1048 | 1049 | const deadline = Date.now() + timeoutMs; |
| 1049 | 1050 | while (Date.now() < deadline) { |
| @@ -1052,7 +1053,8 @@ describe("boot: a forge addressed by IP hands every app a host that works (issue | ||
| 1052 | 1053 | ); |
| 1053 | 1054 | if ( |
| 1054 | 1055 | run && |
| 1055 | (run.state === "ok" || | |
| 1056 | ((live && run.servingAt !== null) || | |
| 1057 | run.state === "ok" || | |
| 1056 | 1058 | run.state === "failed" || |
| 1057 | 1059 | run.state === "cancelled") |
| 1058 | 1060 | ) |
| @@ -1114,10 +1116,15 @@ describe("boot: a forge addressed by IP hands every app a host that works (issue | ||
| 1114 | 1116 | if (!made.ok) return; |
| 1115 | 1117 | const repo = made.value.repo; |
| 1116 | 1118 | const record = made.value.app; |
| 1117 | const run = await settled(repo.id, (r) => r.env === "production"); | |
| 1119 | // The deploy reports live the moment the app has answered its health | |
| 1120 | // path and been swapped in — the state the page below is asked in. The | |
| 1121 | // run itself only ends after the scaffold's whole test suite, which on a | |
| 1122 | // loaded machine is far slower than the app's boot; it is awaited after. | |
| 1123 | const live = await settled(repo.id, (r) => r.env === "production", 60_000, true); | |
| 1118 | 1124 | // Before this fix: "start: exited with code 1 before answering" — the |
| 1119 | 1125 | // scaffold's own src/env.ts throwing on `new URL(FORGE_APP_URL)`. |
| 1120 | expect(run.state).toBe("ok"); | |
| 1126 | expect(live.summary).not.toContain("exited with code"); | |
| 1127 | expect(live.servingAt).not.toBeNull(); | |
| 1121 | 1128 | const url = runtime.urlFor(record, "production"); |
| 1122 | 1129 | // The exact check the scaffold makes at import time on FORGE_APP_URL. |
| 1123 | 1130 | expect(() => new URL(url)).not.toThrow(); |
| @@ -1125,6 +1132,8 @@ describe("boot: a forge addressed by IP hands every app a host that works (issue | ||
| 1125 | 1132 | const page = await viaHost(host); |
| 1126 | 1133 | expect(page.status).toBe(200); |
| 1127 | 1134 | expect(await page.text()).toContain("<h1>ip-forge</h1>"); |
| 1135 | const run = await settled(repo.id, (r) => r.id === live.id, 30_000); | |
| 1136 | expect(run.state).toBe("ok"); | |
| 1128 | 1137 | }, 90_000); |
| 1129 | 1138 | }); |
| 1130 | 1139 |
new above
offline
This 30s wait comes after a wait of up to 60s, inside a 90s test timeout. Budget the waits so they sum below the timeout, so the failure names the step that hung.