Observation sources¶
How to configure the offline trace exports the dashboard reads observed dependencies from, and how a configured source reports its own health.
Observed edges come from OTLP/JSON trace files you mount and name. What an observed edge is, and how it reconciles against a declared one, is in Observed dependencies and reconciliation.
Named observation sources¶
pacto dashboard --traces <file> (repeatable, or the PACTO_DASHBOARD_TRACES
environment variable) is the ad-hoc form: it names its sources by position
(observation, observation-1, ...), which is honest for a one-off command line
and wrong for anything written down. A configuration that is written down uses
pacto dashboard --trace-source NAME=PATH (repeatable, or
PACTO_DASHBOARD_TRACE_SOURCES), where NAME is the source's identity: it is
what the fleet, the API and the dashboard's Data Source list call it.
Identity and location are deliberately separate. Reordering the configuration never renames a source; moving the file never renames it either; and two sources whose files happen to share a basename stay two sources.
One namespace for every Data Source¶
A name must be unique across every Data Source the dashboard assembles, not
just among the trace sources. The live Kubernetes source, the OCI and local-cache
sources, local bundle roots, target-state fixtures, evidence stores and Evidence
Servers all claim names in the same namespace — so a trace source called k8s,
local or oci collides with one of them, and inside a pod (where there is no
kubeconfig context to name the cluster) the live Kubernetes source is called
exactly k8s. A collision is refused before a snapshot is built, with an
error naming both claimants. Neither source is renamed: an identity two sources
share is not an identity, and picking a winner would make the dashboard's answer
depend on assembly order.
What that refusal costs depends on who asked for the snapshot. A command that builds one and exits fails with that error. The long-running dashboard is not killed by it — the HTTP host keeps serving, and the refused build is an ordinary refresh failure: a snapshot that was already published stays published and served while the failure is recorded as degraded, and if no build has ever succeeded there is no snapshot to serve, so the operational-graph endpoints answer with the collision error until the names are distinct and a refresh succeeds. The one outcome that never happens is the ambiguous snapshot: no snapshot ever publishes a Data Source key owned by two sources.
A source reads only inside its own directory¶
A named source may read only inside the directory its file sits in. That directory is the source's root, and the read is resolved through it, so a symlink placed in the storage — by whoever produces the export, or by anyone who can write to it — cannot walk out to the container's own filesystem. Symlinks themselves are fine: the internal indirection a projected Kubernetes ConfigMap volume is built from resolves normally. Only leaving the root is refused, and it is refused as a source failure, so the Data Source becomes explicitly unavailable rather than quietly reading something else.
Operator-managed observation sources¶
The operator-managed dashboard declares its sources in Helm values:
dashboard:
enabled: true
observation:
sources:
- name: orders # the stable Data Source identity
file: traces.json # a file name, directly inside this source's mount
existingClaim: orders-trace-export
The operator mounts each declared backing read-only at
/var/lib/pacto/observation/<name>/ and configures the dashboard to read exactly
<mount>/<file> under the name <name>. Nothing is scanned: Pacto opens the
files you declared and no others, never recursively, and never writes to them.
Changing a source changes the pod template, so Kubernetes rolls the dashboard;
reordering does not, because order is not identity.
file is a plain file name, not a path: no /, no whitespace and no comma
(the character that separates fields on the controller's flag). Give a source
its own backing and mount its export at the top of it rather than in a
subdirectory — which also makes the mount the read root, with nothing above it in
reach. existingClaim and configMap must be valid Kubernetes object names,
checked when the values are read rather than at admission. Every value the chart
accepts survives the trip through the controller's flag unchanged; a
Helm-rendering test
parses the rendered argument rather than a second copy of the grammar.
Exactly one backing supplies each source:
| Backing | Use for | Limits |
|---|---|---|
existingClaim |
Real exports. Some other workload writes the file into a PVC; the dashboard only reads it. | The claim must exist; a missing PVC blocks pod scheduling, as it would for any workload. |
configMap |
Small, static exports — fixtures and deterministic tests. | A ConfigMap caps near 1 MiB. Mounted optional, so a missing ConfigMap degrades that Data Source instead of wedging the pod. |
Storage ownership stays outside Pacto. Whoever owns the claim or the ConfigMap owns producing, sizing, rotating and deleting the trace export; Pacto is a reader with no retention policy.
Offline input only¶
Pacto ships no live OTLP receiver: nothing listens on 4317 or 4318, there is
no /v1/traces endpoint, and no collector ships with the dashboard. For live
collection, run a Collector you own and point a source at whatever file it
exports. Two architecture gates hold the line —
TestOTelObserverStaysOffline on the analyzer and
TestOperatorObservationPackagingStaysOffline on the packaging.
Source health is not evidence freshness¶
A configured trace source is a Data Source like any other, and it answers two independent questions:
- Source health — could Pacto read and parse the file? A missing file, an
unreadable mount, a read that would leave the mount or malformed OTLP/JSON
makes that source explicitly
unavailable, with aSOURCE_UNAVAILABLElimitation naming it. It is never silently absent, and a failing source never takes the dashboard down: the Kubernetes, OCI, local and evidence sources keep answering, and any other healthy trace source keeps contributing. - Evidence freshness — how recent is what the file witnessed? A perfectly readable export of last month's traffic is an available source carrying stale evidence; the observed edges carry the window they were seen in.
The Evidence Server is a different concept and stays separate: it is the verification boundary for signed evidence envelopes, which the dashboard consumes read-only over HTTP. Trace exports do not travel through it, and the registry it publishes to is never reachable from the dashboard.
See also¶
- The operational graph — what observed edges mean and how they reconcile against declared ones
- Offline trace sources for the dashboard — the Helm values in their install context
- Dashboard container — the equivalent environment variables outside Kubernetes
- Evidence protocol — the separate, signed evidence path