Skip to content

[FEATURE] A layout is the declared thing, not a path: GitTarget.spec.layout #293

Description

@sunib

What

Replace the placement path template as the thing a user declares with a declared layout: what the
folder is. GitTarget.spec.layout, a discriminated union on kind
(Auto | Kustomize | Tree | Flat | Template), plus byType overrides that stay valid under every
kind.

Full design, with seven worked examples and a mechanical migration for every current configuration:
docs/design/gittarget-layout-model.md.

Why

Placement today is a ladder of four rungs, three of which are path templates and one of which is not
(byTypedefault → the folder's one kustomize root → canonical). Every open placement question
traces to that one mismatch:

  • a CRD default for placement.default cannot be added, because a non-empty template consumes the
    slot in front of the rung that is not a template;
  • byType: {v1/configmaps: "configmaps/{name}.yaml"} in a kustomize folder produces a file no
    kustomization lists, so it is committed and never rendered (see the sibling issue on placement
    correctness) — one line of user config;
  • placement.default on a kustomize folder does the same thing to every type at once;
  • nothing in the model can create structure, so a repository that needs a kustomization.yaml
    before it can render cannot be bootstrapped by the thing that writes into it.

A path template cannot express "beside this folder's one kustomization", cannot be read at a glance,
and cannot bring a folder into existence.

The two rules that carry the value

  • Whatever chose the path, the file is registered with the kustomization that governs it. That
    makes the unrendered-file bug unstatable rather than fixed.
  • A structural kind excludes a blanket default, so a declared template can no longer silently
    disable the render root.

kind: Auto is a safe CRD default precisely because it names the structural rule instead of
standing in front of it. It is declared inference, which is a different thing from the undeclared
sibling inference that was deleted in #291.

Scope notes

  • Breaking (feat(api)! on GitTarget), and cheaper as part of the API wave than alone. See the
    wave issue.
  • The layout is immutable except a widening transition: GitTarget has no finalizer, so recreating
    one re-adopts every document by identity.
  • It carries the namespace half too: scope: SingleNamespace|MultiNamespace is a structural claim
    that must agree with the authorization bound allowedSourceNamespaces, and writeNamespace: FromContext|Always|Never replaces the inference that decides whether metadata.namespace is
    written — the one inference an empty folder cannot perform.
  • Deliberately not its own CRD: a shared object changing where N folders write, with nothing on
    the GitTarget recording it, is the same defect as sibling inference with a different actor.

Open

Whether scope should be derived and materialized at creation instead of declared.

Not in 0.41.0

Deliberately postponed. 0.41.0 is already a large breaking release (the whole attribution fact-stream
model plus the placement break), and this is the start of a separate wave.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions