Skip to content

feat: a workload can refuse the profiler without refusing the rest (ADR 0071) - #109

Merged
kfeofantov merged 1 commit into
mainfrom
feat/profiling-opt-out-annotation
Sep 7, 2026
Merged

kfeofantov merged 1 commit into
mainfrom
feat/profiling-opt-out-annotation

Conversation

@kfeofantov

Copy link
Copy Markdown
Contributor

The four controls in security.md §11 are one control at four scopes — do not
collect this
— so declining a ten-second capture meant giving up every rollup
and build fact about the service. A fifth control, rebuildstack.co/profile: "false", excludes profiling and nothing else.

Pulling stays on by default; ADR 0058 settled that and this does not reopen it.

The control

Read at the same three levels as the collection opt-out, in the same order, only
on "false", and on the workload object rather than its pod template. It is
decided in PodWatcher.admit from the owner-chain walk that already happens, so
no new lister, no new API read, no second traversal.

It stops both profiling paths and the endpoint confirmation with them, so the
promise is "the agent does not connect to it" with no exception to explain. Three
places read the one flag: targeting.Publisher (an excluded workload takes no
topN place), ContainersOnNode (the only source of container IDs a node's
profiler acts on), and PodAddress (the only place a pod address is read at
all). The candidate funnel is filtered too — a target confirmed before the
annotation would otherwise hold one of the ten pull slots every cycle forever.

Per pod where the path allows it; a workload leaves a ranking or a funnel only
when every indexed pod of it carries the annotation, and a workload with no pods
does not leave at all — a scale to zero is not something the customer asked for.

All five controls are refusals, so the opt-out model gains a scope rather than a
second shape. ADR 0071 §1 argues that; §3 covers the fail-open on a controller
the agent cannot read, counted by ADR 0028's existing two numbers.

Beside it

The log trail. Every pull attempt writes one line — pprof profile pull,
with namespace, workload, container, digest, seconds and outcome — so "who did
you profile, and when" is answerable inside the cluster rather than from a
payload the unbuilt transport never delivers. Bounded by the same construction
that bounds the profiling: ≤10 per cycle, ≤2880 lines a day.

The install disclosure. NOTES.txt warned about root, hostPID and an
unenforced CNI and said nothing about connecting to workloads and starting
profilers in them. It now does, rendered only where that actually runs.

Coverage. Two numbers, different subjects: filter.excluded_profiling_annotation
(pods) and pprof.excluded_by_annotation (endpoint targets). The second is a
gauge on pprof_targets, not an outcome on pprof_pulls_total: no pull is
attempted, and the number falls when an annotation is removed — which a
Prometheus counter may not do, as TestCountersAndGaugesAreTypedByWhetherTheyCanFall
would have caught.

Docs

ADR 0071, Amends: 0025, 0028, 0057, 0058 with the mirror lines. 0025 is in that
list because its Consequences stated "there is no longer a way to profile less
than what is collected", and that is what changed — by the annotation route that
ADR called additive, not by the configured list it deleted.

security.md §10.3 and §11 (four → five, and the table row); two normative
sentences in backend-requirements.md. Both prose ceilings move, for that one
obligation, which is what the diff shows.

Evidence

make test && make chart-lint && make lint

Green, and green again from a clean git archive HEAD extraction. NOTES.txt
rendered for metrics-only (silent), inventory, and pull=false.

New tests: every annotation level and value, fail-open on an unreadable
controller, collected-but-not-profiled, one opted-out replica of a profiled
workload, a workload with no pods; the funnel counting distinct targets rather
than candidates; one log line per attempt naming the workload; both metric
series with their types; the excluded top consumer taking no topN place.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KeZECJXTDHL6Nts95eKMJA

…DR 0071)

The four controls in security.md §11 are one control at four scopes — do
not collect this — so declining a ten-second capture meant giving up every
rollup and build fact about the service. A fifth control,
`rebuildstack.co/profile: "false"`, excludes profiling and nothing else.

It reads at the same three levels as the collection opt-out, in the same
order, only on "false", and on the workload object rather than its pod
template. It stops both profiling paths and the endpoint confirmation with
them, so the promise is "the agent does not connect to it" with no
exception. All five controls are refusals, so the opt-out model gains a
scope rather than a second shape.

Beside it: every pull attempt writes one line naming the workload and its
outcome, so "who did you profile, and when" is answerable inside the
cluster rather than from a payload the unbuilt transport never delivers;
and NOTES.txt discloses at install time that the agent connects to
workloads and starts profilers in them.

Coverage gains two numbers with different subjects: pods excluded from
profiling, and endpoint targets the funnel dropped. The second is a gauge
on `pprof_targets` rather than an outcome on `pprof_pulls_total` — no pull
is attempted, and the number falls when an annotation is removed, which a
counter may not do.

Both prose ceilings move, for that one obligation.

  make test && make chart-lint && make lint — green

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeZECJXTDHL6Nts95eKMJA
@kfeofantov
kfeofantov merged commit d786050 into main Sep 7, 2026
3 checks passed
@kfeofantov
kfeofantov deleted the feat/profiling-opt-out-annotation branch September 7, 2026 12:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant