AB updated Timers to 1.5.0 and the new LTC capture-tool self-build never ran — the tile still showed the 1.4.x error text, word for word. That mismatch was the tell: the manifest is read fresh from disk (so /api/modules reported 1.5.0), but the module's code loads through require(), and Node's require cache handed back the code loaded at startup. A catalog update swaps the folder on disk; the process keeps executing the old module until ProdDash itself restarts. Every module update to date has silently depended on a follow-up app restart nobody knew was required.
Fix
mountModule drops the module directory's entries from require.cache before requiring, so every (re)mount runs the files on disk — nested requires (ltc-listener.js, propresenter-core, helpers) included. Modules already must come up clean on re-init per the module guide, so config-change remounts see the same contract they always promised to honor, minus the trap.
Verified
Probe module in a scratch data dir: changed a nested require on disk, remounted via a config PUT — the route serves the new code (it served the stale code before the fix, which is the exact AB failure shape).
The Timers module re-inits cleanly across repeated fresh-code remounts (its module-scope current handle rebuilds per mount, as the guide requires).
Shell 1.9.0 → 1.9.1, no module changes. Until this lands on the booths, the workaround for any module update is a ProdDash restart from the launcher — which is also all AB needs today for Timers 1.5.0 to take effect and build its capture tool.
## Found via AB
AB updated Timers to 1.5.0 and the new LTC capture-tool self-build never ran — the tile still showed the 1.4.x error text, word for word. That mismatch was the tell: the **manifest** is read fresh from disk (so `/api/modules` reported 1.5.0), but the module's **code** loads through `require()`, and Node's require cache handed back the code loaded at startup. A catalog update swaps the folder on disk; the process keeps executing the old module until ProdDash itself restarts. Every module update to date has silently depended on a follow-up app restart nobody knew was required.
## Fix
`mountModule` drops the module directory's entries from `require.cache` before requiring, so every (re)mount runs the files on disk — nested requires (`ltc-listener.js`, `propresenter-core`, helpers) included. Modules already must come up clean on re-init per the module guide, so config-change remounts see the same contract they always promised to honor, minus the trap.
## Verified
- Probe module in a scratch data dir: changed a **nested** require on disk, remounted via a config PUT — the route serves the new code (it served the stale code before the fix, which is the exact AB failure shape).
- The Timers module re-inits cleanly across repeated fresh-code remounts (its module-scope `current` handle rebuilds per mount, as the guide requires).
Shell 1.9.0 → 1.9.1, no module changes. Until this lands on the booths, the workaround for any module update is a ProdDash restart from the launcher — which is also all AB needs today for Timers 1.5.0 to take effect and build its capture tool.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
AB updated the Timers module to 1.5.0 and its new LTC capture-tool
self-build never ran: mountModule re-required the module's server entry,
and Node's require cache handed back the OLD code — the catalog update
had swapped the folder on disk, but the process kept executing what it
loaded at startup until ProdDash itself restarted. The manifest, read
fresh from disk, meanwhile reported the new version, so the admin page
claimed an update that functionally hadn't happened. Every module update
to date has silently depended on a follow-up app restart.
mountModule now drops the module directory's entries from require.cache
before requiring, so every (re)mount runs the files on disk — nested
requires (ltc-listener.js and friends) included. Modules already must
come up clean on re-init per the module guide, so config-change remounts
see the same contract, minus the trap.
Verified with a probe module in a scratch data dir: change a nested
require on disk, PUT config to remount, the route serves the new code
(it served the stale code before the fix). The Timers module re-inits
cleanly across repeated fresh-code remounts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
michael
merged commit 914ff7795b into main2026-09-27 10:30:57 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Found via AB
AB updated Timers to 1.5.0 and the new LTC capture-tool self-build never ran — the tile still showed the 1.4.x error text, word for word. That mismatch was the tell: the manifest is read fresh from disk (so
/api/modulesreported 1.5.0), but the module's code loads throughrequire(), and Node's require cache handed back the code loaded at startup. A catalog update swaps the folder on disk; the process keeps executing the old module until ProdDash itself restarts. Every module update to date has silently depended on a follow-up app restart nobody knew was required.Fix
mountModuledrops the module directory's entries fromrequire.cachebefore requiring, so every (re)mount runs the files on disk — nested requires (ltc-listener.js,propresenter-core, helpers) included. Modules already must come up clean on re-init per the module guide, so config-change remounts see the same contract they always promised to honor, minus the trap.Verified
currenthandle rebuilds per mount, as the guide requires).Shell 1.9.0 → 1.9.1, no module changes. Until this lands on the booths, the workaround for any module update is a ProdDash restart from the launcher — which is also all AB needs today for Timers 1.5.0 to take effect and build its capture tool.
🤖 Generated with Claude Code