Repository navigation
feat(tenancy): record the tenant in metrics and the console view - #24
Merged
Merged
Conversation
Phase 5 of docs/design-tenancy.md. The audit field landed with resolution in
phase 1; this adds the metric dimension and makes the console's federation
view the viewer's.
The design said "as a metric label". It cannot be one, and the correction is
recorded in the design next to the overlap one. The v1 contract freezes metric
names *and label sets*, so a tenant label on fold_requests_total would break
every dashboard and recording rule built on it — and the contract is one of
the things the roadmap says vetoes a feature regardless of demand. New names
are additive, which the contract permits, so the dimension ships as its own
series: fold_tenant_requests_total{tenant,outcome} and
fold_tenant_upstream_calls_total{tenant}, the second counting the same unit a
tenant budget is charged in, so an allowance can be watched being spent rather
than reconstructed from the audit stream afterwards. Cardinality is the
declared tenant count — config-bounded, like the upstream label.
Untenanted traffic records nothing rather than a tenant="" series: an empty
label reads as a tenant in a dashboard, and those requests are already counted
in fold_requests_total. A test asserts no frozen metric ever grows the label,
which is what fails if someone later folds these two series into one.
The console half turned out to be a boundary, not a nicety. The state API
listed every upstream's URL, owner, and labels to any authenticated principal,
which after phase 4 made the dashboard the one place a scoped tenant could
read the topology its own traffic is refused. The federation view is now the
viewer's — subset, counts, and the tenant's own limits, so a customer-facing
console can answer "what am I allowed" without an operator relaying it.
security-model.md stated the broader disclosure rule as unconditional; it now
records the exception.
Latency gate unmoved at 180us.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 5 of docs/design-tenancy.md. The audit field landed with resolution in phase 1; this adds the metric dimension and makes the console's federation view the viewer's.
The design said "as a metric label". It cannot be one.
The v1 contract freezes metric names and label sets, so a
tenantlabel onfold_requests_totalwould break every dashboard and recording rule built on it — and that contract is one of the things the roadmap says vetoes a feature regardless of demand. New metric names are additive, which the contract permits, so the dimension ships as its own series:fold_tenant_requests_total{tenant, outcome}fold_tenant_upstream_calls_total{tenant}— the same unit a tenant budget is charged in, so an allowance can be watched being spent rather than reconstructed from the audit stream afterwardsCardinality is the declared tenant count: config-bounded, exactly like the
upstreamlabel. Untenanted traffic records nothing rather than atenant=""series — an empty label reads as a tenant in a dashboard, and those requests are already infold_requests_total.TestFrozenMetricsGainNoTenantLabelasserts no frozen metric ever grows the label; it is what fails if someone later folds these two series into one.The correction is recorded in the design record next to the earlier overlap one.
The console half is a boundary, not a nicety
The state API listed every upstream's URL, owner, and labels to any authenticated principal. After phase 4 that made the dashboard the one place a scoped tenant could read the topology its own traffic is refused. The federation view is now the viewer's — subset, counts, and the tenant's own limits, so a customer-facing console can answer "what am I allowed" without an operator relaying it.
docs/security-model.mdstated the broader disclosure rule as unconditional; it now records the exception.Verification
make checkgreen, lint 0 issues, latency gate unmoved at 180 µs. Tests cover the two series counting requests and invocations, the outcome dimension on a denial, the frozen-label assertion, the no-empty-series rule, and the console view being tenant-scoped with counts that agree with the list.Remaining tenancy work after this: phase 6, the docs pass (README config section,
operations.mdwalkthrough,defaults.md, and thesecurity-model.mdrewrite of "Tenant isolation under load", which still describes the pre-tenancy emergent version).🤖 Generated with Claude Code