Task · SKT-0010.09

Classify log entries by shape, not by an absent source label

Description

Found by SKT-0006.05 while building the OTLP pod-logs lane, 2026-08-27. Predates that task and affects both transports equally.

internal/inventory/synth.go keys a log entry on stream.Labels["source"]. Pod-log streams deliberately carry NO source label — SK-20 live-verified that, and reserves source for the journal and kubernetes-events lanes. So synthkit projects every pod-log entry under an empty source, while the corpus records source: k8s_pod_logs.

The consequence is that the fidelity comparator can never match pod-log entries at all, on either transport. They cannot contradict and they cannot be confirmed; they are simply invisible to the audit. That is worse than a false finding, because a silent hole reads as a clean result — and pod logs are one of the highest-traffic surfaces synthkit emits.

The fix is not to stamp a source label onto the wire: SK-20 established that no real pod-log stream carries one, and inventing it to make a comparison work would be correcting the capture to the synth. The inventory projection has to classify a log entry by its SHAPE — the label set identifies a pod-log stream unambiguously — rather than by a label that correctly does not exist.

The new OTLP transport inherits the same empty source deliberately, for the same reason.

Acceptance Criteria

Definition of Done

Final Summary

Pod-log entries are now comparable at all, on both transports, without a source label being invented anywhere.

The shape rule reads label KEYS only: a stream is a pod-log stream when it carries the full namespace/pod/container identity triple in any of the three spellings a real pipeline puts on the wire — dotted OTLP, underscore-sanitised Loki, or the classic Alloy namespace/pod/container form. Reading keys rather than values means it works identically on a live stream and on a corpus document whose values are elided.

THE DEEPER DEFECT, which the task description did not capture: shape classification alone would have changed nothing, because the comparator identity deliberately excludes the recorded source. The raw key set was BOTH the identity AND the thing being compared, so the stream-label and structured-metadata comparisons in diffLogs were unreachable dead code for logs, and two recorded shapes of one family were two families. That is the literal mechanism behind “could not contradict and could not be confirmed”. Fixing the projection without fixing the join would have left the hole open.

WHAT THE NEWLY VISIBLE ENTRIES REVEALED, which is genuinely new information:

Measured A/B on one controlled tree: 650/73/577 to 649/73/576 — exactly one line, the false extra_log, and the extra_log class disappears from the report entirely. No new findings, no regressions.

View the source file on GitHub