Skip to content

docs(support-boundary): render fidelity + consent + reconcile-trigger + kpt (consolidated design docs)#237

Closed
sunib wants to merge 4 commits into
mainfrom
design/render-fidelity
Closed

docs(support-boundary): render fidelity + consent + reconcile-trigger + kpt (consolidated design docs)#237
sunib wants to merge 4 commits into
mainfrom
design/render-fidelity

Conversation

@sunib

@sunib sunib commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Consolidated support-boundary design docs — direction-setting, ships no code. Combines what were PRs #236 and #237 into one, since the design work belongs together and there were too many open PRs. Indexed in the folder README.

The docs

  • render-fidelity.mdour render is not the orchestrator's. We run kustomize build; Flux/Argo run kustomize plus context that isn't in the folder (Flux postBuild, Argo spec.source.kustomize overrides, their version). Records the failed structural ${...} check and why (it broke CRD mirroring — ${} is ambiguous, the discriminator isn't in the repo), and proposes the right fence: measure our render against the live object, refuse where they diverge. Two surfaces — a per-write refusal and a blocking RenderFaithful GitTarget condition you read before you edit — and a §7 on how/where to implement it (fold into the reconcile-on-acceptance).
  • admission-consent.md — turning a blast-radius refusal into a yes: the correctness-vs-policy split, consent modelled as declared WriteIntent (never a bypass), a consequence-hash token, the RBAC edge.
  • orchestrator-reconcile-trigger.md — the operator's one new outward action (ask Flux/Argo to reconcile): revert a refused edit promptly (the only revert under selfHeal: false), and an origin-drift ordering barrier. Diagrams built from bi-directional.md.
  • kpt-and-krm-functions.md — orientation note on where Kpt packages, setters, and KRM functions fit the reverse-GitOps model.

Was #236 (consent + reconcile-trigger + kpt) and #237 (render-fidelity); #236 is closed in favour of this one.

🤖 Generated with Claude Code

…strator's

Design for the context-skew fence raised in #234's review: we run `kustomize
build` on the folder, but Flux/Argo run kustomize plus context that is NOT in the
folder — Flux postBuild substitute (build.go:631), Argo spec.source.kustomize
overrides including images/replicas/patches/version (types.go:723), their kustomize
version and flags. So the live object is not what our render produces, and
sourceForm reads the difference as a user edit and corrupts the source; the oracle
shares the blind spot.

Records the failed approach and WHY, because it is the reason the right fence looks
as it does: a structural "refuse any managed doc with ${...}" acceptance check is
wrong. ${...} is ambiguous — literal and safe in CRD descriptions / KRO templates /
nginx ConfigMaps (live == our render there), dangerous only when actually
substituted (live != our render). The discriminator is not in the repo; it is in
the live object. Measured: the structural check broke CRD mirroring outright (the
Flux CRD documents postBuild with ${var:=default} in its own schema, poisoning the
folder).

Proposes the correct fence: measure our render against the live object and refuse
where they diverge. Precise (same tokens, opposite verdicts, each read off live),
per-object (no folder poisoning), on the write path (needs the live object, so not
the structure-only acceptance gate). Two shapes: 5a the precise token instance (no
false positives, build first) and 5b the general render-vs-live baseline (catches
Argo overrides and version skew too, but must first solve the runtime-drift
discriminator — managedFields is the lead).

Two mermaid diagrams (the two render paths; the fence decision). Direction-setting;
ships no code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a design document describing render fidelity between repository output and Flux/Argo-applied objects, failure modes in source-form projection, and proposed live-object write fences. Updates the support-boundary index formatting.

Changes

Render fidelity design

Layer / File(s) Summary
Render context and failure mode
docs/design/support-boundary/render-fidelity.md, docs/design/support-boundary/README.md
Documents orchestrator-specific rendering context and the resulting source-form projection failure for substituted values; updates the index entry formatting.
Structural fence replacement
docs/design/support-boundary/render-fidelity.md
Explains why structural ${...} rejection is ambiguous and proposes render-versus-live comparison for relevant fields.
Write-path integration and open questions
docs/design/support-boundary/render-fidelity.md
Defines write-path placement, interaction with existing verification, fence variants, and unresolved design questions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is useful but omits the required template sections like Type of Change, Testing, Checklist, Related Issues, and Additional Notes. Rewrite the PR description using the repo template and fill in the missing sections, especially Type of Change, Testing, Checklist, Related Issues, and Additional Notes.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the consolidated support-boundary design docs and the render-fidelity focus.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch design/render-fidelity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/design/support-boundary/render-fidelity.md`:
- Around line 204-217: Clarify the “per field, per object” wording in the
section describing the write-path fence: a single diverged token triggers one
target-level WriteBoundaryRefused, aborts the entire flush, and commits no
writes. State that the per-field check identifies the refusal trigger only and
does not introduce partial-write behavior or change per-edit accounting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 509e9b6f-c034-4e87-bffb-fff51cd6786c

📥 Commits

Reviewing files that changed from the base of the PR and between 64bebc0 and 0bacbcc.

📒 Files selected for processing (2)
  • docs/design/support-boundary/README.md
  • docs/design/support-boundary/render-fidelity.md

Comment thread docs/design/support-boundary/render-fidelity.md Outdated
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

sunib and others added 3 commits July 15, 2026 07:22
The render-vs-live measurement needs the live object, so it runs at reconcile —
which rules out only the STRUCTURE-ONLY gate, not the operator, which holds live
state on every reconcile. So the same measurement surfaces two ways: a per-write
refusal (6a), and a standing GitTarget condition (6b, RenderFaithful) that answers
'do we even have a chance of tracking this folder?' up front, before an edit is
wasted. It is the folder-level 'can we track this?' verdict the reverted structural
check was reaching for and could not have — it failed answering from the disk; the
same question answered from the live object is correct. Sibling of FullyReflected;
open question added on whether it blocks adoption or only informs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oaches

Records the decision: RenderFaithful is BLOCKING. A GitTarget is the claim that a
folder can be reverse-GitOps'd, which is void if our render is not equal to what
the cluster runs — so RenderFaithful=False gates adoption (not tracked, Ready=False),
strict first, loosen later if demand proves out.

Adds §7 Implementation — the design work on how/where to run it. One per-document
predicate (render has a ${...} token where live resolved it) computed once and read
by both surfaces (per-write refusal + folder condition). Three ways to run the
folder pass: (A) fold into the reconcile/resync that runs on acceptance — the moment
both git and live are in hand and nothing is written yet, added as a resync
precondition that aborts and sets the condition (recommended, and the shape the
user described); (B) a distinct live-aware acceptance layer (A with a cleaner seam);
(C) derive the folder verdict from accumulated per-write refusals (loses the
up-front property). We block on the TOKEN form (5a), not general render!=live (5b),
because blocking demands no runtime-drift false positive. Composes second to
GitPathAccepted; recomputable and self-healing.

Open questions renumbered §8; the block-vs-inform question is resolved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nd kpt notes here

Fold the design docs from the design/consent-and-reconcile-trigger branch (PR #236)
onto this PR so the support-boundary design work lives in one PR rather than
several: admission-consent.md, orchestrator-reconcile-trigger.md, and the
kpt-and-krm-functions orientation note, plus their README index rows. render-fidelity
joins the "Renderers & provenance" row beside the other render docs. No content
change to any doc; PR #236 is superseded and closed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sunib sunib changed the title docs(support-boundary): render fidelity — our render is not the orchestrator's docs(support-boundary): render fidelity + consent + reconcile-trigger + kpt (consolidated design docs) Jul 15, 2026
sunib added a commit that referenced this pull request Jul 15, 2026
…lementation

Bring the support-boundary design docs onto this PR — they are the design that sits
next to this real implementation, so they belong together rather than in a separate
PR: render-fidelity.md (our render is not the orchestrator's; the render-vs-live
fence, the blocking RenderFaithful condition, and where to implement it),
admission-consent.md, orchestrator-reconcile-trigger.md, and the kpt-and-krm-functions
orientation note, plus their README index rows. Consolidated from PR #237, now closed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sunib

sunib commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Consolidated into #234 — the design work now sits alongside the implementation it describes. Closing.

@sunib sunib closed this Jul 15, 2026
sunib added a commit that referenced this pull request Jul 15, 2026
…input (#234)

* fix(kustomize): stop writing the build's own output into the build's input

The writer mirrors a live object into the file that produced it. Under kustomize
that file is not what the cluster runs, and mirroring the live object straight
back writes the BUILD'S OUTPUT into the build's INPUT.

Measured, on a folder we accept today, with nothing changed in the cluster and
nothing changed in the render: a kustomization declaring `labels:` +
`commonAnnotations:` and nothing else commits the overlay's `env: prod` and
`owner: platform` into the base manifest, on the first reconcile of an unchanged
folder. Every reconcile of an in-sync folder produced a commit, and the file was
left wrong. In a base shared by two overlays, the value baked in is one
environment's.

The fix is one rule, and it models no transformer:

    WHERE THE LIVE OBJECT AND THE RENDER AGREE, THE SOURCE KEEPS ITS BYTES.
    WHERE THEY DISAGREE, THE USER CHANGED SOMETHING, AND THAT IS WHAT WE WRITE.

Agreement means the build already produces exactly what the cluster runs, so the
source is — by construction — what produced it, and there is nothing to write.
Disagreement is the user's edit: it is routed to an images:/replicas: entry when
the dye says one supplies the field, and written through to the source otherwise
— where, if the build owns the field, the re-render refuses the flush.

Because it needs no model of labels, of namespace, or of a patch, it closes all
of them at once. It is also the gate on tolerating `patches:` at all: a patched
base would otherwise absorb one environment's values, and no re-render can catch
that (the patch re-imposes its value, so the render comes out identical).

Two behavior changes go with it:

  - the re-render now runs for ANY document a render root produces, not only one
    an override chain governs. A change to a build-supplied field in a folder
    with no images:/replicas: entries used to be committed and silently never
    converge; it is now a reported refusal.
  - a live change the projection cannot place is refused (`unplaceable-edit`):
    the build and the user both rewrote one list whose elements carry no unique
    `name:` to pair them by. Pairing by position is not a conservative guess, it
    is measurably wrong — kustomize PREPENDS a container a patch adds.

The corpus no-op invariant now compares the WHOLE document, not just its images,
which is how a projection that quietly rewrote every field we had not modelled
passed it for as long as it did: 8 documents checked before, 53 now.

* docs(kustomize): address review on #234 -- finish the refusal sentence, fix the vars contradiction

The SourceFormRefusedError message (surfaced to the user via WriteBoundaryRefused)
and its IssueUnplaceableEdit doc comment both cut off mid-clause; complete them.
And §2's vars bullet claimed the folder is accepted today while a parenthetical
said it now refuses -- rewrite the passage in past tense (both leaks it cites are
now closed, by #229 and by sourceForm).

* docs(support-boundary): design work alongside the render-fidelity implementation

Bring the support-boundary design docs onto this PR — they are the design that sits
next to this real implementation, so they belong together rather than in a separate
PR: render-fidelity.md (our render is not the orchestrator's; the render-vs-live
fence, the blocking RenderFaithful condition, and where to implement it),
admission-consent.md, orchestrator-reconcile-trigger.md, and the kpt-and-krm-functions
orientation note, plus their README index rows. Consolidated from PR #237, now closed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(render-fidelity): rename the condition RenderFaithful -> RenderMatchesLive

RenderMatchesLive names what it measures directly — does our render match the live
object — better than the 'faithful' framing. The negative reason follows:
RenderNotFaithful -> RenderDoesNotMatchLive, and the gate AcceptRenderFaithful ->
AcceptRenderMatchesLive.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(render-fidelity): conform to the decisions, and add the implementation prompt

Align the prose to the RenderMatchesLive framing (the "faithful/unfaithful"
language follows the rename to "matches / diverges"), and mark §8's 5a-first as
decided rather than open. Add next-prompt-render-matches-live-gate.md: a handoff
for a fresh session to implement the token gate — the design, the code entry points
(patchExisting + the resync path), the CRD lesson (measure render-vs-live, not the
disk; the reverted structural check broke CRD mirroring), the test net, and the
e2e-tail gotcha.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(render-fidelity): the predicate is render-vs-live, not git-vs-live

Incorporate the review findings:

- The predicate must compare the RENDER to live, not the Git source to live.
  kustomize does not RESOLVE ${...}, but it does not PRESERVE every token-bearing
  source field either: a supported labels/commonLabels transform overwrites
  metadata.labels[...] via SetEntry, so `env: ${ENV}` under `labels: {env: prod}`
  renders to `prod` == live. Git-vs-live would falsely refuse that faithful folder.
  The render is dm.Rendered.Object for a kustomize doc, the Git doc for a plain one,
  and reading the render also catches a token a patches: block injects. Fixed the
  prompt (which had the git-vs-live shortcut + "does not need dm.Rendered") and §5a.

- Narrow the causal claim in the fact doc and the design: a rendered token that
  differs from live proves only that our render did not produce the value — could be
  Flux substitution, a live edit, admission, another controller. Refusal is safe
  regardless; RenderDoesNotMatchLive is a fact, "must have been substituted" a guess.

- State the two integration requirements for the blocking gate: aggregate fidelity
  across ALL scoped resyncs (a last-successful-GVR status masks a diverging type),
  and stop opening write windows while failed (status-only refusal isn't a gate).

- Record the bias: blocking a shade too soon is fine; failing to block is not. The
  simple token gate is the right first cut.

Also fixes the fact doc's external-sources markdown links (doccheck treats upstream
checkouts as untracked) to code spans, matching the convention in the sibling docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: define render fidelity gate

* feat: gate writes on render fidelity

* docs: clarify reconcile trigger barrier

* fix: getting the bidirectional e2e test to work again

* test: last extra checks to see if all behaves as expected

* docs: last edits

* docs: feedback of codex

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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