diff --git a/src/bridge/server-route-order.test.ts b/src/bridge/server-route-order.test.ts index a19b608..979f0d3 100644 --- a/src/bridge/server-route-order.test.ts +++ b/src/bridge/server-route-order.test.ts @@ -28,16 +28,29 @@ interface Layer { regexp?: RegExp; } +// UI static hosting (mountUiStatic in ui-static.ts) is registered only when +// ui/dist exists on disk (existsSync check), so its presence in the +// fingerprint flips between a built checkout (CI, dev) and a fresh/unbuilt +// worktree. It is excluded below — the ordering of these entries relative to +// each other is not pinned by this test, only the surrounding API routes are. +const UI_STATIC_ENTRY_PATTERNS = [ + /^USE name=serveStatic path=\^\\\/ui\\\/\?/, + /^ROUTE get \/ui\/\*$/, + /^ROUTE get \/app-harness$/, +]; + /** Ordered fingerprint of the app's top-level middleware/route layers. */ function fingerprint(app: Application): string[] { const stack: Layer[] = (app as unknown as { _router?: { stack: Layer[] } })._router?.stack ?? []; - return stack.map((layer) => { - if (layer.route) { - const methods = Object.keys(layer.route.methods).sort().join(','); - return `ROUTE ${methods} ${layer.route.path}`; - } - return `USE name=${layer.name ?? ''} path=${layer.regexp?.source ?? ''}`; - }); + return stack + .map((layer) => { + if (layer.route) { + const methods = Object.keys(layer.route.methods).sort().join(','); + return `ROUTE ${methods} ${layer.route.path}`; + } + return `USE name=${layer.name ?? ''} path=${layer.regexp?.source ?? ''}`; + }) + .filter((entry) => !UI_STATIC_ENTRY_PATTERNS.some((pattern) => pattern.test(entry))); } function mkAuthConfig(): AuthConfig { diff --git a/src/progress/event-log.test.ts b/src/progress/event-log.test.ts index 9d58f1e..77a322a 100644 --- a/src/progress/event-log.test.ts +++ b/src/progress/event-log.test.ts @@ -148,7 +148,8 @@ describe('FileEventLogger', () => { expect(parsed.iteration).toBe(5); }); - it('does NOT throw when the workspace directory is not writable (failure isolation)', () => { + // root ignores chmod-based write denial, so this only holds as non-root (e.g. CI running as root). + it.skipIf(process.getuid?.() === 0)('does NOT throw when the workspace directory is not writable (failure isolation)', () => { // Make the workspace read-only so appendFileSync fails. chmodSync(workspace, 0o555); try {