From d11912d460759370ff84861f53eeb2fa61303198 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sat, 27 Jun 2026 23:56:34 +0200 Subject: [PATCH] Define ops evidence contract --- docs/specs/README.md | 1 + docs/specs/ops-evidence-contract.md | 173 ++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 docs/specs/ops-evidence-contract.md diff --git a/docs/specs/README.md b/docs/specs/README.md index ec5b192..def4c7c 100644 --- a/docs/specs/README.md +++ b/docs/specs/README.md @@ -11,6 +11,7 @@ This directory is the specification map for Core Hub. The specs are intentionall - [Contract Governance](contract-governance.md) - how contract changes are reviewed and recorded - [Data Model](data-model.md) - initial entity model and migration posture - [Event and Registry Model](event-and-registry-model.md) - event catalogs, manifests, widgets, and capability registries +- [Ops Evidence Contract](ops-evidence-contract.md) - runtime evidence resources, event vocabulary, read-model gaps, and non-secret mapping rules - [Auth, Access, and Custody](auth-access-and-custody.md) - API auth semantics and secret routing rules - [Workplan Coordination](workplan-coordination.md) - file-first workplans, tasks, progress, messages, decisions - [UI and Operator Console](ui-operator-console.md) - whynot-design aligned UI direction diff --git a/docs/specs/ops-evidence-contract.md b/docs/specs/ops-evidence-contract.md new file mode 100644 index 0000000..f280640 --- /dev/null +++ b/docs/specs/ops-evidence-contract.md @@ -0,0 +1,173 @@ +# Ops Evidence Contract + +## Purpose + +Define the Core Hub-owned operations evidence contract that replaces the old +standalone ops-hub model list from `CUST-WP-0025-T14`. + +This contract reconciles the Custodian service inventory lane, Core Hub v2 +registry resources, activity-core probe output, migration/cutover evidence, and +non-secret credential-custody rules. It is intentionally API-first: CLI and UI +surfaces must consume these resources instead of inventing their own evidence +shape. + +## Scope + +In scope: + +- runtime service and endpoint readiness evidence; +- Core Hub registry/bootstrap evidence for ops-hub replacement work; +- activity-core Core Hub sink proof; +- migration import, deployment, outcome, and cutover readiness evidence; +- non-secret credential and access metadata. + +Out of scope for this contract: + +- secret value retrieval or vending; +- SSH certificate issuance; +- operator approval itself; +- the full future ops-hub product boundary if post-cutover work proves a + separate service is needed. + +## Source Inputs + +| Source | Current artifact | Core Hub use | +| --- | --- | --- | +| Custodian service inventory | `CUST-WP-0047` service/location/evidence records | Seed widgets and interaction events; preserve source ids in metadata. | +| Core Hub v2 resources | hubs, manifests, API consumers, API keys, widgets, events, migration runs | Canonical API/read model for replacement evidence. | +| activity-core probe output | `core-hub-interaction-event` sink reports | Append `interaction_events` with source run and verification metadata. | +| Migration tooling | `scripts/core_hub_migrate.py`, `MigrationRun` | Store bundle hash, source, dry-run flag, counts, diagnostics, status. | +| Operator CLI | `deployed-smoke`, `ops-bootstrap-status`, `migration`, `readiness-summary` | Non-secret evidence report generator over the same API resources. | + +## Canonical API Resources + +### Implemented Now + +| Resource | API path | Purpose | Required non-secret fields | +| --- | --- | --- | --- | +| Hub | `/api/v2/hubs` | Domain hub or replacement runtime record. | id, slug, name, domain, hubKind, hubFamily, vsmFunction, vsmSystem, status. | +| Hub capability manifest | `/api/v2/hub-capability-manifests` | Declared widgets/events/scopes/endpoints for a hub. | id, hubId, hubSlug, manifestVersion, status, declared widget/event/policy lists. | +| API consumer | `/api/v2/api-consumers` | Runtime or operator consumer metadata. | id, slug, name, hubCapabilityManifestId, rate/quota values, keyPrefix, status. | +| API key issuance result | `/api/v2/api-consumers/{consumer_id}/api-keys` | One-time generated key plus stored hash/prefix. | returned full key only at creation; persist only id, consumer id, keyPrefix, hash, scopes, status. | +| Widget | `/api/v2/widgets` | Operator-facing evidence target/read model item. | id, hubId, name, widgetType, capabilityRef, viewContext, policyScope, status. | +| Interaction event | `/api/v2/interaction-events` | Append-only operational evidence. | id, widgetId, eventType, viewContext, metadata, createdAt if exposed. | +| Hub registry | `/api/v2/hub-registry` | Read model for hubs and manifests. | hubs[], hubCapabilityManifests[]. | +| Migration run | stored as `migration_runs` | Import/validate evidence. | id, source, schemaVersion, bundleSha256, dryRun, status, counts, diagnostics, createdAt. | + +### Required Read-Model Gaps + +These are the gaps that must close before broad UI expansion or cutover claims: + +| Gap | Required path or behavior | Why it matters | +| --- | --- | --- | +| Migration run read API | `GET /api/v2/migration-runs` and optional `GET /api/v2/migration-runs/{id}` | UI and readiness reports need to inspect import evidence without reading the database directly. | +| Deployment records | Replace deferred empty `/api/v2/deployment-records` with persisted non-secret deployment facts. | Deployed smoke and cutover readiness need image/tag/runtime state evidence. | +| Outcome signals | Replace deferred empty `/api/v2/outcome-signals` with persisted pass/fail/degraded signals. | Operator screens need to distinguish evidence from result interpretation. | +| Service inventory mapping | Persist or derive a mapping from Custodian service ids to Core Hub widget ids/events. | Lets `CUST-WP-0047` inventory become Core Hub evidence without losing provenance. | +| Interaction-event filters | Add query filters for `hubId`, `widgetId`, `eventType`, `viewContext`, and time window. | Needed for compact evidence streams and activity-core sink verification. | +| Registry containment summary | Expose counts and containment booleans now computed by smoke reports. | Avoids each CLI/UI consumer re-deriving the same readiness checks. | + +## Evidence Vocabulary + +Event types should be explicit and versioned through the catalog once promoted. +Initial operational event types: + +| Event type | Producer | Meaning | Required metadata | +| --- | --- | --- | --- | +| `ops-endpoint-verified` | deployed smoke, ops probe, operator CLI | A service endpoint or registry path responded as expected. | runId, source, endpoint label, status code or health state, verified boolean. | +| `core-hub-deployed-smoke` | `scripts/core_hub_deployed_smoke.py` | Deployed Core Hub API smoke result. | runId, hub id/slug, manifest id/status, API consumer id/status/keyPrefix, widget id/count, event id/type, registry containment booleans. | +| `core-hub-activity-sink-verified` | activity-core | activity-core posted and verified a Core Hub interaction event. | runId, widget id, event id, eventType, status, verified boolean, source workplan/task if available. | +| `core-hub-migration-validated` | migration CLI | A bundle validation completed without import. | source, schemaVersion, bundleSha256, dryRun true, counts, diagnostics summary. | +| `core-hub-migration-imported` | migration CLI | A non-dry-run import completed. | source, schemaVersion, bundleSha256, dryRun false, counts, diagnostics summary, migrationRunId. | +| `core-hub-cutover-gate` | operator CLI | A readiness summary evaluated a gate. | gate name, ok boolean, reason, evidence ids/counts, report path or State Hub progress id. | + +All event `metadata` and body fields must be non-secret. Allowed access metadata: + +- key prefixes; +- key hash algorithm labels or stored hash ids; +- OpenBao path/version labels only when they do not reveal values; +- route catalog ids; +- token accessor ids only when explicitly approved by the owning subsystem; +- Kubernetes Secret name and populated-key count, not secret data. + +Forbidden fields: + +- API keys, bearer tokens, SSH private keys, database passwords, OIDC refresh + tokens, cookie values, raw Authorization headers, or copied Secret manifests; +- one-time API key material after the creation response has left the operator + process; +- plaintext excerpts from secret files or OpenBao responses. + +## Service Inventory Mapping + +`CUST-WP-0047` service inventory rows map into Core Hub as follows: + +| Inventory concept | Core Hub target | +| --- | --- | +| service id / slug | `Hub.slug` when the service is itself a hub; otherwise `Widget.body.serviceId`. | +| service display name | `Hub.name` or `Widget.name`. | +| service domain/location | `Hub.domain`, `Widget.viewContext`, and event metadata. | +| evidence type | `InteractionEvent.eventType`. | +| evidence source path | `InteractionEvent.metadata.sourcePath` or `sourceWorkplan`. | +| readiness or blocker state | `Widget.status`, event metadata, and later outcome signals. | +| credential route | metadata route id only, never a credential value. | + +Mapping rules: + +- Keep original inventory ids in metadata so State Hub/Custodian references stay + traceable. +- Prefer one widget per operator-visible evidence target, not one widget per log + line. +- Append interaction events for observations; only change widget status when the + latest stable operator-facing state changes. +- Activity-core may append events to existing widgets only after the widget id + mapping is explicitly configured. + +## Readiness Summary Inputs + +`readiness-summary` is the cutover-facing aggregation. Required gates: + +| Gate | Source report | Required evidence | +| --- | --- | --- | +| deployed_api_smoke | `make deployed-smoke` or operator CLI deployed-smoke | ok true, runId, check count, event id. | +| staging_import | migration import report | ok true, dryRun false, bundleSha256, counts, migrationRunId. | +| activity_core_sink | activity-core sink report | at least one posted and verified event. | + +Optional but useful gate: + +- `legacy_inter_hub_reference`: explicit rollback/compatibility evidence while + Inter-Hub remains available. + +Cutover is not ready until every required gate is true and the operator records +an approval decision outside this contract. + +## API / CLI / UI Order + +1. API resources and read routes are canonical. +2. CLI wrappers generate and summarize evidence over the same API. +3. UI screens are read-heavy views over API and CLI-compatible summaries. + +The `/console` rebuild must not read migration tables directly once the +`migration-runs` API exists. + +## Implementation Backlog + +| Priority | Item | Acceptance | +| --- | --- | --- | +| P0 | Add migration run read routes. | `/api/v2/migration-runs` lists stored runs with source, bundle hash, dryRun, status, counts, diagnostics summary. | +| P0 | Add interaction-event filters. | API supports filtering by event type, widget id, view context, and time window. | +| P0 | Define service inventory import fixture. | A fixture maps at least one Custodian inventory service into a widget plus event with provenance metadata. | +| P1 | Persist deployment records. | `/api/v2/deployment-records` stops returning only an empty compatibility collection. | +| P1 | Persist outcome signals. | `/api/v2/outcome-signals` can store non-secret pass/fail/degraded signals linked to events or migration runs. | +| P1 | Registry readiness summary route. | API exposes counts/containment booleans used by deployed smoke and UI readiness overview. | + +## Acceptance For CUST-WP-0025-T14 + +This spec closes the T14 definition gate. Implementation remains in follow-up +Core Hub tasks and the deployed evidence gates: + +- `CUST-WP-0025-T16` for deployed Core Hub and activity-core smokes; +- `CUST-WP-0025-T17` for cutover/legacy coupling; +- `CUST-WP-0025-T18` for the UI rebuild after API/CLI evidence is stable; +- `CORE-WP-0005` for staging import and cutover readiness; +- future Core Hub work for the P0/P1 read-model gaps above.