config upgrade and config refresh no longer silently drop user-authored config data. Fixes the 2026-04-19 HIGH-severity config-data-loss regression.
Fixed
massu config upgrade— top-level keys not in the built-in preservation list are now passed through verbatim via the newcopyUnknownKeyshelper inpackages/core/src/detect/passthrough.ts. Nested subkeys inside theframework,paths,project, andpythonblocks are now passed through viapreserveNestedSubkeyswhen the migrator rebuilds those blocks.massu config refresh—mergeRefreshrewritten to preserve: (1) top-level user keys not handled by the detector, (2) user subkeys insideframework/paths/project, (3)toolPrefix(previously silently reset to'massu'), (4) user-setproject.root(previously silently reset to'auto'), (5) user-authored aliases insidepaths.aliases(2-level-nested — previously overwritten by detector's hardcoded{'@': <source>}), (6) customverification.<lang>sections and user command overrides on shared languages (2-level-nested — previously silently replaced by detector-only verification output).
Impact — what was happening on 1.1.0
- Top-level: on
@massu/core@1.1.0, the keys PRESERVED duringconfig upgradewere exactly this set:{rules, domains, canonical_paths, verification_types, detection, accessScopes, knownMismatches, dbAccessPattern, analytics, governance, security, team, regression, cloud, conventions, autoLearning}— plusschema_version,project,framework,paths,toolPrefix,verification, andpythonvia dedicated code paths. ANY OTHER top-level key in your v1 config was DROPPED — if your config had something likeservices,workflow,north_stars, or any other custom top-level section, it is gone from the upgraded file. Restore fromgit log. - Nested: on
@massu/core@1.1.0, subkeys PRESERVED inside each rebuilt block were exactly:framework→{type, router, orm, ui, primary, languages};paths→{source, aliases, routers, routerRoot, pages, middleware, schema, components, hooks};project→{name, root}. ANY OTHER subkey inside those blocks was DROPPED — for example,project.description, customframework.<lang>blocks, or custompaths.<name>entries. Restore fromgit log.
Restoration instructions
Added
packages/core/src/detect/passthrough.ts— new module exportingcopyUnknownKeys(source, target, handledKeys)andpreserveNestedSubkeys(sourceBlock, targetBlock). Target-wins semantics documented in JSDoc. Shared bymigrate.tsandconfig-refresh.tsto prevent the two-allow-lists-drifting-apart class of bug that caused this incident.- 26 new tests covering top-level passthrough, nested passthrough across
framework/paths/project/python, refresh-sidemergeRefreshpreservation (toolPrefix,project.root, nested subkeys, 2-level-nestedpaths.aliasesandverification.<lang>user overrides), loose-v1-input coercion (non-object framework/paths/project/python), a sentinel-injection property-style regression guard that fails if a future rebuild block omits passthrough, and a new regression fixture that reproduces the exact 12-top-level-key shape the incident dropped data from. Total suite: 1357 tests passing.
Shipped
- Merged via PR #1 (commit
94e6723; merge commitbfa8686). Published to npm on 2026-04-20 withgitHead: bfa8686. P5-007 post-publish regression against 5 downstream consumer repos: zero key removals at any depth.