Repository navigation
fix(everything-dev): stamp app.* slots only — plugins are declaration-scoped (rc.26 child-deploy hotfix) - #657
Merged
Conversation
…-scoped (rc.26 child-deploy hotfix) The rc.26 release-scoped stamping wrote every non-authored slot from the release manifest's slots map into the child's leaf payload — including the parent's plugins.* slots. A child that declares its own `plugins` object owns the whole plugin domain in one wholesale replace (mergeBosConfigWithExtends), so the stamps (a) expanded the child's composed plugin set to the parent's entire fleet and (b) produced schema-invalid plugins.<id>.ui records — the stamped ui entry carries no required `name`, and the wholesale replace never fills it — which the boot-check refused: children with authored plugins (feedback.nearbuilders.org) could not deploy; plugins.ai: Invalid input. Fix: the stamp policy allowlists app.* slots only (`^app\.[^.]+(\.ui)?$`) — the base-runtime slots children never author and which merge per-key with the parent (so the parent's ui.name and friends fill the stamped entries). The release manifest keeps recording every slot (a record, not a policy). Tests: - unit: the rc.26 regression pinned — a child with authored plugins stamps only app.*; its plugins object stays byte-equal untouched. - e2e: simulateDeploy now runs verifyResolvedBootShape over the merged shape (the coverage that would have caught this), and the incident-replay child declares its own plugin while the root release carries plugins.* slots — stamped list app-only, merged.plugins equals the child's exact set, merged shape schema-valid. The e2e fixture's live parent config also gains the required app.host / app.api keys the schema parse needs.
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.
The incident
Merging #656 released rc.26 — the first release-carrying slots manifest and the first CLI that stamps. Children deploying with the rc.26 CLI got every non-authored slot in the release manifest's
slotsmap stamped into their leaf payload — including the parent'splugins.*slots. For children that declare their ownpluginsset (e.g. feedback.nearbuilders.org), that broke deploys in CI:Two compounding defects, both in the stamp policy:
pluginsobject owns the whole plugin domain in one wholesale replace (merge.ts:109-113 —merged.plugins = cleanNullSentinels(child.plugins)). Stamping the parent's plugin slots into the leaf made the child compose the parent's entire plugin fleet — polugins it deliberately excluded.plugins.<id>.uirecord is{production, pin}—PluginUiConfigSchema.nameis required, and the wholesale replace means the parent'snamenever fills it in → the boot-check (plugins.ai: Invalid input) correctly refused the publish.Nothing was published — the boot-check fires before the registry write. Live apps are unaffected; CI deploys are blocked for rc.26 children with authored plugins.
The fix
The stamp policy allowlists
app.*slots only (^app\.[^.]+(\.ui)?$) — the base-runtime slots children never author (app.auth,app.auth.ui,app.host), which merge per-key with the parent, so the parent'sui.nameand friends fill the stamped entries and the schema stays valid. The release manifest keeps recording every slot (a record, not a policy); the filter lives at stamp time, so no root-side action is needed.Tests
app.*; itspluginsobject stays byte-equal untouched.simulateDeploynow runsverifyResolvedBootShapeover the merged shape — the coverage that would have caught this. The incident-replay child declares its own plugin while the root release carriesplugins.*slots: stamped list is app-only,merged.pluginsequals the child's exact set, merged shape schema-valid. (The e2e fixture's live parent config also gains the requiredapp.host/app.apikeys the schema parse demands.)Full framework suite: 1692 passed. Typecheck, biome, effect-lint clean.
Residual (recorded, not hotfix material)
Children that declare no
pluginsstill inherit the parent's plugin pins live — pre-existing behavior, unchanged by this fix; the composition gate still catches their skew pre-publish. Making plugin inheritance release-scoped would require full-entry recording in the slots map — a future seam.Rollout notes for the rc.26 release body
rc.26 children that author their own
pluginsare CI-blocked untilbos upgradepicks this fix up in the next release; live apps are unaffected.