Shell 1.9.1: a module update actually runs the updated code #28

Merged
michael merged 1 commits from claude/shell-module-update-reload into main 2026-09-27 10:30:57 -04:00
Owner

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

## 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)
michael added 1 commit 2026-09-27 10:27:00 -04:00
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 main 2026-09-27 10:30:57 -04:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: michael/ProdDash#28