|
| 1 | +# 0049. Revisions belong to whatever controls the ReplicaSet, and the payload is renamed for it |
| 2 | + |
| 3 | +Date: 2026-08-29 |
| 4 | + |
| 5 | +Status: Accepted |
| 6 | + |
| 7 | +Amends: 0030 §1–2 |
| 8 | + |
| 9 | +Widens `deployment_revisions` to every workload that manages ReplicaSets and |
| 10 | +renames it `workload_revisions`. No new RBAC, no new field, no new payload kind. |
| 11 | + |
| 12 | +## Context |
| 13 | + |
| 14 | +ADR 0030 scoped revisions to Deployments, and at the time that was the whole of |
| 15 | +what manages ReplicaSets in a cluster this agent could see. It is not. Argo |
| 16 | +Rollouts is widely deployed, and a `Rollout` creates and scales ordinary |
| 17 | +ReplicaSets exactly as a Deployment does — the agent already lists them, already |
| 18 | +resolves their pods, and already reports `workload_kind: Rollout` (ADR 0048 §2). |
| 19 | +The only thing standing between those sets and the payload was a kind check. |
| 20 | + |
| 21 | +Measured on kind (Kubernetes 1.36.1) against Argo Rollouts v1.10.0, mid-canary |
| 22 | +with `setWeight: 25` on four replicas: |
| 23 | + |
| 24 | + payments-7bd58f4db4 rev 2 desired 1 current 1 ready 1 pause:3.10 |
| 25 | + payments-f47dc5486 rev 1 desired 3 current 3 ready 3 pause:3.9 |
| 26 | + |
| 27 | +That is the shape ADR 0030 §2 already describes — two revisions with non-zero |
| 28 | +counts is a rollout in flight, and the split is the weight it is running at. The |
| 29 | +record needs no new field to say it; it was simply never emitted. |
| 30 | + |
| 31 | +`revisionHistoryLimit` defaults to 10 on a Rollout as it does on a Deployment, |
| 32 | +so the bound ADR 0030 leaned on to keep the snapshot small holds unchanged. With |
| 33 | +the limit set to 3 the cluster retained five sets: three historical, the stable |
| 34 | +one, and the one in flight. |
| 35 | + |
| 36 | +Two things this does not reach, and both are worth stating so the widening is |
| 37 | +not read as more than it is. A `Rollout` paused at a step and a `Rollout` |
| 38 | +degraded look identical from the ReplicaSets — `status.phase` and |
| 39 | +`pauseConditions` are on the custom resource, which the agent does not read. And |
| 40 | +StatefulSets and DaemonSets are still absent: their revisions live in |
| 41 | +`controllerrevisions`, which ADR 0030 declined and this does not revisit. |
| 42 | + |
| 43 | +## Decision |
| 44 | + |
| 45 | +**1. Any ReplicaSet whose controller is a collected workload is reported**, and |
| 46 | +the kind check goes. What made a Deployment special was that the agent knew the |
| 47 | +name of its revision annotation, not anything about the object graph. Scope is |
| 48 | +still inherited from the admitted pod index, so an excluded workload is absent |
| 49 | +here exactly as before, and the namespace and pod opt-outs reach these workloads |
| 50 | +even where the workload-level one cannot (`docs/security.md` §11). |
| 51 | + |
| 52 | +**2. A ReplicaSet with no controller is not a revision.** A bare set is the |
| 53 | +workload rather than one version of one, and it has no history to report; its |
| 54 | +pods already resolve to the set itself. It is skipped rather than reported as a |
| 55 | +revision of nothing. |
| 56 | + |
| 57 | +**3. The revision number is read for Deployments and no one else.** Every |
| 58 | +controller numbers its revisions under a key of its own — |
| 59 | +`rollout.argoproj.io/revision` for Argo — and the agent reports `revision: |
| 60 | +null` for all of them rather than learning vendor keys. |
| 61 | + |
| 62 | +No finding needs the number. Deploy frequency needs the ordering, which |
| 63 | +`created_at` gives; which revision is live needs the replica counts, which ship; |
| 64 | +"this revision is that build" needs the image and the instant, which ship. A |
| 65 | +table of vendor annotation keys would be a second list to keep in step with |
| 66 | +other people's releases, bought for a field nothing reads. Records with no |
| 67 | +number sort by age, so the payload stays deterministic. |
| 68 | + |
| 69 | +**4. The kind is renamed `deployment_revisions` → `workload_revisions`**, and |
| 70 | +the spool file with it. The old name would be false the moment the first Argo |
| 71 | +record appeared, and a payload kind whose name contradicts its contents is the |
| 72 | +defect ADR 0022 exists to prevent. The rename costs a registry row, a golden and |
| 73 | +three documents today; after a backend exists it is a protocol migration. ADR |
| 74 | +0019 renamed `go_dependencies` → `go_build` on the same reasoning. |
| 75 | + |
| 76 | +## Consequences |
| 77 | + |
| 78 | +**Easier.** The regression watch — CPU per replica across an image change — now |
| 79 | +covers Argo-managed workloads, which was one of the three things such a workload |
| 80 | +lost. Deploy frequency and rollout-in-flight follow for every ReplicaSet-based |
| 81 | +controller at once, including operators nobody here has heard of, because |
| 82 | +nothing in the reduction names a vendor. |
| 83 | + |
| 84 | +**Harder / given up.** A consumer can no longer assume a revision number exists. |
| 85 | +It was already optional — an unannotated ReplicaSet yielded null before this — |
| 86 | +but it was rare, and it now happens for a whole class of workload. The backend |
| 87 | +contract states it. |
| 88 | + |
| 89 | +The payload can now carry a workload kind that is not a Kubernetes built-in, so |
| 90 | +`workload.kind` is a string from a CRD rather than from a closed set. It is a |
| 91 | +kind name, not free text, and it is already shipped in `workload_metadata` for |
| 92 | +the same workloads (ADR 0048 §2), so this exposes nothing new. |
| 93 | + |
| 94 | +**Not changed.** No new RBAC — ReplicaSets were already granted and read. No new |
| 95 | +field, no new payload kind, no change to the natural key or the delivery |
| 96 | +discipline. StatefulSet and DaemonSet revisions remain uncollected, and the |
| 97 | +custom resource itself remains unread: what this decision uses is the object the |
| 98 | +agent was already watching. |
| 99 | + |
| 100 | +This ADR records decisions implemented in the same pull request, per the process |
| 101 | +in [`README.md`](README.md). |
0 commit comments