Skip to content

feat(fieldmap): tier-3 HelmRelease values field maps - #34

Merged
Ca-moes merged 5 commits into
mainfrom
feat/tier-3-helmrelease-fieldmaps
Jul 1, 2026
Merged

feat(fieldmap): tier-3 HelmRelease values field maps#34
Ca-moes merged 5 commits into
mainfrom
feat/tier-3-helmrelease-fieldmaps

Conversation

@Ca-moes

@Ca-moes Ca-moes commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Closes #6.

Tier-3 completes the three-tier headline: right-size Flux HelmRelease values:, on the same machinery as tiers 1–2 (the FieldMapper interface, the path-addressed ApplyPaths editor, the translate-before-group pattern, and the golden harness).

The problem

The recommender reports the Helm-generated workload (e.g. the Deployment ingress-nginx-controller), but the repo holds the HelmRelease. A chart keeps its resources at a chart-specific path under spec.values (spec.values.resources, or nested like spec.values.controller.resources). Every HelmRelease shares one (group, kind), so the tier-2 (group,kind) key doesn't fit — the discriminator is the chart name (spec.chart.spec.chart).

What's here

  • Chart-keyed config (helmReleaseMaps): ChartConfig/ChartMap/ChartComponent, mirroring the tier-2 registry but keyed by chart. Multi-workload charts use components, each carrying its own match rule (each component is a separate generated workload with a distinct name).
  • Tier3 mapper: Supports/ResolvePath/Resolve — keys on the manifest's chart, resolves the spec.values…resources cell, verifies the parent exists (never fabricates nesting), reuses resolveWant/sortEdits.
  • TranslateHelmTarget: rewrites the generated workload → {HelmRelease, release, component} so discovery finds the release and a chart's workloads collapse onto one PR. Shares matchWorkload/recoverName with tier-2 (extracted in the first commit).
  • Built-in catalog (best-effort, // TODO verify, folded into chore: capture real krr -f json samples; verify tier-2 built-in match rules #33): keycloakx (single) and ingress-nginx (multi-component controller/defaultBackend). A wrong match rule degrades safely — the workload falls back to tier-1, or the rewritten release isn't found and reverts.
  • Wiring: registered Tier2, Tier3, Tier1; helmReleaseMaps validated alongside fieldMaps.

Scope / non-goals (v0.1)

Verification

  • go test ./... green (145 tests); tier-1/tier-2 golden suites unchanged (the shared-helper refactor is byte-stable).
  • New byte-exact goldens for HelmRelease edits (multi-component + create), comment/order/anchor preserving.
  • Real CLI dry-run over an ingress-nginx + keycloakx repo produces the expected surgical spec.values… diffs end-to-end (adapter → translate → discover → fieldmap → policy → yamledit), no cluster/creds.
  • docs-framework validate docs/ passes.

Commits (one concern each)

  1. refactor(fieldmap): extract shared matchWorkload/recoverName
  2. feat(fieldmap): chart-keyed config + built-in catalog
  3. feat(fieldmap): tier-3 mapper + golden fixtures
  4. feat(fieldmap): HelmRelease translation + run wiring
  5. docs(explanation): tier-3 architecture + config example

🤖 Generated with Claude Code

Ca-moes and others added 5 commits July 1, 2026 19:19
…pers

Pull the match-rule gating and name recovery out of TranslateTarget into
matchWorkload and recoverName, both keyed on a MatchRule + cached regexp
rather than a *CRMap. Tier-3 HelmRelease translation will share the same
two helpers, so the gating (workloadKind, containerToComponent) and the
NamePattern/NameSuffix recovery stay in one place across tiers.

Pure refactor: no behavior change. Existing tier-2 translate tests and the
tier-1/tier-2 golden suites prove the output is byte-identical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add ChartConfig/ChartMap/ChartComponent — the tier-3 registry, keyed by
chart name (spec.chart.spec.chart) rather than tier-2's (group, kind),
because every Flux HelmRelease shares one apiVersion+kind and the chart is
the real discriminator. Resources live at an absolute path under
spec.values (spec.values.resources, or nested like
spec.values.controller.resources).

Multi-workload charts use Components, each carrying its OWN Match: unlike a
tier-2 Component, each is a separate generated workload with a distinct
name, so its rule recovers the shared release name and identifies the
component. Validate/findChartMap/MergedChartMaps mirror the tier-2
equivalents (user maps win, built-ins fill gaps, NamePatterns precompiled).

Built-in catalog (keycloakx single-workload, ingress-nginx multi-workload)
ships best-effort match rules marked // TODO verify (#33): Helm's generated
names depend on release name and fullname overrides, so a wrong rule
degrades safely to a tier-1 fallback or a not-found revert.

Extract validateNamePattern from MapConfig.Validate so both the tier-2 and
tier-3 config validators share one MatchRule pattern check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tier3 implements FieldMapper for Flux HelmReleases: Supports matches a
HelmRelease whose spec.chart.spec.chart has a chart map; ResolvePath keys
on that chart, selects the component (single ResourcePath or a named
Component), verifies the resources block's parent exists under spec.values,
and returns the absolute cell path. chartRef-only releases (no inline chart
name) and unmapped charts cleanly report unsupported.

Add byte-exact golden fixtures proving the path-addressed editor edits
nested values surgically: helmrelease_ingress (multi-component controller +
defaultBackend, CPU-limit delete with cascade) and helmrelease_create
(create a resources block under an existing controller). Comments and
unrelated values keys survive. No editor code change — absolute
spec.values paths flow through ApplyPaths exactly like tier-2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add TranslateHelmTarget: it rewrites a Helm-generated workload (e.g. the
Deployment "ingress-nginx-controller") to the owning Flux HelmRelease
identity, reusing matchWorkload/recoverName. Single-workload charts match
on the top-level rule; multi-workload charts try each component's own rule,
so the controller and defaultBackend of one release recover the same name
and their own component.

Wire it through the run loop: Runner gains ChartMaps; translateTargets now
tries tier-2 CR translation then tier-3 Helm translation, each committed
only when the owning resource exists in the repo (crResolvable), so a
coincidental name match still falls back to tier-1. Register the Tier3
mapper (Tier2, Tier3, Tier1) and add a helmReleaseMaps config section
(validated alongside fieldMaps).

Integration tests prove the full chain end-to-end: a generated controller
Deployment right-sizes the HelmRelease's spec.values, and a controller +
defaultBackend pair collapses into a single PR editing one file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update the tier-3 line to reflect the shipped config-driven per-chart maps
(helmReleaseMaps) with keycloakx/ingress-nginx built-ins and the inline
spec.values-only scope. Add a compact chart-map config example, and
broaden the operator-CR translation note into a workload-to-source note
that also covers HelmReleases (chart-generated Deployment -> HelmRelease,
per-component match rules, chart-keyed values subtree).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Ca-moes
Ca-moes merged commit 96760e0 into main Jul 1, 2026
3 checks passed
@Ca-moes
Ca-moes deleted the feat/tier-3-helmrelease-fieldmaps branch July 1, 2026 18:57
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.

feat(fieldmap): tier-3 HelmRelease values + catalog

1 participant