Skip to content

fix: make adopt a plain overlay so every layer survives - #13

Merged
mkmik merged 1 commit into
mainfrom
fix-adopt-overlay
Oct 21, 2026
Merged

mkmik merged 1 commit into
mainfrom
fix-adopt-overlay

Conversation

@mkmik

@mkmik mkmik commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Problem

k8s.adopt built a finished copy of type + upstream item and stacked it on the object. A copy holds plain values, not merges, so:

  • type-level overlays on adopted items were overwritten (e.g. PodSpec+: { containers_+: { app+: { env_+: ... } } } lost its env entries, and Container+: defaults beat per-item settings)
  • fields that read self (e.g. a pull policy derived from self.image) were computed from the upstream values and never updated
  • type asserts ran against the upstream item, before later overlays

#12 fixed overlays applied after adopt by making that copy earlier, which moved the loss to overlays applied before adopt. This PR removes the copy instead.

Change

  • adopt(o) is now typeFor(o) + adoptOverlay(o). The overlay merges upstream values in and reads the type only through super, at render time.
  • typedNamedArrays records item types in a hidden _namedArrays+::, so extending a type adds named arrays instead of replacing the built-in ones.
  • Deleted deepMapObject, adoptObject, adopterFromPartialType, adoptNamedArray.

Also fixed by the same code:

  • upstream items keep their upstream order (init containers, $(VAR) in env); overlay-added items follow
  • nested objects in items (securityContext, resources) merge with type defaults
  • items with no name, a null name or a repeated name stay in place and no longer block overlays on the rest of the array
  • null arrays (Helm's empty env:) are treated as [] instead of crashing
  • kubectl.kubernetes.io/default-container follows containers added after adopt

examples/adopt.golden changes: the side container now gets COMMON_ENV, and the pod has no default-container annotation (it has two main containers).

Not changed

An upstream item with the same name as a type-level default item is still merged onto it, not replaced. Replacing would break type-level overlays on adopted items.

Testing

just test passes. New adopt cases in tests/k8s_test.jsonnet fail on the old code.

🤖 Generated with Claude Code

adopt used to build a finished copy of `type + upstream` and stack it on
the object. A copy holds plain values, not merges, so it overwrote
type-level overlays (env_ entries, per-item settings), froze fields that
read `self`, and checked type asserts against the upstream item.

adopt(o) is now `typeFor(o) + adoptOverlay(o)`. The overlay merges the
upstream values in and reads the type only through `super` at render
time. typedNamedArrays records item types in a hidden `_namedArrays+::`,
so extending a type adds named arrays instead of replacing them.

Also:
- upstream items keep their upstream order; overlay-added items follow
- nested objects in items merge with type defaults
- unnamed, null-named and repeated-name items stay in place and no
  longer block overlays on the rest of the array
- null arrays (Helm's empty `env:`) are treated as []
- default-container annotation follows containers added after adopt

The adopt example golden changes: the sidecar now gets COMMON_ENV and
the pod has no default-container annotation (two main containers).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mkmik
mkmik merged commit 49b7f17 into main Oct 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant