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' — a fixed-shape config object (enable, access, protection, tenancy, lifecycle, userActions, publicSharing, external) the later object declares still replaces the earlier one wholesale (residue of the #14848 collection-only ruling) #16075
Found while implementing #14848 (the objectConflict: 'merge' collection refusal); out of scope there by the ruling's own boundary and recorded here instead. Measured on origin/main @ c463d03e0, packages/spec/src/stack.zod.tsmergeObjects.
What was measured
The #14848 ruling (comment 5542636547, option 4) narrows objectConflict: 'merge' for object-level COLLECTIONS only: every key of ObjectSchema whose declared type is an array or a record (actions, indexes, listViews, validations, ... — fields excepted) is refused when both objects declare it with different values. The PR landing it derives that set from the shape and states, in the docblock, that everything else keeps later-wins.
"Everything else" includes eight FIXED-SHAPE CONFIG OBJECTS on ObjectSchema (measured over ObjectSchema.shape, wrapper-stripped type object): enable, access, protection, tenancy, lifecycle, userActions, publicSharing, external. Under 'merge' a later object that declares one replaces the earlier declaration wholesale — member by member gone — with nothing said:
For access (ADR-0066 D2 exposure posture) and protection this is the security-downgrade shape composeSingleValue refuses at the top level for api / server: an add-on package switches off a core package's posture by declaring its own.
Why it is recorded separately
The ruling's text and its four-facet analysis speak of collections ("actions, validation, hooks, indexes, ..."), and the dispatch clause for the fix says explicitly that scalars and labels stay later-wins — "the ruling narrows collections only". A config object is neither a collection of authored entries nor a scalar; treating it as a collection would widen the ruling, treating it as a scalar leaves the loss. The fix keeps to the ruling and names the boundary in the docblock; whether the boundary should move is a decision, not an implementation detail.
Reach
Zero non-test call sites pass objectConflict in this tree (measured for #14848 over packages/**, examples/**, apps/**); the default 'error' refuses the pair outright. Reachable only by an author who opts into 'merge'.
Found while implementing #14848 (the
objectConflict: 'merge'collection refusal); out of scope there by the ruling's own boundary and recorded here instead. Measured onorigin/main@c463d03e0,packages/spec/src/stack.zod.tsmergeObjects.What was measured
The #14848 ruling (comment 5542636547, option 4) narrows
objectConflict: 'merge'for object-level COLLECTIONS only: every key ofObjectSchemawhose declared type is an array or a record (actions,indexes,listViews,validations, ... —fieldsexcepted) is refused when both objects declare it with different values. The PR landing it derives that set from the shape and states, in the docblock, that everything else keeps later-wins."Everything else" includes eight FIXED-SHAPE CONFIG OBJECTS on
ObjectSchema(measured overObjectSchema.shape, wrapper-stripped typeobject):enable,access,protection,tenancy,lifecycle,userActions,publicSharing,external. Under'merge'a later object that declares one replaces the earlier declaration wholesale — member by member gone — with nothing said:For
access(ADR-0066 D2 exposure posture) andprotectionthis is the security-downgrade shapecomposeSingleValuerefuses at the top level forapi/server: an add-on package switches off a core package's posture by declaring its own.Why it is recorded separately
The ruling's text and its four-facet analysis speak of collections ("actions, validation, hooks, indexes, ..."), and the dispatch clause for the fix says explicitly that scalars and labels stay later-wins — "the ruling narrows collections only". A config object is neither a collection of authored entries nor a scalar; treating it as a collection would widen the ruling, treating it as a scalar leaves the loss. The fix keeps to the ruling and names the boundary in the docblock; whether the boundary should move is a decision, not an implementation detail.
Reach
Zero non-test call sites pass
objectConflictin this tree (measured for #14848 overpackages/**,examples/**,apps/**); the default'error'refuses the pair outright. Reachable only by an author who opts into'merge'.Options (for triage, not decided here)
objecttypes too;fieldsstays the one merge). Same message shape, same identical-passes reading.'merge'describe text (the 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 PR already says it for scalars and config objects).Filing unassigned for triage.
Generated by Claude Code