Variant
worldmonitor.app (Full / Geopolitical)
Affected area
Other
Bug description
Summary
The app Dockerfile builder stage runs, in order: npm ci → COPY . . → node scripts/generate-inventory-facts.mjs → node docker/build-handlers.mjs → npm run build:pro → npm run build:crawlable-corpus && npm run build:sitemap && npx tsc && npx vite build.
build:crawlable-corpus invokes the source-attribution drift gate (validateManifest in scripts/source-attribution.mjs), which scans SOURCE_ROOTS = ['scripts', 'server', 'api', 'src'] for files with extensions in SOURCE_EXTENSIONS (including .js) and requires every observed host's scan-derived kinds/references to deep-equal the committed manifest (shared/source-attribution-manifest.json).
By the time the gate runs, two earlier Dockerfile steps have written untracked .js into those same scanned roots: generate-inventory-facts.mjs (e.g. api/_inventory-facts.generated.js) and build-handlers.mjs (~130 compiled handler files in api/, each embedding the source URLs of the TypeScript it was compiled from). The scan sees hundreds of files the manifest was never generated against, nearly every entry drifts, and the build dies:
Error: source-attribution: invalid manifest (stale manifest entry for 24.hu: kind, references no longer match the source tree; run node scripts/source-attribution.mjs --write; ...)
~472 entries on our install, reproduced at both 2b1f9553 (2026-08-28) and d1b9d117 (2026-08-29 tip). The remedy in the error message (--write) is wrong here: regenerating against a build-polluted tree would commit the pollution.
Evidence the gate itself is sound
Running the gate against the pristine checkout inside the same container image passes cleanly:
docker run --rm -v <repo>:/x:ro -w /x --entrypoint node worldmonitor:latest scripts/source-attribution.mjs --check
# → source-attribution: 753 active hosts across 744 providers (...), exit 0
The failure is purely ordering: pristine tree passes, post-generator tree fails.
Reproduction
- Clean clone of
main (verified at 2b1f9553 and d1b9d117).
docker compose build worldmonitor.
- Builder step
npm run build:crawlable-corpus ... exits 1 with hundreds of stale manifest entry errors.
Expected
The repo's own Dockerfile should be able to build the repo's own image. The attribution gate should either run against the pristine tree (before any generator step), or exclude generated artifacts from the scan (e.g. skip *.generated.* and build-handlers outputs), or both.
Suggested fix
Move npm run build:crawlable-corpus && npm run build:sitemap to immediately after COPY . . (before generate-inventory-facts and build-handlers), or teach walkSourceFiles to consult .gitignore/a generated-file denylist so the gate only ever sees tracked sources.
Workaround (in production on our install since 2026-08-29)
Dockerfile reordered exactly as above (corpus + sitemap run right after COPY . .; npx tsc && npx vite build stay in their original position). Full image build completes; gate passes at its new position.
Environment
Steps to reproduce
- Clean clone of
main (reproduced at 2b1f9553, 2026-08-28, and at d1b9d117, 2026-08-29 tip)
docker compose build worldmonitor per the self-hosting docs
- Builder reaches the step
RUN npm run build:crawlable-corpus && npm run build:sitemap && npx tsc && npx vite build
- Build exits 1:
Error: source-attribution: invalid manifest (stale manifest entry for 24.hu: kind, references no longer match the source tree; run node scripts/source-attribution.mjs --write; ...) — repeated for ~472 hosts
- Control experiment:
docker run --rm -v <repo>:/x:ro -w /x --entrypoint node worldmonitor:latest scripts/source-attribution.mjs --check against the pristine checkout passes (753 active hosts, exit 0), confirming the gate fails only after generate-inventory-facts.mjs and build-handlers.mjs have written untracked .js into the scanned roots
Expected behavior
The repo's own Dockerfile should be able to build the repo's own image from a clean checkout. The source-attribution drift gate should either run against the pristine tree (before any generator step writes into the scanned roots), or exclude generated artifacts from the scan (e.g. skip *.generated.* and the build-handlers outputs), or both. An operator following the self-hosting docs should get a completed image, not ~472 stale-manifest errors pointing them at --write (which would regenerate the manifest against a build-polluted tree and commit the pollution).
Screenshots / Console errors
No response
Browser & OS
No response
Variant
worldmonitor.app (Full / Geopolitical)
Affected area
Other
Bug description
Summary
The app
Dockerfilebuilder stage runs, in order:npm ci→COPY . .→node scripts/generate-inventory-facts.mjs→node docker/build-handlers.mjs→npm run build:pro→npm run build:crawlable-corpus && npm run build:sitemap && npx tsc && npx vite build.build:crawlable-corpusinvokes the source-attribution drift gate (validateManifestinscripts/source-attribution.mjs), which scansSOURCE_ROOTS = ['scripts', 'server', 'api', 'src']for files with extensions inSOURCE_EXTENSIONS(including.js) and requires every observed host's scan-derivedkinds/referencesto deep-equal the committed manifest (shared/source-attribution-manifest.json).By the time the gate runs, two earlier Dockerfile steps have written untracked
.jsinto those same scanned roots:generate-inventory-facts.mjs(e.g.api/_inventory-facts.generated.js) andbuild-handlers.mjs(~130 compiled handler files inapi/, each embedding the source URLs of the TypeScript it was compiled from). The scan sees hundreds of files the manifest was never generated against, nearly every entry drifts, and the build dies:~472 entries on our install, reproduced at both
2b1f9553(2026-08-28) andd1b9d117(2026-08-29 tip). The remedy in the error message (--write) is wrong here: regenerating against a build-polluted tree would commit the pollution.Evidence the gate itself is sound
Running the gate against the pristine checkout inside the same container image passes cleanly:
The failure is purely ordering: pristine tree passes, post-generator tree fails.
Reproduction
main(verified at2b1f9553andd1b9d117).docker compose build worldmonitor.npm run build:crawlable-corpus ...exits 1 with hundreds ofstale manifest entryerrors.Expected
The repo's own Dockerfile should be able to build the repo's own image. The attribution gate should either run against the pristine tree (before any generator step), or exclude generated artifacts from the scan (e.g. skip
*.generated.*andbuild-handlersoutputs), or both.Suggested fix
Move
npm run build:crawlable-corpus && npm run build:sitemapto immediately afterCOPY . .(beforegenerate-inventory-factsandbuild-handlers), or teachwalkSourceFilesto consult.gitignore/a generated-file denylist so the gate only ever sees tracked sources.Workaround (in production on our install since 2026-08-29)
Dockerfile reordered exactly as above (corpus + sitemap run right after
COPY . .;npx tsc && npx vite buildstay in their original position). Full image build completes; gate passes at its new position.Environment
docker composefrom the repo's compose file, checkout2b1f9553Steps to reproduce
main(reproduced at2b1f9553, 2026-08-28, and atd1b9d117, 2026-08-29 tip)docker compose build worldmonitorper the self-hosting docsRUN npm run build:crawlable-corpus && npm run build:sitemap && npx tsc && npx vite buildError: source-attribution: invalid manifest (stale manifest entry for 24.hu: kind, references no longer match the source tree; run node scripts/source-attribution.mjs --write; ...)— repeated for ~472 hostsdocker run --rm -v <repo>:/x:ro -w /x --entrypoint node worldmonitor:latest scripts/source-attribution.mjs --checkagainst the pristine checkout passes (753 active hosts, exit 0), confirming the gate fails only aftergenerate-inventory-facts.mjsandbuild-handlers.mjshave written untracked .js into the scanned rootsExpected behavior
The repo's own Dockerfile should be able to build the repo's own image from a clean checkout. The source-attribution drift gate should either run against the pristine tree (before any generator step writes into the scanned roots), or exclude generated artifacts from the scan (e.g. skip
*.generated.*and thebuild-handlersoutputs), or both. An operator following the self-hosting docs should get a completed image, not ~472 stale-manifest errors pointing them at--write(which would regenerate the manifest against a build-polluted tree and commit the pollution).Screenshots / Console errors
No response
Browser & OS
No response