You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
composeStacks objectConflict: 'merge' merges fields only — the later object's actions (and every other key) replace the earlier package's wholesale, silently dropping its embedded actions #14848
Found while implementing #14662 (the cross-stack action-key check in composeStacks); out of scope there and recorded here instead. Measured on main @ f3ae441fa, packages/spec/src/stack.zod.tsmergeObjects.
fields is the only key merged. Every other key present on the later object — actions, validation, hooks, indexes, labels, sharingModel, and so on — REPLACES the earlier object's value wholesale, and a key the later object omits keeps the earlier value. For the collections this is silent loss:
ConflictStrategySchema documents 'merge' as "Shallow-merge items with the same name (later fields win)", which reads as a description of fields, not as "and the earlier package's actions are discarded". Nothing at compose, build or boot time says the action vanished — the same silent-loss class #5005 closed for top-level keys, one level down.
Why it is recorded now
#14662's collision check judges what the composition CARRIES: an embedded action that 'merge' did not carry into the composed object cannot collide, so this loss is invisible to it by design (documented in collectComposedActionKeyCollisions). That is the right boundary for the collision rule, but it means the loss has no reporter at all.
Keep the shallow semantics and WARN once per dropped collection entry, the way warnMalformedCollectionKey reports a dropped key.
Keep as is and make the describe text say it plainly.
Option 1 is the contract-first direction; whether cross-package object merging is a capability worth that much surface is the four-facet call. Filing unassigned for triage.
Found while implementing #14662 (the cross-stack action-key check in
composeStacks); out of scope there and recorded here instead. Measured onmain@f3ae441fa,packages/spec/src/stack.zod.tsmergeObjects.What was measured
objectConflict: 'merge'is implemented asfieldsis the only key merged. Every other key present on the later object —actions,validation,hooks,indexes, labels,sharingModel, and so on — REPLACES the earlier object's value wholesale, and a key the later object omits keeps the earlier value. For the collections this is silent loss:ConflictStrategySchemadocuments'merge'as "Shallow-merge items with the same name (later fields win)", which reads as a description offields, not as "and the earlier package's actions are discarded". Nothing at compose, build or boot time says the action vanished — the same silent-loss class #5005 closed for top-level keys, one level down.Why it is recorded now
#14662's collision check judges what the composition CARRIES: an embedded action that
'merge'did not carry into the composed object cannot collide, so this loss is invisible to it by design (documented incollectComposedActionKeyCollisions). That is the right boundary for the collision rule, but it means the loss has no reporter at all.Options (for triage, not decided here)
'merge'merges the object-level collections by name (actionsfirst, since it is the one with a runtime key) and throws on a same-name pair — the shapecomposeFunctionsalready uses for handlers; a same-key pair then surfaces throughcomposeStacksconcatenatesactionsacross packages with no same-scope duplicate-key check — two packages each declaring oneglobal:NAMEcompose into one collapsed handler key #14662's check instead of being dropped.warnMalformedCollectionKeyreports a dropped key.Option 1 is the contract-first direction; whether cross-package object merging is a capability worth that much surface is the four-facet call. Filing unassigned for triage.
Generated by Claude Code