Description
High DPM per series is one detector input; series CHURN is the other, and it drives a different set of tools — ‘new series per minute’ alerting, active-series accounting, and the Adaptive Metrics recommendations that follow from a set that will not settle.
synthkit already models real churn in places: the k8s constructs turn pods over through their lifecycle, and network_topology drives change_total from a real edge-visibility predicate with state.DeleteGauge behind it. What it does not have is a way for a blueprint to say ‘turn the active series set over at this rate’ so the churn becomes a test knob rather than whatever the model happens to produce.
Scope this by finding the existing seam, not by inventing one. Start from internal/state (which owns cumulative series lifetime and already has DeleteGauge) and from the constructs that genuinely have an identity lifecycle to churn — pods, nodes, topology edges — and decide there whether the knob belongs in shared state, in the fixture/identity layer, or as a per-construct declaration. Constructs must stay isolated from each other and from blueprint names; whatever seam is chosen has to respect that.
Two things not to do:
- Do not churn identity that is contractually stable. Cluster-unique pod names, UIDs and PV/PVC/EBS identity are seeded and deterministic on purpose (seed:cluster / clusterSeed / volSeed, and resolve-to-liveCluster byte-parity is tested). A churn knob that reseeds those breaks determinism guarantees the tests rely on.
- Do not manufacture churn by emitting a label that changes every tick. That produces cardinality with no lifecycle — the series never dies, it just multiplies, which is a different failure and a misleading test signal. Churn means series stopping as well as starting.
Deliverable is a rate a blueprint can declare, honoured by whichever constructs can honour it truthfully, and a plain statement of which constructs cannot and why.
Acceptance Criteria
- #1 A blueprint can declare a churn rate and the active series set demonstrably turns over at approximately that rate
- #2 Churned series stop being emitted, rather than accumulating alongside their replacements
- #3 Deterministic cluster-scoped identity (pod UIDs, volume identity, cluster seeds) is unchanged by the churn knob, proven by the existing determinism tests still passing
- #4 Constructs that cannot honour churn truthfully are named, with the reason, rather than silently ignoring the field
- #5 Construct isolation holds: TestCatalogImportIsolation still passes
Definition of Done
- #1 make gate (build vet test race rw-proto-check spdx-check forbidden-words)
- #2 make blueprint-schema (only if a blueprint field or construct/workload config struct changed)
- #3 DRY_RUN=true go run ./cmd/synthkit -once -dump — inventory diffed against signals/
Implementation Plan
After SKT-0015.01 lands, find the existing identity-lifecycle seam, TDD a declarable churn rate that retires old series without reseeding stable cluster identity, document unsupported constructs, and preserve import isolation.
Implementation Notes
Implementation decision: series_churn_per_minute belongs on the network_topology integration because its reconciled edge inventory already has truthful visibility transitions and DeleteGauge retirement. It rotates only stable declared edge identities and rejects rates larger than half the declared edge pool. Kubernetes pods, nodes and storage do not honour this field: their cluster-scoped names, UIDs, seeds and PV/PVC/EBS joins are deterministic contracts and are not reseeded or silently churned.
Implemented network_topology.series_churn_per_minute as a bounded rotating window over declared edge identities. Retired gauges use DeleteGauge; skipped ticks walk every elapsed churn-minute boundary so change_total does not lose a complete rotation. Focused validation: go test ./internal/construct/nettopo ./internal/construct/k8scluster ./internal/archtest -count=1 passed; make blueprint-schema regenerated both artifacts; git diff –check passed. CodeRabbit final review completed with zero findings after fixing delayed-tick transition accounting and clarifying baseline-visibility semantics.
Final evidence: tests prove two stable edge identities are removed and two returned per minute without accumulation at a 10s tick cadence, complete skipped rotations are counted, half-pool validation is pinned, Kubernetes determinism and TestCatalogImportIsolation pass, schema generation passed, and the integrated make gate passed.
Final Summary
Added truthful declarable churn to network_topology by rotating existing edge identities and deleting retired gauges. Preserved deterministic Kubernetes identity, documented unsupported constructs, and verified transition accounting plus isolation.