Files
worldmonitor/Dockerfile.relay
Elie Habib c31662c3c9 fix(relay): COPY missing _seed-envelope-source + _seed-contract — chokepointFlows stale 32h (#3132)
* fix(relay): COPY _seed-envelope-source + _seed-contract into Dockerfile.relay

Root cause of chokepointFlows STALE_SEED (1911min stale, maxStaleMin=720):
since 2026-04-14 (PR #3097/#3101 landing), scripts/_seed-utils.mjs imports
_seed-envelope-source.mjs and _seed-contract.mjs. Dockerfile.relay COPY'd
_seed-utils.mjs but NOT its new transitive dependencies, so every execFile
invocation of seed-chokepoint-flows.mjs, seed-climate-news.mjs, and
seed-ember-electricity.mjs crashed at import with ERR_MODULE_NOT_FOUND.
The ais-relay loop kept firing every 6h but each child died instantly —
no visible error because execFile only surfaces child stderr to the
parent relay's log stream.

Local repro: node scripts/seed-chokepoint-flows.mjs runs fine in 3.6s
and writes 7 records. Same command inside the relay container would
throw at the import line because the file doesn't exist.

Fix:
1. Add COPY scripts/_seed-envelope-source.mjs and
   COPY scripts/_seed-contract.mjs to Dockerfile.relay.
2. Add a static guard test (tests/dockerfile-relay-imports.test.mjs)
   that BFS's the transitive-import graph from every COPY'd entrypoint
   and fails if any reached scripts/*.mjs|cjs isn't also COPY'd. This
   would have caught the original regression.

Matches feedback_dockerfile_relay_explicit_copy.md — we now have a test
enforcing it.

* fix(test): scanner also covers require() and createRequire(...)(...) — greptile P2

Review finding on PR #3132: collectRelativeImports only matched ESM
import/export syntax, so require('./x.cjs') in ais-relay.cjs and
createRequire(import.meta.url)('./x.cjs') in _seed-utils.mjs were
invisible to the guard. No active bug (_proxy-utils.cjs is already
COPY'd) but a future createRequire pointing at a new uncopied helper
would slip through.

Two regexes now cover both forms:
- cjsRe: direct require('./x') — with a non-identifier lookbehind so
  'thisrequire(' or 'foorequire(' can't match.
- createRequireRe: createRequire(...)('./x') chained-call — the outer
  call is applied to createRequire's return value, not to a 'require('
  token, so the first regex misses it on its own.

Added a unit test asserting both forms resolve on known sites
(_seed-utils.mjs and ais-relay.cjs) so the next edit to this file
can't silently drop coverage.
2026-04-16 17:28:16 +04:00

2.3 KiB