You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The legibility residue of #291. The sibling-inference deletion shipped, and so did the counters that
say where every new file landed (placements_total{source, disposition, gittarget_namespace, gittarget_name, group, version, resource}, placement_refusals_total{reason}, placement_kustomization_entries_total{outcome}). What is still missing is the durable half:
a metric says a fall-back happened, and nothing says what the operator understood about the folder.
Shapes, with five worked examples (greenfield, kustomize overlay, brownfield missing one rule, two
ambiguous roots, a refusal from an operator-configured sensitive type): docs/design/placement-visibility-and-declared-defaults.md.
Contents
GitTarget.status.layout (config surface B2). Highest value per line of code in the
config-surface doc, and more so after the deletion. An epoch-scoped per-target roll-up marked
from the write path over the existing MarkTargetRetention seam, which already enqueues on
change — that retires the "the data plane cannot notify the GitTarget" objection. It should carry
the per-target record of which types resolved by declaration and which fell back. ambiguousDocuments in particular is a correctness-relevant fallback that is currently a
debug-level store diagnostic.
renderRootReason: Ambiguous. Two supported kustomizations under one GitTarget produce a
file that is unreachable and uncounted today. Publish the signal as its own series rather than
as a third outcome on a counter that counts entry attempts. The refuse-or-write policy belongs
to [FEATURE] A layout is the declared thing, not a path: GitTarget.spec.layout #293.
Split source="declared" into byType and default, keep canonical. Today a byType hit
and a default hit are one series, so a catch-all quietly swallowing a type you meant to name
explicitly looks identical to a rule working as intended. For a metric whose job is "is a rule
missing?", that is the wrong place to lose resolution.
Unify the prose on "canonical". architecture.md still calls the built-in path "the built-in
default" while the CRD comment calls it "the built-in canonical path", and placement.default is
a user declaration. One name, one meaning.
{kindLower}, plus the single-namespace recipe and its identity caveat in configuration.md. A toLower function syntax would be a language; one variable answers the
actual need.
Express the canonical path as a template constant rendered through RenderPlacementTemplate,
pinned byte-for-byte against ResourceIdentifier.ToGitPath() across cluster-scoped, core,
grouped and sensitive identities. Removes the hand-written canonicalPath duplication.
The Event question, still undecided
Whether a fall-back to canonical also raises a corev1.Event on the GitTarget. The split argued in
the design docs is: an Event for timeliness, status.layout for durability, because an Event is
deduplicated and expires (--event-ttl defaults to 1h) while a status field is what someone reads a day
later and the only one of the two a kubectl get -o yaml in a bug report contains.
Two facts constrain it: LocateNew runs on the branch worker with no reconcile context, so the write
path has to hand the fact back rather than emit it (the pathRefusal → GitPathAccepted=False
projection is that seam); and that seam does not enqueue the GitTarget, so it surfaces on the next
requeue, up to ten minutes later — good enough for a durable condition, weak for a notification.
The metric now carries the actionable part in the meantime: one placements_total{source="canonical"}
series names the target and the exact byType key that is missing.
Relationship to the layout model
status.layout wants #293's vocabulary (declaredKind beside the resolved kind, renderRoot), and #294 makes it do double duty as the Observe-mode dry run. So it is worth doing with the wave rather
than inventing a status shape twice. The metric-value split, {kindLower} and the template constant do
not depend on either and can land any time.
The legibility residue of #291. The sibling-inference deletion shipped, and so did the counters that
say where every new file landed (
placements_total{source, disposition, gittarget_namespace, gittarget_name, group, version, resource},placement_refusals_total{reason},placement_kustomization_entries_total{outcome}). What is still missing is the durable half:a metric says a fall-back happened, and nothing says what the operator understood about the folder.
Shapes, with five worked examples (greenfield, kustomize overlay, brownfield missing one rule, two
ambiguous roots, a refusal from an operator-configured sensitive type):
docs/design/placement-visibility-and-declared-defaults.md.Contents
GitTarget.status.layout(config surface B2). Highest value per line of code in theconfig-surface doc, and more so after the deletion. An epoch-scoped per-target roll-up marked
from the write path over the existing
MarkTargetRetentionseam, which already enqueues onchange — that retires the "the data plane cannot notify the GitTarget" objection. It should carry
the per-target record of which types resolved by declaration and which fell back.
ambiguousDocumentsin particular is a correctness-relevant fallback that is currently adebug-level store diagnostic.
renderRootReason: Ambiguous. Two supported kustomizations under one GitTarget produce afile that is unreachable and uncounted today. Publish the signal as its own series rather than
as a third outcome on a counter that counts entry attempts. The refuse-or-write policy belongs
to [FEATURE] A layout is the declared thing, not a path: GitTarget.spec.layout #293.
source="declared"intobyTypeanddefault, keepcanonical. Today abyTypehitand a
defaulthit are one series, so a catch-all quietly swallowing a type you meant to nameexplicitly looks identical to a rule working as intended. For a metric whose job is "is a rule
missing?", that is the wrong place to lose resolution.
architecture.mdstill calls the built-in path "the built-indefault" while the CRD comment calls it "the built-in canonical path", and
placement.defaultisa user declaration. One name, one meaning.
{kindLower}, plus the single-namespace recipe and its identity caveat inconfiguration.md. AtoLowerfunction syntax would be a language; one variable answers theactual need.
RenderPlacementTemplate,pinned byte-for-byte against
ResourceIdentifier.ToGitPath()across cluster-scoped, core,grouped and sensitive identities. Removes the hand-written
canonicalPathduplication.The Event question, still undecided
Whether a fall-back to canonical also raises a
corev1.Eventon the GitTarget. The split argued inthe design docs is: an Event for timeliness,
status.layoutfor durability, because an Event isdeduplicated and expires (
--event-ttldefaults to 1h) while a status field is what someone reads a daylater and the only one of the two a
kubectl get -o yamlin a bug report contains.Two facts constrain it:
LocateNewruns on the branch worker with no reconcile context, so the writepath has to hand the fact back rather than emit it (the
pathRefusal→GitPathAccepted=Falseprojection is that seam); and that seam does not enqueue the GitTarget, so it surfaces on the next
requeue, up to ten minutes later — good enough for a durable condition, weak for a notification.
The metric now carries the actionable part in the meantime: one
placements_total{source="canonical"}series names the target and the exact
byTypekey that is missing.Relationship to the layout model
status.layoutwants #293's vocabulary (declaredKindbeside the resolvedkind,renderRoot), and#294 makes it do double duty as the
Observe-mode dry run. So it is worth doing with the wave ratherthan inventing a status shape twice. The metric-value split,
{kindLower}and the template constant donot depend on either and can land any time.