Reality-corpus refresh and review¶
The reality corpus is the committed, credential-free evidence used by the signal-fidelity check. An unexempted contradiction fails that check; an explicit exemption remains visible in the Contradictions section, and a coverage gap is report-only. This page describes how to refresh the corpus and how to decide whether a candidate records real signal drift or only a different capture sample. The on-disk contract is defined in the reality-corpus README; this page is the operating procedure built on that contract.
The contract is deliberately narrow:
- The version is
synthkit.telemetry.reality-corpus/v1alpha1. - Each document is one
signals/<area>.mdarea and one generic producer atreality-corpus/<signals-area>/<source-id>.json. The loader reads only the corpus root and per-area subdirectories, so a sibling directory holding a different record kind is skipped rather than parsed as a corpus document. - The
sourceprovenance andauthority.substratesapply to every observation in that document. - Documents from different substrates are never unioned before
Diff. - Capture counts and receipts explain how an observation was collected; they are not signal-contract evidence.
- Explicit contradiction decisions live in a separate versioned exemption document. They are review records, not changes to captured reality.
Report-size standard¶
The human-readability budget for the signal-fidelity report is 27,212 lines or fewer. This bound is measured, not invented: on 2026-09-05, the current just signal-fidelity run produced a 27,212-line report body (7,369,240 bytes). That body contained 13,588 finding lines (two visible exempted contradictions and 13,586 coverage gaps) and 13,586 copy-pasteable PENDING lines. The bound is the current measured report size, and a later report that grows beyond it must be disclosed as a readability breach while this wave remains report-only for size.
The body is the complete output rendered by inventory.WriteFindingsReport after comparing the generated synth inventory with the loaded corpus documents and applying the contradiction-exemption records. It measures the heading and explanation, evidence-scope lines, contradiction and coverage-gap class headings, every finding line, every generated PENDING stub, and the blank lines and Markdown fences emitted around those sections. It does not use raw capture rows, distinct signal names, report bytes, or stderr as its unit. The command prints the body count after the report in this form:
N counts the newline-delimited report body and excludes that diagnostic line. Size alone never changes the exit status: malformed input, exemption errors, and unexempted contradictions retain their existing failure behavior.
Use the signal catalogue, its cross-cutting canon, and the signal-area index to identify the owning area and interpret an observed shape. The Kubernetes and CloudWatch catalogues are examples of area-level authorities: Kubernetes and CloudWatch.
The two producers¶
There are two allowed ways to obtain a refresh candidate. They produce different evidence and must remain distinguishable in the envelope.
| Producer | What it does | Authority and safety boundary |
|---|---|---|
| Credential-free k3d capture | Runs the disposable k3d capture lab and records collector-egress inventory. Its provenance uses the generic k3d_lab producer kind and the k3s substrate. | Root-owned and exclusive. It needs no service credentials. It may establish k3s-scoped shapes, but it cannot establish claims about another substrate. |
| Operator-selected live read-back | Reads the operator-selected live source through read-only queries and records the resulting inventory. Its provenance uses the generic gcx_live_readback producer kind and the substrate selected for that read-back. | Root-owned and exclusive. The operator chooses the target before the read-back; queries must not mutate the source. Credentials are used only by the root operation, never copied into a candidate, corpus document, or this page. |
| Reviewed external capture | Converts a reviewed schema-2 capture into a generic metric-only record. Its provenance uses synthkit_terraform_capture, an SHA-256 content identity, a scope class, and the source schema/tool versions. | The raw artefact stays outside this repository. Every promoted label value is elided, tag_* keys are omitted, and source scope/warning IDs remain visible. A source with an unknown metric type retains its instrument_type_source; no metric-name suffix is used to manufacture a type. |
The producer kind, substrate, collector name, collector version, and capture date are part of the evidence. A source ID is a generic producer name, not a stack, account, tenant, cluster, or other deployment identifier. The corpus must not contain private deployment details.
In particular, k3s and EKS evidence are not interchangeable. Evidence from k3s cannot correct an EKS-scoped claim, and evidence from EKS cannot correct a k3s-scoped claim. Keep the documents separate and let authority.substrates limit which synthetic claims each document may contradict.
Cross-substrate findings¶
The comparator never merges evidence across substrates. A finding originates from one document and names that document's substrate. When another captured substrate contains the same signal and has no difference for the same field, the finding reports it as matching evidence on substrate(s). When a captured substrate did not contain the signal, it reports absent evidence on
substrate(s). Absence is not agreement and it never changes a contradiction into a coverage gap or an exemption.
For example, the clean GCP capture observed label_cloud_google_com_gke_nodepool on kube_node_labels, while the EKS corpus observed label_eks_amazonaws_com_nodegroup on that family. This is a recorded cross-cloud divergence: a synthkit claim that matches EKS but contradicts the GCP label field names both substrates. It is not proof that either capture is defective, and a short capture that omitted kube_node_labels on a third substrate supplies no verdict at all. A synthkit defect is established only by the evidence for the substrate to which the finding applies; matching evidence elsewhere neither suppresses nor broadens it.
Reviewed schema-2 captures can be converted into generic candidate records only through a reviewed, hash-keyed routing manifest. The manifest names an ordered set of capture-provided identity label keys and routes each exact family to its signals area. The standard keys are the ingest marker and job. Projection consumes both as identity before eliding values; neither becomes a compared label. Per-family producer overrides are rejected. A missing job preserves the direct transport identity. If more than one identity component has multiple values, the family-level capture cannot prove their pairing: projection preserves only the directly observed transport identities. It never invents the Cartesian product of independent value sets. These transport-only claims do not match job-scoped synthetic claims and their coverage gaps stay visible.
Synthetic producers come from the catalog transport and each emitted series' own job. A family name, area, prefix or elided value never selects a producer. The live read-back admits a fixed vocabulary of generic literal job values for privacy; that vocabulary does not map families to jobs. Unknown live values cannot become public producer identities.
When a synth producer selects the k8s-monitoring default allow-list, its metric producer provenance also records the pinned chart version and selected variant (cluster-metrics, node-exporter=default, or node-exporter=integration). That provenance is a configuration fact, not a claim that a missing family was filtered: the comparator records an allow-list absence only when direct producer/source evidence proves the selected list owns that family. Otherwise the two possible causes of missing metadata remain unresolved evidence.
The converter currently projects metrics only and preserves the raw content hash, scope class, source schema/tool versions, warning IDs, source capture duration/window/soak/load declaration, and each family's instrument_type_source, including WINDOW_EXCEEDS_SOAK. The source logs, traces, and profiles remain absent evidence until they have an identity-safe, area-owned mapping into the inventory envelope; their omission does not assert that the source emitted no such signals. Superseded attempts remain excluded.
Schema-2 fixed-capture routing and partial projection¶
The manifest belongs at reality-corpus/manifests/capture-v2-routing.json; manifests/ is not a signals area, so the corpus loader deliberately does not treat it as an evidence document. Its version is synthkit.telemetry.capture-v2-routing/v1alpha1. It contains one route for each immutable raw-capture SHA-256 and, for every promoted metric family in that capture, an exact name and area. Producer values are derived only from the reviewed identity-label keys, never from a per-family override. Every producerless family instead has an exact unrouted record. A capture route also records only generic promotion provenance: kind, substrate, scope, collector/version, capture date, and the capture-provided producer-label key. It may also carry limitations, an optional list of {id, text} entries for capture-specific limitations. These are reviewed generic text on the route and projected verbatim into source.capture_limitations on every document produced from it; IDs are stable slugs. A route or existing corpus document without the field remains valid.
A capture route is exhaustive by classification, not by promotion. Each exact family must be either a direct route with an explicit area and directly observed identity, or an unrouted record with one exact reason:
missing_producer_and_areamissing_producer_unique_exact_area
ProjectCaptureV2 promotes only direct routes and returns unrouted families as separate residue. A consumer asking to compare an unrouted family receives an error, rather than absent evidence or a fallback projection. The converter rejects a missing capture hash, a direct family without a route, a producerless family without an unrouted record, stale routes or residue, duplicate classification, an unknown area, or a forbidden per-family producer override. It has no prefix fallback, source splitting, default area, or synthetic-union fallback. Do not create a placeholder or infer a row from the synthetic union: an unrouted row is visible residue, not corpus evidence.
The seven reviewed-input hashes are:
| Scope | SHA-256 |
|---|---|
| cluster EKS | c01efa82a07645a295e8a810ee6ca004f4a3628cac8a78813eb2e1727c3a1a9f |
| cluster AKS | 173dc9fdcf828762cecb8d089e0745c7a20416f42ffbea317ce41641be5c81db |
| cluster GKE | a5ef809344ac23b907edd096d771ea7910b845ecbd9be68a4adcf07fb1c31967 |
| cloud AWS | a38163f5306d92c0b9b698745a57bde788a60e8229967938797e6d51d1df3133 |
| cloud Azure | c425f16d70ad75fcc5dfa6cc0c110b2b212fb382eefc37f2234d201e435aaf27 |
| cloud GCP | 3904edb0183aadd3e3b5680e0f31d7655c21cac278fb3a877eb57c0e8a6ded78 |
| canonical full | d740d6f2d6058989ad16ba59ac567953a26865360587199d8789c43dd35d6155 |
2026-09-03 routing-review boundary¶
The seven raw files contain 14,261 metric rows and 5,204 distinct family names. The row count is capture volume, not a routing-review count. Review therefore starts from the distinct-name set, retaining every raw row only as evidence for that name's direct producer identity.
The capture-provided producer key is rksy_ingest. It directly identifies 2,286 distinct family names, including 514 names observed through more than one direct producer. The remaining 2,918 names have no direct producer value. For those remaining names only, exact membership in a machine-readable yaml signals metric or info_series entry identifies 781 names with one signals area. It does not resolve a name listed by more than one area, and it does not use a metric prefix, a label other than the producer key, or prose resemblance as a fallback.
These are review buckets, not name-routing inputs. In particular, promrw is an explicit ingest identity, not an owning signals area. The direct subset was rendered into hash-keyed 00-canon candidate documents, an explicitly allowed generic area: comparison remains producer-scoped and does not use that area to select a synthetic family. Producerless families are recorded as unrouted even when an exact catalogue-area membership is already known: area membership is not producer identity.
This leaves 2,137 distinct families in area residue. The 2,918 families without direct producer identity remain ineligible for corpus projection: 781 have a unique exact catalogue area but still need a producer, while 2,137 need both area and producer. They must be stored as exact hash/family unrouted rows, with the matching reason, rather than blocking the 2,286 directly identified families. The unreviewed producerless rows remain unavailable to signal fidelity; no exemption converts them into coverage.
The two failed full-capture attempts are not rows in this manifest. All canonical raw captures remain immutable in the sibling capture repository. The seven direct-subset records are non-loaded candidate evidence at reality-corpus/manifests/candidates/00-canon/, alongside reality-corpus/manifests/capture-v2-unrouted.json; manifests/ is excluded by the corpus loader. They are deliberately not active corpus evidence: just signal-fidelity compared them producer-scoped and reported signal-fidelity: 251 unexempted contradiction findings (28 histogram-bound and 223 unexpected-label-key contradictions; two unrelated pre-existing findings remain exempted). No exemption was added. Promotion is parked at those exact contradictions. The area is a generic candidate container only; the direct producer set remains the comparison gate.
EKS live read-back command¶
The EKS producer is manual and credentialed. The root must receive the target selection from the operator and pass it explicitly; the target rejects the former task-runner's unrelated default context rather than querying it:
GCX_SINCE optionally changes the bounded lookback from its 24h default. The command first runs gcx config check --context <selected> and stops with a clear error if the named context, its credential, connectivity, or configured Prometheus datasource is unavailable. It then uses only the read-only gcx metrics series endpoint. It does not change the active context and never calls a create, update, push, delete, apply, or other mutation command.
The query scope is deliberately explicit:
- EKS node and pod identity:
kube_node_info,kube_node_labels,kube_pod_info, andkube_pod_labels, limited to clusters proven EKS by anaws://provider-ID observation and an EKS-marked kubelet version. - EKS add-ons:
awscni_*,kubeproxy_*, and kube-proxy'skubernetes_build_infoseries. - Core CloudWatch catalogue families from
signals/cw.md, including observed_sum,_average,_maximum,_minimum, and_sample_countnames.
Bedrock, AppFlow, and every other AI/LLM family are excluded by construction. The command writes only the generic paths k8s/eks-live-readback.json, k8s-addons/eks-live-readback.json, and cw/eks-live-readback.json. Stable enum, instance-type, and topology values are retained; stack, account, tenant, cluster, resource, pod, node, IP, UID, ARN, and other deployment identities are stored as key presence with sticky values_elided: true. CloudWatch tag_* label keys are omitted because a tag name can itself contain a live deployment identity, which the frozen schema cannot safely elide. The selected context is never written to a document or printed in the report.
Safe refresh sequence¶
The accepted corpus is never edited in place from an unreviewed capture. Build a candidate, compare a temporary normalized result, then have the root accept and commit the reviewed per-area files.
Choose one producer and freeze its scope. Record the source kind, substrate, collector/chart and version, and the configuration that produced the candidate. For k3d, the root owns the disposable lab operation. For live read-back, the root obtains the operator's source selection and performs only read-only queries. Do not mix producer paths or substrates in one refresh.
Create a capture candidate. Retain the inventory output and its provenance outside the committed corpus while it is being reviewed. Check that it declares
synthkit.telemetry.inventory/v1alpha1, has the required signal-class arrays, and carries source provenance for the observations. Keepcapture_volumeandinventory.receiptsas provenance only. Remove any credential material or private deployment detail before the candidate is shown to a reviewer.Split the candidate by area. For every covered area, make a working document at
reality-corpus/<signals-area>/<source-id>.json. The area is the basename of the owning file undersignals/without.md; the source ID is generic. Each working document contains exactly one area and one producer. Do not put a full-capture document in the corpus, and do not combine observations from different substrates or producers merely because their field names look similar.Find the matching baseline. A cumulative merge is allowed only when the path, producer, substrate, collector/chart, version, and relevant configuration describe the same source. Compare the working document with the existing document without overwriting it. A substrate change or collector-version change is a review boundary, not an ordinary refresh; stop and use the reviewer decisions below.
Normalize repeated measurements. If the candidate came from multiple runs of the same source/configuration, first project each run to structural inventory and form their cumulative union. Sort set-valued fields. Preserve stable evidence, but do not let run count, receipt count, timestamps, dynamic exemplars, or a transient sample decide whether a shape exists.
Cumulatively merge with the baseline. Merge the normalized candidate into a temporary copy of the matching document. The identity used for each signal class is:
| Signal class | Identity for the union |
|---|---|
| Metric | Metric name |
| Log | Transport plus stream-label and structured-metadata shape |
| Trace | Service |
| Profile | Profile type |
| Sigil | Ingest kind |
Union structural fields and sort them. Attribute keys are sticky: once a real key has been observed for an identity, a later subset does not remove it. Dynamic log-source exemplars are provenance, not family identity. A missing observation never deletes an established shape.
Compare before accepting. Compare the current document with the temporary merged result and classify every difference using the reviewer table below. Then run the fidelity comparison against the synthetic inventory. Inspect the value-bearing canonical inventory with
DRY_RUN=true BLUEPRINT_NAMES='*' go run ./cmd/synthkit -once -inventory-json. The-dumppath is label-key-only structural output and can help inspect names and keys, but it is not a substitute when values are under review. The corpus comparison is scoped to the families covered by each corpus document. A family absent from a document is not thereby a coverage gap for that document.Review the candidate, not just the diff count. Confirm that any proposed addition is supported by the same substrate and configuration, that stable values are genuinely stable, and that no removal or narrowing was inferred from absence. The report is evidence-only: a finding does not authorize a corpus edit, a synthetic-code edit, or a deployment change. Once the corpus and exemption document load and validate successfully, findings fail the command only when an unexempted contradiction remains. Malformed input or a stale, overlapping, or count-mismatched exemption rule also fails closed.
Commit only the accepted merge. Update
captured_ononly when the reviewer accepts new structural evidence or confirmed stable-value evidence. Keep provenance-only count or receipt changes from changing the date. The root stages explicit accepted per-area paths, runs the repository's final documentation and fidelity checks, and owns the commit and push. An unreviewed candidate remains outside the committed corpus.
Evidence rules the comparator applies¶
The comparator answers one question: does the corpus contain evidence that contradicts a synthetic claim? Absent evidence is never a contradiction. A field a producer could not observe is a coverage gap that routes to a PENDING, and the fix is to make the producer observe it, not to exempt the field permanently. A corpus producer must therefore understand what its output means:
- Reviewed producer identity. A metric comparison requires the family name and a matching explicit
producers[].name. Names, prefixes, label values, document areas and prose never manufacture that identity. Different recorded producer sets yield oneproducer_mismatchcoverage gap per document/family, naming both sets. Disjoint sets do not compare signal shapes. An overlapping producer still compares with exactly the existing instrument, label and histogram rules; allow-list version/variant remain configuration provenance. A transport-only identity is not proof of a job match. Family unions cannot be split into per-job shapes after privacy elision. Legacy documents without producer attribution retain their existing comparisons. - No comparable producer. Each synthetic family/producer with no matching explicitly attributed reality producer anywhere in the selected substrate scope yields one
no_comparable_producerfinding in its own report section. Wholly unobserved families remain outside corpus coverage. Missing synthetic attribution is reported as(unrecorded), never inferred. Partial overlap preserves comparison and reports the unmatched claims.verdicts/producer-coverage.jsonretains the versioned count bound and records each reviewed family/producer pair with its triage reason. Growth fails, and a newly unmatched pair fails even when another pair disappears and the count stays unchanged. Smaller explicit blueprint selections may observe a subset. The baseline observation under the composite contract is 103, replacing the earlier transport-only observation of six. The command prints its actual selected-scope count; a smaller default selection is not evidence that the full observation disappeared. Ratchet entries do not exempt contradictions. Same-producer shape differences still contradict. The platform PostgreSQL activity family and chart telemetry build-info family have different jobs from the captured standalone integration and static scrape respectively; requiring those unrelated producers to contradict was an attribution error. - Instrument type. A metric whose
instrument_typesis exactly["unknown"]records that the producer could not observe an instrument shape. It yields a visibleunknown_instrument_evidencecoverage gap and PENDING stub, never aninstrument_mismatchor contradiction. The report says that the corpus does not know; it does not silently filter the family. Any entry recording a real type contradicts normally when synth disagrees, including a set that mixes a real type with the sentinel. A producer that learns to read instrument types therefore turns absent evidence into real verdicts without any comparator change. This is the SKT-0021.01 decision: use absent evidence because the producer did not observe a type; inferring one from a metric-name suffix would invent evidence rather than enrich the corpus. - Label keys. A key synthkit emits that the reality view does not carry is a contradiction; that is the never-invent-a-name rule and it is not relaxed. A key reality carries that synthkit does not emit is a coverage gap.
- Folded producer families. A corpus family that combines several jobs cannot establish the absence of a job-specific key.
kubernetes_build_infocurrently folds kubelet and kube-proxy, so itssourcedifference is a coverage gap that records the corpus modelling limit, not an exemption or a synth defect. - Read-path enrichment labels. A label a producer's read path adds after collector egress is not evidence about the emitted shape. Declare it in that producer's
source.enrichment_labels, with the provenance that says why the read path adds it. A declared key is removed from that document's reality view before comparison, in both the key and the value comparison. The declaration is per producer on purpose: one producer's read-path quirk must never govern another producer that does not add the key. - Destination-derived labels. The corpus normally records collector egress, while synthkit may intentionally model a final destination shape. Loki derives
service_nameafter ingestion when it is absent from an incoming stream. The manifest-stream exemption records that exact pre-ingest/post-ingest boundary; it does not claim that either the capture or synthkit is defective. The same finding's reality-onlyinstancekey remains a separate coverage gap under absent-evidence semantics and is not hidden by the exemption. - Read-path enrichment values. A read path also writes markers into the value of a label that is otherwise genuine collector-egress evidence: Grafana Cloud Adaptive Metrics replaces a retained label's value with
<aggregated>when it aggregates the series away. Declare those with the same block plus avalueslist. The key stays in the reality view and still compares as a key; only the declared values are removed before the value comparison. Use thevaluesform whenever the key itself is real — a key-scoped declaration would silently stop the comparator noticing that synthkit never emits that key. - The synth producer's own selector labels. synthkit's composition root stamps a blueprint selector label on every blueprint-scoped series, stream and span. It is synthkit's routing key rather than a vendor name synthkit invented, and no capture of collector egress can carry it, so comparing it against one is the same category error as comparing a read-path enrichment label. The synth export declares those keys in
provenance.selector_labels, read from the constant the composition root defines so a rename cannot silently reopen the finding class, and the comparator removes them from the synth view. This runs in the synth-to-reality direction only and only for declared keys: every other synth-only key is still a contradiction, and this field must never become a general suppression list. - Substrate scoping is document-level. When the synth export declares
provenance.substrate, a corpus document whoseauthority.substratesdoes not include it is skipped entirely. That is the right scope for a substrate-specific claim and the wrong scope for everything else in the same document, so an export that models more than one substrate — the fidelity gate's does, because it is produced withBLUEPRINT_NAMES='*'— declares no substrate rather than a value that would drop whole documents of real, substrate-independent evidence. A capture-instance value that only one substrate can produce, such as a Kubernetes build string, is kept out of the comparison by the producer marking itvalues_elided, not by dropping the document that carries it. - Label values need closed-set evidence before they contradict. A value synthkit emits that reality does not carry is a coverage gap by default: one deployment capture cannot enumerate an open set such as region, topology, protocol, operating system, or request type. The comparator keeps a short, explicit signal-and-field allow-list for values whose owning signal contract proves a closed enum; only those synth-only values are contradictions. A reality-only value is always a coverage gap. An unknown value set therefore follows the standing absent-evidence rule. Open two-way differences stay one coverage gap and name both directions; closed two-way differences remain one finding in each report section. Empty or elided values remain absent evidence and are not compared.
- The current
kube_pod_infolimits remain visible. The EKS evidence includescreated_by_kindvaluesAutoscalingListenerandEphemeralRunnerbeyond synthkit's four modeled owner kinds, and includeshost_network=truealongsidefalse. These are coverage gaps, not contradictions, and are tracked as accuracy limits under existing SKT-0010.13 (pods without a Deployment owner or node, including the related host-network modeling work). - Elided or empty value sets. A label marked
values_elidedcarries no value evidence at all and runs no value comparison, and neither does a key observed on either side without any value. Presence of the key is still evidence.
Explicit contradiction exemptions¶
An exemption is a narrow, reviewable decision for a contradiction that is known and intentionally outside the current model. It must not hide a new finding or turn a coverage gap into a pass. The command loads a separate JSON document with this versioned shape:
{
"version": "synthkit.telemetry.contradiction-exemptions/v1alpha1",
"exemptions": [
{
"id": "EX-001",
"reason": "The selected account is not the complete region universe.",
"area": "cw",
"source_kind": "gcx_live_readback",
"substrate": "eks",
"finding_kind": "label_value_contradiction",
"field": "labels.region",
"signal_prefix": "aws_",
"only_in_synth": ["eu-west-1", "us-east-1"],
"expected_matches": 2
}
]
}
id, reason, area, source_kind, substrate, finding_kind, field, only_in_synth, and expected_matches are required. Exactly one selector is also required: signal selects one exact signal, while signal_prefix selects a prefix. only_in_synth must be a non-empty, sorted, duplicate-free list that exactly equals difference(synth_values, reality_values) for each match. expected_matches must be positive and protects against a stale rule when the corpus changes. Unknown fields, duplicate IDs, malformed records, stale counts, overlapping rules, and rules that match the wrong finding kind are errors.
Applying exemptions marks matching contradiction findings with the exemption ID and reason in place. It never removes or reclassifies a finding. A finding may match at most one rule, and every rule must match exactly its expected count. The report keeps exempted findings under Contradictions, with the ID and reason shown on the finding line. Only contradictions without an exemption ID fail the command. Coverage gaps remain visible and report-only. If the exemption document is intentionally optional, its caller may treat a missing file as an empty list; malformed or present documents must still fail closed. An exemption count mismatch also fails closed, but the command writes the full report before returning that drift diagnostic so a stale rule and every co-occurring contradiction are visible in the same run.
A declared enrichment label looks like this, and lives in the source block beside the rest of the producer provenance:
"enrichment_labels": [
{
"key": "<observed-key>",
"provenance": "<why this producer's read path adds the key after ingest>"
},
{
"key": "<observed-key-with-a-real-egress-meaning>",
"values": ["<marker-the-read-path-writes-into-it>"],
"provenance": "<why this producer's read path writes that value after ingest>"
}
]
A declaration is curated evidence about a read path, so a cumulative refresh never drops it: a producer re-run that omits the block keeps the established declaration and may only add keys or values to it. A key-scoped declaration is the broader claim, so merging a key-scoped and a value-scoped declaration of the same key keeps it key-scoped and never narrows it. Removing a declaration is a reviewer decision, made the same way as any other narrowing in the table below.
Reviewer decision table¶
Use this table for every candidate difference. The question is not whether the raw capture changed; it is whether the authoritative structural evidence for the same producer, substrate, and configuration changed.
| Candidate observation | How to recognize it | Decision | Corpus action |
|---|---|---|---|
| New stable structure or value evidence | A new metric/log/trace/profile/sigil identity, structural field, or value is present in repeated measurements of the same source/configuration, or is independently confirmed by the same substrate. | Accept when the owning signals/<area>.md contract and provenance agree. | Add it through the cumulative structural union, retain confirmed stable values, and update captured_on. If the evidence disagrees with synth, correct synth toward the observed data; do not alter the observation to make synth pass. |
| Capture-volume or subset noise | Run counts, receipt counts, observed contract counts, timestamps, or the number of sampled instances changes; the candidate is only a subset of established shapes. | Treat as noise, not drift. | Keep established shapes and omit the candidate-only metadata change from Diff. capture_volume and receipts may document the run, but they never authorize deletion or narrowing and do not update captured_on by themselves. |
| Volatile identifiers | A real attribute key is present, but its values vary between runs or are per-run names/IDs. | Accept the key or structural presence, not the changing value set. | Store values: [] with values_elided: true. This is presence-only evidence and must not become a list of synthetic identifiers. Keep dynamic log-source exemplars out of family identity. |
| Substrate-only difference | A shape or value appears in one substrate and not another, such as a k3s-specific or EKS-specific label. | Keep the evidence substrate-scoped. Never use it to contradict the other substrate. | Keep separate documents and authority.substrates values. K3s evidence cannot correct EKS-scoped claims and vice versa. |
| Collector-version change | The collector/chart version, or another configuration component that defines the source, differs from the baseline. | Do not silently merge it as the same source/configuration. | Preserve the old baseline while the root reviews the new provenance. Accept it only as a separately identified producer/configuration or after an explicit baseline decision; retain the version in source.collector_version. |
| Candidate removal or narrowing | A previously accepted identity, field, key, or value is absent from one later capture. | Absence in one capture is not deletion authority. Require separate confirmed drift evidence from the same substrate/configuration. | Do not remove or narrow the baseline during an ordinary refresh. If confirmed drift is later accepted, make that explicit review decision and update the affected document; otherwise retain the established evidence. |
The report is an evidence record and an input to the review above, not permission to change captured reality. The command fails on an unexempted contradiction and reports coverage gaps without failing. When an accepted, substrate-scoped observation contradicts synthkit, the implementation and its authoritative signal catalogue are corrected toward observed reality. Captured evidence is not rewritten merely to silence a finding.
Sticky values and values_elided¶
Attribute values are evidence about a key, not a contract to enumerate every runtime value. The normal merge is a sorted set union for a stable value set. When the same key has varying values across the measurement runs, the canonical form is:
This means that the key is real and its values are open-ended capture noise. It does not mean that the key was absent, that the value is empty, or that a reviewer may choose an arbitrary replacement value. Once values_elided is true, it is sticky: a later candidate containing one value cannot re-materialize a finite value list or narrow the established evidence. Clearing the elision, narrowing a value set, or treating a new stable value as confirmed drift requires separate reviewer-confirmed evidence from the applicable source and substrate.
The same rule protects structural fields. A later subset cannot erase an attribute key, transport, histogram form, span name, or other established shape. Only separately confirmed drift can authorize deletion or narrowing.
Operational boundary and useful references¶
Live operations are root-only and exclusive. Reviewers and execution lanes may inspect candidates and reports, but must not run the k3d lab or live tooling, write to a live source, deploy anything, or issue a non-read-only query. Never put credentials, credential-bearing URLs, private deployment identifiers, or operator-selected target details in this page, a source ID, or a committed corpus document.
For the exact envelope and path rules, see the reality-corpus README. For capture tooling and inventory concepts, see Capture & Tooling and CLI & Commands. For signal naming and scope, use the catalogue contract, cross-cutting canon, and the relevant signal area.