Skip to content

feat: a window says what changed (ADR 0089) - #133

Merged
kfeofantov merged 1 commit into
mainfrom
feat/a-window-says-what-changed
Sep 19, 2026
Merged

kfeofantov merged 1 commit into
mainfrom
feat/a-window-says-what-changed

Conversation

@kfeofantov

Copy link
Copy Markdown
Contributor

The half ADR 0088 named and left. Completes the "when" work.

The gap

Every counter in collection_coverage is cumulative from since:

filter.excluded_namespace_annotation: 12

A namespace annotated an hour ago and one annotated three weeks ago produce the
same twelve. When a customer's data stops arriving for a workload, the counter
that explains it cannot say whether the explanation is today's.

Differencing successive payloads does not rescue it: the kind supersedes, so a
history is something the backend was never asked to keep; a restart moves
since and starts the counters over; and the resolution would be whatever it
happened to retain.

What ships

agent_counters — one record per (window, counter), hour-aligned,
superseding, the same shape as agent_states so it resumes through the same
machinery and the backend implements one thing twice rather than two things.

The counter's name is the dotted path that number has where it is reported
cumulatively — filter.excluded_pod_annotation, pprof_pull.refused. The name
is the join, so this payload says when and never restates what: each
number's meaning stays in the one place that already documents it.

The subtraction was decided once already

ADR 0062 moved the /proc counter subtraction onto the node and set the rule
that matters more than the arithmetic: three cases produce no delta rather
than a wrong one
. Same shape here, with since in the role of the process
start time:

  • a pass whose base differs from the previous pass's accrues nothing — the
    readings belong to different processes and are not subtractable;
  • a counter that fell under an unchanged base accrues nothing either;
  • the first pass of a process accrues nothing, because there is nothing behind
    it to subtract from.

And one rule the durations do not need: the interval splits at a window
boundary because it is a duration; the rise does not, because it happened at an
instant no pass can see. Splitting it by elapsed time would invent that instant.

The counter list is closed, and each exclusion is argued

In the ADR rather than as a hunch. The shipping counters are out for the reason
worth repeating here: the backend issued those statuses itself and saw the gaps
in captured_at itself, so a window of them would tell it what it already
wrote down.

Also out: the placement and node drops (shape of the data, not behaviour over
time); the endpoint and goroutine coverages (targets by latest answer — a
snapshot, and subtracting two snapshots gives a number with no referent); and
the inventory/scan/eBPF blocks (per-node aggregates nothing may subtract across
a changing set of nodes).

What it still cannot say

Under its own heading in ADR 0089: a restart loses the rises inside its own gap
— the new process's counters start at zero, so no reading anywhere spans the
outage, and observed_nanos is what makes that hole visible rather than silent.
A rise within one pass of a boundary may land in the later window. And a delta
counts decisions, not objects, inheriting that exactly from the counters it is
derived from.

Evidence

go test -race ./...            all packages ok
go vet -tags e2e ./...         clean
GOOS=linux golangci-lint run   0 issues
git archive HEAD | tar -x      builds and tests clean from the extraction

🤖 Generated with Claude Code

https://claude.ai/code/session_01KeZECJXTDHL6Nts95eKMJA

The half ADR 0088 named and left. Every counter in `collection_coverage` is
cumulative from `since`, which answers how much and never when: a namespace
annotated an hour ago and one annotated three weeks ago reach the same total,
and the counter that explains a workload's missing data cannot say whether the
explanation is today's.

`agent_counters` is one record per (window, counter), hour-aligned, carrying the
rise within the window and how much of it the agent was running to count. The
counter's name is the dotted path that number has where it is reported
cumulatively, so the payload says when and never restates what.

Where a subtraction belongs was settled once already: ADR 0062 put the /proc
counter subtraction on the node and set the rule that matters more than the
arithmetic — three cases produce no delta rather than a wrong one. Same shape
here with `since` as the key: a pass whose base moved accrues nothing, and a
counter that fell under an unchanged base accrues nothing either.

The counter list is closed and each exclusion is argued in the ADR rather than
being "every number we have". The shipping counters are out for a reason worth
naming: the backend issued those statuses itself and saw the gaps in
`captured_at` itself, so a window here would tell it what it already wrote down.

  go test -race ./...            all packages ok
  go vet -tags e2e ./...         clean
  GOOS=linux golangci-lint run   0 issues

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeZECJXTDHL6Nts95eKMJA
@kfeofantov
kfeofantov merged commit fad1723 into main Sep 19, 2026
5 checks passed
@kfeofantov
kfeofantov deleted the feat/a-window-says-what-changed branch September 19, 2026 08:45
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