Skip to main content
You pick the rung; nothing above it leaves, and nothing above it is kept. Every rung is the same mechanism — a bundle of plain, inspectable files pushed to your station’s write path on the channel host you already pull from. No streams, no second endpoint, no new firewall rule; the tool prints the payload path and stops before sending, so your security team can open it first.
Content is on no rung. Transcripts and meeting bodies never leave, structurally: report.v1 sets additionalProperties: false on every object but one, so there is no field a transcript could go in. The exception is usage.tokens_by_model, an open-keyed map — and its keys are constrained to model-name shape while its values must be integers, so it cannot hold a string either. A payload carrying content fails validation on your side, before it is sent.
Your contract.yaml declares the rung, and three independent things hold it:
  1. The packager cannot collect above itcollectors.collect() resolves your tier to a list of collector functions before calling any of them; at T2 the usage collector is never referenced.
  2. The schema refuses a payload above its own declared tier, so even a bug in (1) cannot produce one.
  3. Our ingest refuses a bundle exceeding your declared scope — a T3-shaped bundle against a T2 contract is refused (S10) and nothing is kept. That is the half you cannot check yourself, which is why it is there.

Declaring your rung

tier is deliberately not settable from a values file. A report_scope with no tier is tier 1; no report_scope at all is a refusal at both ends. explicit-command-only means nothing in the delivered software originates a report — it happens when an operator types --submit. Setting scheduled is what authorises the in-cluster CronJob: the station chart renders no CronJob unless receiptSender.trigger is scheduled, and that value is set to mirror your contract. The chart reads its values, not the contract document — so the two must be set together, and the contract is the authority the value is copied from.

Sending, per rung

T1 fires from a PostSync hook Job when a sync completes. T2/T3 go by that CronJob, or by hand — the sender’s RBAC is get/list on pods, deployments, cronjobs and jobs plus get on one named ConfigMap, and get on the one named Argo Application it follows, in the argocd namespace. That last one is what gives the receipt its pin and sync status; it defaults on (receiptSender.readArgoApplication) and a station that will not grant cross-namespace read sets it false and submits with those fields absent rather than invented. No secrets, no exec, no logs, no write.
T4 does not send. It writes a scrubbed bundle to your disk and stops — no --submit path, and no tier: 4 value in report.v1. Secret and ConfigMap values, container env values and credential-shaped annotations are removed; object names, images, conditions and event messages are kept.
A counter that could not be collected is reported absent, with a reason — never defaulted to zero. T3 ships today as an interface with no implementation and says so: every counter null, one absent row explaining why. The more your side chooses to send back, the faster your deployment improves: support entitlement at T1, degradation visible before you file a ticket at T2, fleet benchmarks and tuned defaults at T3. Next: The station gate · Security model