let an artifact say who owns it instead of inferring it from its kinds - #83
Merged
Conversation
… kinds Three defects from the same external review, all reproduced before the change and all rooted in guessing. Attribution was a kind only one renderer emits. A ResourceClaimTemplate is not one: both write it, so the standalone `-scheduler-fallback.yaml` holds nothing that decides, was a subset of both sets, and belonged to neither. Turning --dra-fallback off left the previous generation in the desired-state directory for good -- and it was not reported as unattributable either, so nothing said so. Every document names its writer now, and the renderer that wrote it takes it back while the other still does not touch it. Ownership was a mission fingerprint. The priority-class bundle has none: it is cluster-scoped, one set per installation, which is what --priority-class-prefix keeps from colliding. Two bundles both answering "no mission" is how the ownership check compared `None` with `None` and let a second installation replace the first's class set, silently, while the Jobs naming those classes stayed where they were. The prefix is the installation, so that is the owner the bundle carries, and a cross-owner replacement is refused. And a mission-scoped --prune deleted that bundle outright. A single invocation does not hold the installation's desired set, so it cannot tell a class nobody needs any more from one another mission's Jobs still reference. It leaves them now and says it did, with --prune-global as the opt-in for the installation that owns them. A bundle belonging to someone else is named and left whatever the run was asked to do. So every document carries renderer, owner-scope, artifact-role and a schema version, with the owner's own name in an annotation beside the fingerprint -- 64 bits of a digest should not decide a delete by itself. Every document in one file has to agree on that tuple: an operator concatenating two renders into one bundle produces a file that answers for nobody, and it is not deleted on either writer's say-so. An artifact carrying no schema at all predates this and is reported rather than acted on. Adopting it would mean guessing again; re-rendering adopts it properly. Mutations: attributing by kind again, dropping the installation comparison in preflight, giving the bundle mission scope, letting an ordinary prune take it, letting another installation take it, and letting a file's documents disagree. The last one was not caught at first -- the agreement rule had no test -- which is why there are three now. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
This was referenced Aug 3, 2026
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.
Why
Three findings from the review of #81, all reproduced against its head before anything changed here. They are one problem: the compiler was inferring ownership from things that cannot express it.
Attribution was a kind only one renderer emits. A
ResourceClaimTemplateis not one — both write it — so the standalone*-scheduler-fallback.yamlholds nothing that decides. It was a subset of both sets, belonged to neither, and turning--dra-fallbackoff left the previous generation in the desired-state directory permanently. Measured: after--prune, the file is still there andstale_unattributableis absent, so nothing tells the operator either.Ownership was a mission fingerprint. The priority-class bundle has none: it is cluster-scoped, one set per installation, which is what
--priority-class-prefixexists to keep from colliding. Two bundles both answering "no mission" is how the ownership check comparedNonewithNoneand let a second installation replace the first's class set. Measured:team-a-class names gone, no warning, and the Jobs referencing them untouched.A mission-scoped
--prunedeleted that bundle outright. One invocation does not hold the installation's desired set, so it cannot tell a class nobody needs from one another mission's Jobs still reference. A warning after the fact is not ownership.What
Every document carries
orbital/renderer,orbital/owner-scope,orbital/artifact-roleandorbital/ownership-schema, with the owner's own name inorbital/owner-idbeside the fingerprint — 64 bits of a digest should not decide a delete by itself.The bundle's owner is the prefix, because that is what makes one installation's classes distinct from another's in a cluster. A cross-owner replacement is refused; the same installation replacing its own is not.
Ordinary
--prunemanages mission scope.--prune-globalis the opt-in for cluster-scoped artifacts, and only for the installation that wrote them. Either way they are named in the report and on stderr, because leaving them silently is how an operator finds out by having a workload fail admission.Every document in one file has to agree on that tuple. An operator concatenating two renders into one bundle for
kubectl apply -fproduces a file that answers for nobody, and it is not deleted on either writer's say-so.An artifact carrying no schema label predates this and is reported rather than acted on. Adopting it would mean guessing again; re-rendering adopts it properly. That is a deliberate behaviour change for a directory written by an older version, and it fails closed.
Verification
Written as failing tests first, then each guarantee checked against a mutation: attributing by kind again, dropping the installation comparison in preflight, giving the bundle mission scope, letting an ordinary prune take it, letting another installation take it, and letting a file's documents disagree.
The last one was not caught. The agreement rule had no test at all, which is why there are three now — and re-running that mutation fails all three.
The three original reproductions were re-run end to end: the second prefix now exits 2 with
team-a-intact, the scheduler fallback is retired by its own renderer and not by the other, and a second mission's--pruneleaves the bundle and says why.1001 pytest passed, 1 skipped.
ruffclean,mypyclean, 15 goldens pass.Depends on #82
Third in the stack: #81, then #82, then this. It rewrites the ownership model #81 introduced, so reviewing them apart would mean resolving that overlap at merge time.