fix(bundles): warm mpak cache before manifest read so cold-install placements register (#60)#367
Merged
Merged
Conversation
…acements register (#60) Named bundles declare UI placements under `_meta["ai.nimblebrain/host"].placements`. `startBundleSource` read the manifest from the mpak bundle cache once, up front, to derive that metadata — but on a cold/first-ever install the cache is empty, so the read returned null, `meta`/`manifest` stayed null, and placement registration (plus user_config resolution) silently no-op'd. The bundle spawned and its tools worked (it showed under Connectors), but its `sidebar.apps` placement never registered, so it never appeared under Apps until a process restart re-read the now-warm cache. `prepareServer` populates the cache as a side effect, but only *after* the up-front read, and nothing re-registered placements. `installNamed` masked this by pre-warming with `loadBundle` before calling `startBundleSource`; the Connectors-UI path (`installBundleInWorkspace`) didn't, so UI installs hit the bug. Fix at the single chokepoint every named install/respawn path funnels through: warm the cache before the up-front read. Guard on `getBundleManifest` (the same manifest.json the read consumes), not on `loadBundle`'s internal `.mpak-meta.json` short-circuit — so a manifest-only cache (warm boots, offline starts, test fixtures) adds no network call. Remove the now-redundant pre-warm from `installNamed`. Regression test reproduces the cold→warm transition deterministically by stubbing `loadBundle` to materialize the cache; it fails without the fix (meta null) and passes with it, and a second case locks the no-extra-pull guarantee on warm caches.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #60. Named bundles that declare UI placements (
_meta["ai.nimblebrain/host"].placements, e.g.slot: "sidebar.apps") silently failed to register them on a cold/first-ever install — the bundle spawned and its tools worked (it showed under Connectors), but it never appeared under Apps until a full process restart.Confirmed in prod: tenant
webcaredigital, bundle@nimblebraininc/synapse-collateral— present as a connector, absent from the Apps nav, the platform logging themanifest cache misswarning.Root cause
startBundleSource(src/bundles/startup.ts, named-bundle branch) reads the manifest from the mpak bundle cache once, up front, to derive placement/UI metadata. On a cold cache that read returnsnull, someta/manifeststay null and placement registration (plususer_configresolution) silently no-op.prepareServerpopulates the cache as a side effect — but only after the read, and nothing re-registers placements. A restart re-reads the now-warm cache and the placement appears.installNamed(admin/CLI path) masked the bug by pre-warming withloadBundlebefore callingstartBundleSource(lifecycle.ts). The Connectors-UI path (installBundleInWorkspace) didn't, so UI installs hit it.The issue's "log a warning when the read misses" recommendation already shipped — that's the
manifest cache misswarning. This PR lands the actual fix.Fix
Warm the cache at the one chokepoint every named install/respawn path funnels through (connector UI,
installNamed, boot reload, JIT), immediately before the up-front read:getBundleManifest(the samemanifest.jsonthe read consumes), not onloadBundle's internal.mpak-meta.jsonshort-circuit. A manifest-only cache (warm boots, offline starts, test fixtures) therefore adds no network call — warm-cache spawns stay network-free, exactly as today.installNamed; the contract is enforced in one place instead of relied on per-caller.Tests
New
test/integration/startup-cold-cache-placements.test.tsreproduces the cold→warm transition deterministically by stubbingloadBundleto materialize the cache (no network):meta === null, emits the prod warning) and pass with it.await loadBundlewould make this 2 and hit the network on manifest-only caches).verify:staticgreen; 127/127 across the bundle/placement/install suites pass.Review
Root-cause analysis run through the bug-fix workflow with an independent adversarial review (ENDORSE-WITH-REFINEMENTS) — the reviewer caught the
.mpak-meta.jsonvsmanifest.jsonshort-circuit mismatch, which is why the warm is guarded ongetBundleManifest.