Description
Layer 0, the enabler: nothing else in SKT-0006 can be built without one struct that both the synth side and the capture side populate.
Today cmd/synthkit printInventory prints free text (metric name -> label KEYS, log source -> stream keys, service -> span names/attrs) and e2e/receiver keeps map[string]map[string]bool name->label-key sets. Neither carries label VALUES, instrument type, or histogram bucket bounds, so a diff built on them cannot detect the drift classes that matter most.
Deliver a shared internal/inventory package holding the schema plus a typed Diff. It must be importable by cmd/synthkit, by the capture receiver, and by tests, and must stay inside the architecture contract (no construct/workload imports it; it reads sink inventories only).
Cardinality is the design risk: real KSM kube_pod_labels / kube_node_labels label_* bags are unbounded, so the schema needs an explicit per-metric value-set cap with a recorded elision marker, otherwise the corpus becomes an enormous file that churns on every capture.
Acceptance Criteria
- #1 internal/inventory defines one schema covering metrics (instrument type, label keys, bounded label value sets, histogram bucket bounds), logs (transport, stream label keys and values, structured metadata keys), traces (resource attribute keys and values, span names, span attribute keys), profiles, and sigil ingest kinds
- #2 Label value sets are capped per metric with an explicit elision marker recorded when the cap is exceeded, so an unbounded label_* bag cannot bloat the output
- #3 synthkit gains a JSON inventory export producing this schema, and the existing -dump text output is either derived from it or kept working unchanged
- #4 The e2e receiver /__inventory endpoint emits the same schema
- #5 inventory.Diff returns typed findings distinguishing missing metric, extra metric, unexpected label key, label-value contradiction, instrument mismatch, and bucket-bound mismatch
- #6 Diff distinguishes a contradiction (synth emits something reality never produced) from a coverage gap (reality has something synth does not)
- #7 Two consecutive JSON exports of the same blueprint set have byte-identical structural projections: sorted (sink, metric name, sorted label keys) sets plus sorted log, trace, profile, and sigil contract fields; volatile sigil counts and randomly sampled dry-run exemplars are excluded. SKT-0004 proves literal whole-output byte identity is unsatisfiable.
- #8 Tests cover the schema, the cap/elision behaviour, and each Diff finding class
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
Run contract and ownership\n- Root role: DESIGN+INTEGRATION on gpt-5.6-sol/high. Root owns schema design, integration, cmd/synthkit, sink inventory adapters required to populate the schema, tracker mutations, commits, pushes, and acceptance.\n- Lane 2: EXECUTION on gpt-5.6-luna/max, fork_turns=“none”, owns internal/inventory/diff.go and its tests only; blocked until this schema is frozen and compiling.\n- Lane 3: EXECUTION on gpt-5.6-luna/max, fork_turns=“none”, solely owns e2e/receiver/receiver.go and e2e/receiver/receiver_test.go; blocked until this schema is frozen and compiling.\n- Delegation is forbidden in every lane. No lane runs Docker, k3d, Helm, or kubectl.\n\nFrozen inventory schema (JSON names shown verbatim)\n- Schema: schema_version, optional provenance, metrics[], logs[], traces[], profiles[], sigil[], receipts[].\n- Provenance: substrate, chart_version, captured_at; when present it applies to every entry in that captured inventory.\n- Metric: name, transports[], instrument_types[], labels[], optional histogram.\n- Attribute: key, values[], values_elided. Values are sorted and deduplicated. DefaultValueLimit=64 applies independently to each attribute key within each metric; values_elided=true is the explicit cap marker.\n- Histogram: classic, native, bucket_bounds[], native_schemas[]. classic and native may both be true for one family.\n- Log: source, transport, stream_labels[], structured_metadata_keys[].\n- Trace: service, resource_attributes[], span_names[], span_attribute_keys[].\n- Profile: profile_type, labels[].\n- Sigil: ingest_kind, operation_names[].\n- Receipt: protocol, count.\n- All top-level and nested slices are emitted in stable lexical or numeric order. Empty optional provenance/histogram data is omitted; synth-side JSON omits capture provenance and volatile sigil counts.\n\nFrozen Diff contract\n- Diff(synth, reality) returns []Finding.\n- Finding has kind, disposition, signal, field, synth_values[], reality_values[].\n- kind is one of missing_metric, extra_metric, unexpected_label_key, label_value_contradiction, instrument_mismatch, bucket_bound_mismatch.\n- disposition is contradiction when synth claims a shape reality did not produce, and coverage_gap when reality produced a shape synth does not model.\n\nImplementation sequence\n1. Add schema types, bounded deterministic builders/normalization, JSON export flag and sink adapters while preserving current -dump text byte shape.\n2. Run focused schema/export tests and freeze the compiling seam.\n3. Dispatch Lane 2 and Lane 3 only after route preflight and inspect route metadata after spawn.\n4. Integrate, run e2e-tagged receiver tests plus structural two-export comparison, CodeRabbit, and the task’s proportionate final gate.\n5. Commit explicit paths, push main, confirm exact-SHA CI, then finalize SKT-0006.01 before starting SKT-0006.03.
Formatting correction: the prior plan entry contains literal newline escapes because of a CLI quoting mistake. The frozen seam is:
- Schema: schema_version, optional provenance, metrics, logs, traces, profiles, sigil, receipts.
- Metric: name, transports, instrument_types, labels, optional histogram.
- Attribute: key, values, values_elided; retain the lexicographically smallest 64 values per attribute key per metric.
- Histogram: classic, native, bucket_bounds, native_schemas; classic and native may both be true.
- Diff(synth, reality) returns typed findings with kind and contradiction-or-coverage-gap disposition.
- Root owns cmd/synthkit and sink capture adapters. Lane 2 solely owns diff files. Lane 3 solely owns both receiver files. Both are Luna/max leaves with delegation forbidden.
Implementation Notes
2026-08-24: Corrected AC #7 before implementation. SKT-0004 demonstrates that raw whole-output identity is unsatisfiable because sigil counts vary by design candidate and dry-run exemplar lines are sampled; the replacement compares the stable structural projection.
2026-08-24 CodeRabbit review completed with 3 issues: both Major findings were fixed (invalid OTLP spans no longer enter captured inventory; native histogram names ending in classic suffix text are preserved) with regression tests. The Minor tracker-formatting issue was dismissed because task Markdown may only be mutated through Backlog CLI and the safety hook forbids destructive –plan replacement; the appended formatting-correction block is the authoritative readable copy.
2026-08-24 verification: focused inventory, receiver, race, and vet checks passed; two consecutive structural projections for k8s-full-stack, otlp-native, profiling-demo, and acme-ai-eval were byte-identical; populated export contained 1195 metrics, 5 logs, 10 traces, 15 profiles, and 3 sigil kinds. CodeRabbit completed under the rknightion organization; both Major findings were fixed with regression tests. The root final gate make gate passed once, including build, vet, plain and race tests, RW proto, SPDX, and forbidden-word checks. The required all-blueprint DRY_RUN text dump passed with 2645 distinct metric names and 15 profile types. make blueprint-schema was not run because no blueprint field or construct/workload config struct changed.
Final Summary
Added the shared canonical telemetry inventory schema, deterministic structural projection, synth JSON export, canonical e2e receiver output, and typed contradiction/coverage-gap Diff. Verified with focused inventory and e2e-tagged receiver tests including race and vet, byte-identical consecutive structural projections, CodeRabbit with both Major findings fixed, one passing make gate, and a populated all-blueprint DRY_RUN text dump. Exact-SHA CI run 32733293152 passed secret-scan, UI, Docker, Go, and E2E; its hygiene/ci-success failure is the pre-existing forbidden term in parent task SKT-0006, outside this task scope.