Read-API proposals to governance service owners (HD-4)

Status: IMPLEMENTED 2026-08-06 (owner directive "Finish all / Open gates next") — all eight endpoints below now exist in services/service-*/main.py with the D6/D11 conventions (tenant REQUIRED + resolved against the caller; bounded reads; explicit truncation; read-only; no battery subsetting anywhere) and are covered by tests/remediation/test_hd4_read_apis.py (8 tests). Envelope for listings: {items, limit, truncated}.

Deployment reality — SUPERSEDED, re-measured 2026-08-30: all six services now carry these endpoints in their serving revision. Each service's serving revision was resolved to its image tag (the build commit) and that commit's services/<svc>/main.py was inspected for the endpoint:

Service Serving revision Endpoint Present in serving image
decision-control-plane 00039-x4k /api/v1/decisions, /api/v1/decisions/summary yes
approval-routing 00021-992 /api/v1/history yes
audit-replay 00031-wwb /api/v1/recent yes
validation-orchestrator 00023-6qp /api/v1/passports yes
action-runner 00041-4xv /api/v1/outcomes, /api/v1/actuators yes
policy-engine 00032-gxl /api/v1/policies yes

The six were redeployed 2026-08-22…08-30, well after the 2026-08-06 implementation, which is what closed the gap; the operator redeploy this note was waiting on has therefore already happened.

Measurement limit (do not overstate this): presence was verified in the image's build commit, NOT exercised over the wire. These services are --no-allow-unauthenticated and admit only ALLOWED_CALLER_SA, so a workstation identity token returns an ingress 401 and cannot prove response shape. What is proven: the routes are in the code that is serving. What is NOT proven: live response bodies against real tenant data.

Consequence for the frontend program: Phase 1D's "strict zero mock imports" is no longer blocked upstream — the UI already references all eight endpoints. Remaining work on those surfaces is UI-side consumption, not a backend wait.

Original note, kept as the dated record (2026-08-06): the governance services deploy ONLY via the operator-run ops/remediation/deploy_all.sh — no Deploy Router workflow watches their paths — so these endpoints were implemented, not serving until an operator redeployed the six services; until then the UI's tri-state rendered the honest upstream state (404 on the new paths) and kept its labeled illustrative fallbacks.

Implementation notes per the original constraints: - audit-replay recent: audit-chain records deliberately carry no tenant field (chain shape untouched) — tenant scoping is a JOIN (tenant's newest decisions → their proposal-time audit ids → full trails), never a filter that could leak refs. - action-runner outcomes: outcome docs are tenant-stamped forward-only at the execute path from 2026-08-06 (from the authorization's tenant); pre-stamp rows are not returned — operator-timed backfill extends coverage (GOVERNANCE 5.4 migration pattern). - decisions status filter validates against the Eligibility enum (422 on unknown) and filters only the RECORDED value — presentation only.

Original proposal text (2026-08-05) kept below for the record:

Why: Phase 1D live composition wired every read the services expose (approval pending queue, decision/passport lookup-by-id, audit verify/replay/ chain). The remaining Command Center surfaces need list/aggregate reads that do not exist. The UI will keep rendering labeled illustrative content for those sections until an owner accepts and ships the additions.

Common requirements for every proposed endpoint (matching the deployed services' existing conventions): - verify_caller + resolve_tenant; tenant-scoped, tenant REQUIRED (D6 class) - Bounded: limit capped server-side, cursor/offset pagination, newest-first - Read-only; no filter parameter may weaken a validation battery (D-class: no caller-selected subsets) - Standard /health /readyz untouched

Per-service proposals

Service Proposed endpoint Consumer surface Rationale
decision-control-plane GET /api/v1/decisions?tenant_id=&status=&limit=&cursor= /command-center/decisions queue Only GET /decision/{id} exists — operators cannot see the queue without already knowing each id
decision-control-plane GET /api/v1/decisions/summary?tenant_id= (counts by status/domain, DEL distribution buckets) Overview tiles Honest live tiles need aggregates; today any "N pending decisions" tile would be fabrication
approval-routing GET /api/v1/history?tenant_id=&limit=&cursor= (resolved approvals: approved/denied/expired w/ approver + resolved_at) Approvals "recently resolved" Only pending is readable — resolved records are written but not listable
audit-replay GET /api/v1/recent?tenant_id=&limit=&cursor= (recent audit records) Audit table (replaces the illustrative example traces) Replay requires a known audit id; there is no way to discover recent ids
validation-orchestrator GET /api/v1/passports?tenant_id=&limit=&cursor= Validation surfaces (2A) Lookup-by-id only today
action-runner GET /api/v1/outcomes?tenant_id=&limit=&cursor= + GET /api/v1/actuators (registry w/ stage + ceiling) Action center (authorization lifecycle, Stage-3/4 truth) Outcome records and the actuator stage ledger are written but not listable; the Action center cannot render honest lifecycle state without them
policy-engine GET /api/v1/policies (read-only active policy set + thresholds/version) Policy center (read-only) Evaluation exists; the active policy inventory is not readable
canonical-ingestion (none — events/point-in-time suffices for the evidence explorer) — —

Explicitly NOT proposed

Process

Backend scope belongs to the service owners. Acceptance path per the repo's governance: owner picks up a row → implements in services/service-* with the existing verify_caller/resolve_tenant/store conventions + contract tests → deploys via ops/remediation → the UI's Phase 1D wiring consumes it through the existing typed adapter (one function + one contract-table row per endpoint). Until then the affected UI sections stay labeled illustrative.

← All docsView source on GitHub →