Task · SKT-0013.01

Capture the OTel-native receiver permutation and resolve SK-85

Description

The first permutation to capture, and it is worth doing before any of the SKT-0007 emission waves rather than alongside them.

config-other-methods/otel-collector-receivers/ deploys a DaemonSet running otlp, hostmetrics and filelog, and a Deployment running otlp, k8s_cluster and k8sobjects. Those are the exact producers SKT-0007.01 cited when it verdicted k8s_cluster and host OTEL-NATIVE, so this permutation IS the ground truth those verdicts were reasoned about but never observed.

What it unblocks: cantfind SK-85 records that the k8sclusterreceiver metric names are confirmed from its own metadata but the kubeletstatsreceiver DEFAULT-ENABLED set is not, and SKT-0007.04 explicitly cannot emit a kubeletstats family until that resolves. Capturing this permutation in the k3d lab is substantially cheaper than the emission work waiting behind it.

Confirmed from the documentation: the collector stamps k8s.cluster.name via a resource processor, promotes k8s.node.name and host.name to datapoint attributes, and uses service.name=integrations/kubernetes/eventhandler for events. Two host metrics are explicitly enabled beyond the defaults. Capture the real shape rather than encoding those four facts — they are orientation, not a contract.

Note what this permutation does NOT cover, so nobody over-reads the capture: it carries resource metrics, events and logs. It is not a drop-in replacement for the full kube_* surface, so a blueprint modelling it should not silently also emit families this deployment never produces.

Acceptance Criteria

Definition of Done

Implementation Notes

DELIVERED 2026-08-27, commit 1f3b433. Captured, promoted, recorded.

The capture

LAB_RUN_ID=skt001301a bash e2e/lab/run.sh otel-receivers — outcome CAPTURED, all four acceptance checks PASS, teardown confirmed, 300s window. 74 metric families, 8302 OTLP metric records, 168 OTLP log records, 0 traces. Instrument evidence PASS. The permutation’s meta.env is now PROVEN, so it joins the default matrix selection, and PERMUTATION_CORPUS_AREAS is corrected from the pre-capture guess “otlp-metrics” to “k8s host logs”: the split is by producer domain, not by transport.

Promoted into three permutation-tagged corpus documents with a new tested tool, lab-matrix promote, so the value-retention rule is one place rather than a judgement made afresh: an attribute’s values survive only when the set is fixed by the producer’s own contract (os.type, direction, state, protocol, k8s.container.status.reason). Everything a deployment chooses is elided. Documented in reality-corpus/README.md with the exact invocation.

THE CHART TRAP, and it decided whether this task could succeed at all

The documented values file names service.pipelines.metrics.receivers: [otlp, hostmetrics], so reading it alone concludes kubeletstats is disabled and SK-85 unresolvable from this permutation. It is not: presets.kubeletMetrics APPENDS its receiver to the pipeline rather than being overwritten by the explicit list, and supplies the nodes/stats RBAC. Verified by helm template before spending a cluster on it. Same render also shows the chart emitting Alloy’s snake_case component spellings (file_log, k8s_attributes, otlp_http) under command.name: bin/otelcol, so a config grep for filelog finds nothing.

SK-85 resolved from observation

kubeletstats default-enabled = container, pod and node metric groups. volume is NOT default (no k8s.volume.* observed) and the *.node.utilization ratios stay opt-in (absent). Full family list, instruments and attribute sets in signals/k8s.md [slug: k8s-otel-native-permutation].

What the capture could NOT observe — filed, not guessed

Observations a future emitter must not get wrong

Verification

make gate green, 239 packages. make signal-fidelity: contradictions unchanged at 68 — the 74 new families land entirely as coverage evidence, which is the correct signal that synthkit emits none of this surface yet. CodeRabbit review run pre-push; three findings fixed (empty-document refusal widened to every shape, observed_contract_counts now counts logs so a logs-only document does not record 0, test assertion tightened to the specific reality-only family) and two documentation errors corrected from it (the filepath-vs-k8sattributes split above, and the watch semantics in SK-102). Its fourth suggestion — retype k8s.container.status.reason as sum — was NOT applied: the corpus has no observation distinguishing a Gauge from a non-monotonic Sum, so recording sum would assert something unobserved. Filed as SK-103 instead.

Final Summary

The OTel Collector native-receivers permutation is captured, promoted and recorded, and cantfind SK-85 is resolved from observation rather than documentation. One 300s k3d run decoded 74 metric families, 8302 OTLP metric records and 168 OTLP log records, now held in three permutation-tagged corpus documents and written up in signals/k8s.md, signals/host.md and signals/logs.md with provenance. kubeletstats default-enabled is confirmed as the container, pod and node metric groups, with the volume group and the *.node.utilization ratios confirmed off. The capture nearly did not happen: the documented values file names an explicit metrics receiver list that omits kubeletstats, and only a helm template render showed that the chart preset appends its receiver rather than being overwritten — reading the values file alone would have concluded the permutation could not answer SK-85. What the run could not observe is filed rather than guessed, as SK-100 through SK-103: the filesystem scraper is silent for a k3s-in-Docker reason and not a receiver reason, the lab runs no StatefulSet/Job/CronJob/HPA objects, the k8sobjects event stream saw no watch update, and the corpus vocabulary cannot tell an OTLP Gauge from a non-monotonic Sum. Verified by make gate green at 239 packages and by contradictions holding at 68 while the 74 new families land entirely as coverage evidence, which is the correct reading that synthkit emits none of this surface yet.

View the source file on GitHub