docs: chapter 30, the Deliverable Set - #61
Closed
ExtraToast wants to merge 1 commit into
Closed
Conversation
Layer 3, and the rule that makes separating the other two worthwhile: a
Fragment's content is a pure function of the Resolved Deployment, and its path
is a pure function of its adapter and the object it carries. If a renderer has
to choose, the choice belongs one layer up -- because a decision taken during
serialisation appears in no schema, is recorded in no lock, and is invisible in
the projection a service owner reads back.
Two things turned out to be already solved by the implementation. A Fragment is
already {path, content, adapter}, so ADR-0016's attribution assertion needs no
new machinery. And a blueprint pack is not a special case: it is a list of
Fragments each tagged adapter: flux-packs.
CLOSES OPEN ITEM 8. ADR-0016 required each adapter to become total and recorded
the cost as unmeasured. Measured across fleet-infra/cluster, excluding the Flux
installer which contributes 32 objects of its own: 450 objects, 39 kinds, 329
files.
kind: Kustomization is two unrelated APIs and had to be split before any figure
meant anything -- 74 are kustomize file lists and 15 are Flux reconcile units.
A coverage claim conflating them is wrong by 74.
class A, derived from Service Intent 364 81%
class B, pack-delivered 41 9%
class C, authored content 45 10%
Class C is entirely Grafana: 31 dashboards and 14 folders. A dashboard is
authored content like an asset; nothing in Service Intent implies its panels,
and deriving it would mean inventing a dashboard DSL.
Of the 364 that should come from an adapter, 328 do and 36 do not. That is 8%
of the tree, not the 19% a naive count of unregistered kinds suggests. Fourteen
need only registering, because render/servicemonitor.ts and
render/networkpolicy.ts already work and were never registered as adapters.
Twenty-two need writing: rbac and podDisruptionBudget.
The PDB row strengthens a proposal chapter 10 left ungraded. A PDB is exactly
minAvailable serialised, and six already exist -- an argument for that field
beyond replica arithmetic.
Also records that the adapter set is not yet clean. Four of the sixteen
registered adapters are duplicated pairs from two generations --
traefik-public/traefik-route-fragment, gatus/gatus-endpoint-fragment,
edge-catalog/edge-catalog-fragment, image-metadata/image-metadata-fragment.
Attribution is only meaningful if one adapter owns a kind, so the pairs must
collapse before the coverage assertion can be enforced.
Names the reason coverage is not hygiene: Flux prunes, so an object the render
omits is an object deleted from the cluster on the next reconcile. That is also
why ADR-0015's participants list exists -- a domain that fails to publish does
not go stale, it gets deleted, and the render that deletes it looks valid.
Three bidirectional ledgers, each failing both on a missing entry and on a
stale one. One live drift entry marks where the limit genuinely is:
agent-gateway cannot be probed because it is a sidecar jar inside agent-runner
pods with per-runner Services created and destroyed at runtime. Some objects
are outside any declarative model, and the ledger is where they belong -- with
a reason rather than with silence.
Four open items, including one the chapter found by reading the allocator: its
gitops root is still platform/cluster/flux while fleet-infra uses cluster/flux,
and the pack Fragment paths carry the platform/ prefix -- so the allocator
appears to predate the monorepo split.
This was referenced Aug 31, 2026
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Chapter 30. Stacked on #60 → #59 → #58; each base retargets as the one below merges.
Layer 3, and the rule that makes separating the other two worthwhile:
If a renderer has to choose, the choice belongs one layer up — because a decision taken during serialisation appears in no schema, is recorded in no lock, and is invisible in the projection a Service owner reads back.
Two things the implementation had already solved
A Fragment is already
{path, content, adapter}, so ADR-0016's attribution assertion needs no new machinery. And a blueprint pack is not a special case — it is a list of Fragments, each taggedadapter: flux-packs.This closes open item 8
ADR-0016 required each adapter to become total for its subsystem and recorded the cost as unmeasured. Measured across
fleet-infra/cluster, excludingflux-system/gotk-components.yaml(the Flux installer, 32 objects of its own, rendered from nothing): 450 objects, 39 kinds, 329 files.kind: Kustomizationhad to be split first, because it is two unrelated APIs — 74 kustomize file lists and 15 Flux reconcile units. A coverage claim that conflates them is wrong by 74.flux-packs/flux-sourcefromflux-modulesat a pinned refClass C is entirely Grafana — 31 dashboards, 14 folders. Nothing in Service Intent implies a dashboard's panels; deriving it would mean inventing a dashboard DSL.
Of the 364 that should come from an adapter, 328 do and 36 do not — 8% of the tree, not the 19% a naive count of unregistered kinds suggests:
ServiceMonitor,PodMonitor,PrometheusRule,NetworkPolicyrender/servicemonitor.ts,render/networkpolicy.ts— they were simply never registered as adaptersrbac(ClusterRole,Role, and bindings),PodDisruptionBudgetSo the cheaper half of the gap is registration, not authorship.
The PDB row also strengthens a proposal chapter 10 left ungraded: a PDB is exactly
minAvailableserialised, and six already exist — an argument for that field beyond replica arithmetic.The adapter set is not yet clean
Four of the sixteen registered adapters are duplicated pairs from two generations:
traefik-public/traefik-route-fragment,gatus/gatus-endpoint-fragment,edge-catalog/edge-catalog-fragment,image-metadata/image-metadata-fragment. Attribution only means something if one adapter owns a kind, so the pairs must collapse before the coverage assertion can be enforced.Why coverage is not hygiene
Flux prunes. An object the render omits is an object deleted from the cluster on the next reconcile. That is also why ADR-0015's participants list exists — a domain that fails to publish does not go stale, it gets deleted, and the render that deletes it looks entirely valid.
One live drift entry marks where the limit genuinely is:
agent-gatewaycannot be probed because it is "a sidecar jar inside agent-runner pods, not a workload of its own", with per-runner Services created and destroyed byagents-apiat runtime. Some objects are outside any declarative model, and a bidirectional ledger is where they belong — with a reason rather than with silence.Found while reading the allocator
The path allocator's gitops root is still
platform/cluster/fluxwhilefleet-infrausescluster/flux, and the pack Fragment paths carry theplatform/prefix — so the allocator appears to predate the monorepo split. Recorded as an open item rather than fixed here.