Skip to content

fix(gateway): inline runtime into bundle to fix image crash-loop#708

Merged
marcusrbrown merged 1 commit into
mainfrom
fix/gateway-runtime-packaging
May 31, 2026
Merged

fix(gateway): inline runtime into bundle to fix image crash-loop#708
marcusrbrown merged 1 commit into
mainfrom
fix/gateway-runtime-packaging

Conversation

@marcusrbrown
Copy link
Copy Markdown
Collaborator

Summary

The gateway Docker image crash-looped on boot with ERR_MODULE_NOT_FOUND for @fro-bot/runtime. The gateway bundle imported the runtime as an external bare specifier that resolved to its src/index.ts entry — a file absent from the runtime image, which ships only dist/.

Changes

  • Inline the runtime into the gateway bundle (packages/gateway/tsdown.config.ts) via noExternal, matching how the action tier already bundles the runtime. The gateway bundle is now self-contained.
  • Drop the now-dead runtime copy from the gateway image's final stage in deploy/gateway.Dockerfile — the inlined bundle no longer references @fro-bot/runtime at runtime.
  • Add a gateway image smoke test to CI: build the image, boot it with no secrets, and assert it reaches config loading without a module-resolution crash. A build-time check also asserts the bundle contains no bare @fro-bot/runtime import. This catches the packaging regression class that previously shipped undetected.

Verification

  • Gateway bundle contains zero bare @fro-bot/runtime imports after build.
  • Local image smoke: boots, exits cleanly on missing secrets, no ERR_MODULE_NOT_FOUND.
  • Gateway tests, lint, and type-check pass.

Fixes #707

The gateway bundle imported @fro-bot/runtime as an external specifier that
resolved to its src/index.ts entry, which is absent from the runtime image —
crash-looping on boot with ERR_MODULE_NOT_FOUND. Inline the runtime into the
gateway bundle (matching the action tier), drop the now-dead runtime copy from
the image, and add a CI smoke that builds and boots the image to catch
packaging regressions.

Fixes #707
@marcusrbrown marcusrbrown requested a review from fro-bot as a code owner May 31, 2026 07:25
@fro-bot fro-bot added the agent: working Agent is currently working on this label May 31, 2026
Copy link
Copy Markdown
Owner

@fro-bot fro-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: PASS

The fix is correct, minimal, and well-targeted. Inlining @fro-bot/runtime via noExternal in packages/gateway/tsdown.config.ts makes the gateway bundle self-contained, which directly resolves the ERR_MODULE_NOT_FOUND crash-loop: the final image no longer carries packages/runtime/dist, and the bundle no longer emits a bare @fro-bot/runtime specifier that would resolve to the absent src/index.ts. Dropping the now-dead COPY lines from deploy/gateway.Dockerfile is the right follow-through. The new gateway-smoke CI job is a genuine regression guard for the exact packaging failure class that previously shipped undetected.

I verified the bundler change is consistent with the established pattern — the root action-tier tsdown.config.ts already lists @fro-bot/runtime under noExternal, so this brings the gateway tier in line.

Blocking issues

None

Non-blocking concerns

  • Bundle-path assertion is hard-coded to dist/main.mjs. The smoke job greps packages/gateway/dist/main.mjs and runs node dist/main.mjs, while the gateway tsdown.config.ts sets outDir: 'dist' without a fixed extension. If a future tsdown/format change emits main.js (or splits chunks), the grep -q would match nothing and silently pass, while CMD ["node", "dist/main.mjs"] in the Dockerfile would break at runtime. Consider globbing the bundle dir (e.g. assert over packages/gateway/dist/*.{js,mjs}) so the check can't be bypassed by an extension change, and keeping the Dockerfile CMD and the test path derived from one source of truth.
  • Smoke test couples to two human-readable log strings (Missing required secret: DISCORD_TOKEN and ERR_MODULE_NOT_FOUND). The negative assertion on ERR_MODULE_NOT_FOUND is robust. The positive assertion on the exact Missing required secret: DISCORD_TOKEN phrasing will break if that config-error message is ever reworded; it's load-bearing for the test but not for behavior. A slightly more durable signal (e.g. a stable exit code for missing-secret, or a dedicated startup marker) would decouple the guard from copy changes. Low priority.
  • gateway-smoke rebuilds runtime + gateway from source even though needs: [setup] and a separate build job already compiles the workspace. This is acceptable isolation for a Docker build, just noting the duplicated compile cost.

Missing tests

  • The smoke test proves the image doesn't crash on module resolution, but not that inlined runtime code is actually reachable at runtime. Since the failure mode here is specifically "imported symbol resolves to a missing file," reaching the DISCORD_TOKEN config check (which executes after module load) is a reasonable proxy and largely covers this. A direct positive assertion that a runtime-provided export executes would be stronger but is not required given the config-load checkpoint.
  • No assertion that the final image no longer contains node_modules/.../@fro-bot/runtime or packages/runtime/dist. Adding a ! test -e ... check would lock in the Dockerfile deletion so a future re-add is caught. Optional hardening.

Risk assessment (LOW/MED/HIGH): LOW

Blast radius is confined to the gateway image build and CI; no runtime API, secret handling, network surface, or auth path is touched. The smoke job boots with no secrets, so it cannot leak anything. The change mirrors the already-proven action-tier bundling pattern and replaces a hard crash-loop with a self-contained bundle, so regression likelihood is low. The only residual exposure is the bundle-path/log-string coupling noted above, which affects detection durability of the new guard rather than the correctness of the fix itself.


Run Summary
Field Value
Event pull_request
Repository fro-bot/agent
Run ID 26706460915
Cache hit
Session ses_18311febfffeST2iFz8lsVHBNg

@fro-bot fro-bot removed the agent: working Agent is currently working on this label May 31, 2026
@marcusrbrown marcusrbrown merged commit 721f213 into main May 31, 2026
11 checks passed
@marcusrbrown marcusrbrown deleted the fix/gateway-runtime-packaging branch May 31, 2026 07:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gateway v0.46.1 runtime image crash-loops: ERR_MODULE_NOT_FOUND @fro-bot/runtime resolves to src/index.ts

2 participants