StreamAttestationService
- Package:
osyrastream.v1 - Fully-qualified name:
osyrastream.v1.StreamAttestationService - Source file:
stream_attestation_service.proto - RPC count: 8
StreamAttestationService is the AP00012 control surface (internal service-mesh, gRPC over HTTP/2 + mTLS; no public REST at V1, consistent with AP00002-IAM and AP00011-OME). The signed wire artifact is always the osyra-drift-v1 canonical-CBOR BAR; the protobuf messages below are decoded VIEWS and MUST NOT be the signature preimage (WIRE-TRUTH INVARIANT, above).
RPCs
| RPC | Kind | Request | Response |
|-----|------|---------|----------|
| AnchorBatch | unary | AnchorBatchRequest | AnchorBatchResponse |
| AnchorTermReceipt | unary | AnchorTermReceiptRequest | AnchorTermReceiptResponse |
| CountActiveAgents | unary | CountActiveAgentsRequest | CountActiveAgentsResponse |
| EmitBAR | bidirectional streaming | EmitBARRequest | BARReceipt |
| GetAttlogTrajectory | server streaming | GetAttlogTrajectoryRequest | AttlogRecordItem |
| GetTrajectory | server streaming | GetTrajectoryRequest | TrajectoryItem |
| SubscribeDrift | server streaming | SubscribeDriftRequest | DriftEvent |
| VerifyBAR | unary | VerifyBARRequest | VerifyBARResponse |
AnchorBatch
rpc AnchorBatch(AnchorBatchRequest) returns (AnchorBatchResponse)
- Kind: unary
- Request type:
AnchorBatchRequest - Response type:
AnchorBatchResponse
AnchorBatch: commit the current per-tenant MMR root to the AP00011 Verified-Memory JMT. Called by the AnchorScheduler every N BARs (default 60). Unary.
SLO: p99 ≤ 90 s commit-lag (network-bound on AP00011). Errors: anchor-commit-failed 6250, anchor-path-malformed 6251, MMR-append on unregistered tenant 6252.
AnchorTermReceipt
rpc AnchorTermReceipt(AnchorTermReceiptRequest) returns (AnchorTermReceiptResponse)
- Kind: unary
- Request type:
AnchorTermReceiptRequest - Response type:
AnchorTermReceiptResponse
AnchorTermReceipt: anchor an AP00007 Agent Termination Receipt root into the AP00011
JMT via the same AnchorCommitter seam AnchorBatch uses (ADR-137: AP00012 ANCHORS the
receipt's emission; AP00016 verifies it; AP00007 owns the lifecycle). The committed
value is receipt_root = SHA-256 of the canonical COSE_Sign1 osyra-term-receipt-v1
envelope (ADR-137 D3); the JMT path discriminator is the receipt's 32-byte
session_binding, so one termination session maps to ONE claim_id slot:
osyra-tenants/{hex(sha256(tenant_id))}/term-receipts/{hex(session_binding)}
AP00011 OME Insert is LAST-WRITE-WINS on (workspace, claim_id): re-anchoring the SAME
receipt is an idempotent no-op (identical value_hash), while a DIFFERENT root for the same
session OVERWRITES the anchored root (OME provides no conflict signal). Cross-tenant
anchoring is prevented by the OS-Tenant-Id authn guard (tenant_id MUST match the
authenticated identity when the header is present) + OME per-workspace RLS — NOT by an OME
conflict rejection. A termination is a discrete lifecycle-terminal emit — it does NOT enter
the BAR MMR (path-namespace-disjoint from anchors/). Unary.
Errors: cross-tenant 6233, request-validation 6234, anchor-path-malformed 6251, anchor-commit-failed 6250 (transient OME failure → Unavailable; permanent OME rejection → FailedPrecondition). Returns Unimplemented when no term-receipt committer is wired. LINEAR: ENG-2038 (EPIC ENG-2034); additive + buf-breaking-safe.
CountActiveAgents
rpc CountActiveAgents(CountActiveAgentsRequest) returns (CountActiveAgentsResponse)
- Kind: unary
- Request type:
CountActiveAgentsRequest - Response type:
CountActiveAgentsResponse
CountActiveAgents: the distinct-BAR-agent cardinality source for per-agent metered billing (ENG-1713/1716). Returns the COUNT of distinct agents (distinct sha256(agent_did)) that emitted at least one BAR for the tenant within [since_unix_ns, until_unix_ns] — it NEVER returns or exposes any agent_did (the agent identity is a billing-cardinality DoS and a PII vector, DESIGN §11.1 / threat-model C-1: agent_did is never a label and never crosses this surface). The count unions the durable cold archive (the authoritative, anchored history) with the live hot ring (very-recent, not-yet-anchored agents), so an agent that emitted seconds ago is counted.
TENANT SCOPING (confused-deputy defense §8.1.1): scoped to the AUTHENTICATED tenant from the OS-Tenant-Id ingress metadata — NEVER request input. A non-empty CountActiveAgentsRequest.tenant_id that disagrees with the authenticated tenant is rejected (OSY-DRIFT-6233; mirrors GetTrajectory §10.3 / SubscribeDrift). A tenant cannot count another tenant's agents.
EXACTNESS: the cold archive is partitioned by UTC day ({yyyy}/{mm}/{dd}), so the cold scan
is day-granular. When [since, until] aligns to UTC day boundaries the result is exact
(exact = true); otherwise the day-rounded cold scan is a SUPERSET of the true window and
exact = false (the count is an upper bound on the partial boundary days). Callers that
need a billing-exact count align the window to UTC days.
Unary. Read-only; per-tenant-scoped and authn-gated (not an unauthenticated DoS); callers bound the scan via since/until.
EmitBAR
rpc EmitBAR(stream EmitBARRequest) returns (stream BARReceipt)
- Kind: bidirectional streaming
- Request type:
EmitBARRequest - Response type:
BARReceipt
EmitBAR: an agent runtime client-streams per-window BARs; the server verifies each BAR through the tenant-resolving verify path (design §8.1.1), appends it to the per-tenant MMR, and returns one BARReceipt per BAR (MMR position + status). Bi-directional backpressure via HTTP/2 flow control — on emitter overrun the server applies backpressure rather than dropping (no silent loss).
SLO: p99 300 µs server-side per BAR; stream deadline 30 s idle. Errors (via BARReceipt.Status): drift-budget 6210, monotonicity 6211, baseline 6212, signature 6220, tenant-unregistered 6230, session-key-expired 6240.
GetAttlogTrajectory
rpc GetAttlogTrajectory(GetAttlogTrajectoryRequest) returns (stream AttlogRecordItem)
- Kind: server streaming
- Request type:
GetAttlogTrajectoryRequest - Response type:
AttlogRecordItem
GetAttlogTrajectory: ordered osyra-attlog-v1 ATTESTED-LOG record stream for forensic replay
over a time range for one (tenant_id, agent_did) stream (ENG-2512 — the source the AP00001
edge attested-log resolver proxies, unblocking ENG-2440). Distinct from GetTrajectory, which
streams osyra-drift-v1 BARs from a DIFFERENT wire format + a DIFFERENT MMR. Reads the durable
WORM cold archive via attlog.ReadStream, which decodes every record and verifies the per-record
Ed25519 signature + the gap-free causal-ordering chain; a tamper/gap verdict is surfaced as a
terminal FailedPrecondition AFTER the (verified-as-far-as-possible) records stream (stream-then-
verdict, mirroring GetTrajectory's T-DRIFT-2 surfacing). encoded_record is the canonical
signed wire (WIRE-TRUTH) so the consumer (edge resolver → FE viewer) re-verifies OFFLINE.
Server-streaming.
TENANT SCOPING (confused-deputy defense §8.1.1): scoped to the AUTHENTICATED tenant from the OS-Tenant-Id ingress metadata; a non-empty request tenant_id that disagrees is OSY-DRIFT-6233. Returns Unimplemented when no attested-log is wired.
GetTrajectory
rpc GetTrajectory(GetTrajectoryRequest) returns (stream TrajectoryItem)
- Kind: server streaming
- Request type:
GetTrajectoryRequest - Response type:
TrajectoryItem
GetTrajectory: ordered BAR stream for forensic replay over a time range for one (tenant_id, agent_did, workspace_path) trajectory. Reads from the hot ring buffer (recent) → cold archive (older); attaches AP00011 inclusion proofs when include_proofs is set. Server-streaming.
SLO: first-byte p99 50 ms.
SubscribeDrift
rpc SubscribeDrift(SubscribeDriftRequest) returns (stream DriftEvent)
- Kind: server streaming
- Request type:
SubscribeDriftRequest - Response type:
DriftEvent
SubscribeDrift: a downstream policy enforcer (e.g. the AP00001 edge gateway) server-side subscribes to the live per-tenant drift-event feed. The server pushes a DriftEvent for ANY non-OK terminal EmitBAR status — drift-budget 6210, monotonicity 6211, baseline 6212, signature 6220, tenant-unregistered 6230, session-key-expired 6240 (the full BARReceipt.Status non-OK set; same set as the EmitBAR doc above). This lets an enforcer quarantine a misbehaving agent at ingress BEFORE it reaches downstream services, WITHOUT polling GetTrajectory (which is forensic-replay shaped, not a live push). Events are fanned out ONLY on the emitting tenant's own authenticated stream (the publish is keyed on the OS-Tenant-Id ingress identity, never the decoded bar.tenant_id — §8.1.1).
TENANT SCOPING (confused-deputy defense, §8.1.1): the subscription is scoped to the AUTHENTICATED tenant resolved from the OS-Tenant-Id ingress metadata — NEVER from request input. A non-empty SubscribeDriftRequest.tenant_id that disagrees with the authenticated tenant is rejected (OSY-DRIFT-6233). A subscriber NEVER receives another tenant's drift events.
DELIVERY: best-effort, at-most-once, newest-wins. The server applies bounded per-subscriber buffering and, on subscriber overrun, drops events for THAT subscriber only — signalled via DriftEvent.dropped_since — rather than blocking the EmitBAR hot path (p99 300 µs). The authoritative, gap-free record remains the per-tenant MMR (replay via GetTrajectory). The pushed DriftEvent carries the opaque signed canonical_cbor so the subscriber can VerifyBAR authoritatively (WIRE-TRUTH INVARIANT) — the protobuf fields are decoded VIEWS, never the signature preimage.
SLO: push latency p99 ≤ 5 ms from emit classification. The stream is long-lived (no idle deadline — the enforcer holds it open for the lifetime of its process).
VerifyBAR
rpc VerifyBAR(VerifyBARRequest) returns (VerifyBARResponse)
- Kind: unary
- Request type:
VerifyBARRequest - Response type:
VerifyBARResponse
VerifyBAR: validate a BAR's signature + T-DRIFT-1/3 structural invariants + freshness + (optionally) JMT anchor membership. Routes through the tenant- resolving verify path (design §8.1.1): the per-tenant session pubkey is resolved INTERNALLY from the BAR's tenant_id, never from caller input — closing the confused-deputy gap (a valid tenant-B BAR presented on tenant-A ingress is rejected, OSY-DRIFT-6233). Unary.
SLO: p99 500 µs (adds the JMT proof check when jmt_proof is set).