Skip to content

docs: chapter 30, the Deliverable Set - #61

Closed
ExtraToast wants to merge 1 commit into
docs/ch20-resolved-deploymentfrom
docs/ch30-deliverables
Closed

docs: chapter 30, the Deliverable Set#61
ExtraToast wants to merge 1 commit into
docs/ch20-resolved-deploymentfrom
docs/ch30-deliverables

Conversation

@ExtraToast

Copy link
Copy Markdown
Contributor

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:

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 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 tagged adapter: 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, excluding flux-system/gotk-components.yaml (the Flux installer, 32 objects of its own, rendered from nothing): 450 objects, 39 kinds, 329 files.

kind: Kustomization had 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.

class objects share produced by
A — derived from Service Intent 364 81% an adapter, per Service
B — pack-delivered 41 9% flux-packs/flux-source from flux-modules at a pinned ref
C — authored content 45 10% not derivable

Class 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:

gap objects state
ServiceMonitor, PodMonitor, PrometheusRule, NetworkPolicy 14 renderers already workrender/servicemonitor.ts, render/networkpolicy.ts — they were simply never registered as adapters
rbac (ClusterRole, Role, and bindings), PodDisruptionBudget 22 no adapter, no renderer

So 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 minAvailable serialised, 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-gateway cannot 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 by agents-api at 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/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. Recorded as an open item rather than fixed here.

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.
@ExtraToast ExtraToast added type: docs Documentation-only change. area: deploy homelab-deploy, deploy-v2, manifests, and rollout flow. component: config Configuration schema, defaults, or repo settings. labels Aug 31, 2026
@ExtraToast

Copy link
Copy Markdown
Contributor Author

Superseded by #64, which landed chapters 20-60 together. The stack could not be rebased after #58 and #59 squash-merged: each branch was cut from the pre-squash tip of the one below. Kept open until now as the per-chapter review record.

@ExtraToast ExtraToast closed this Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: deploy homelab-deploy, deploy-v2, manifests, and rollout flow. component: config Configuration schema, defaults, or repo settings. type: docs Documentation-only change.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant