10 KiB
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
- API resources and read routes are canonical.
- CLI wrappers generate and summarize evidence over the same API.
- 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-T16for deployed Core Hub and activity-core smokes;CUST-WP-0025-T17for cutover/legacy coupling;CUST-WP-0025-T18for the UI rebuild after API/CLI evidence is stable;CORE-WP-0005for staging import and cutover readiness;- future Core Hub work for the P0/P1 read-model gaps above.