generated from coulomb/repo-seed
6.9 KiB
6.9 KiB
Ops Hub Activity-Core Event Payloads
Date: 2026-06-15
Workplan: IHUB-WP-0022
Inter-Hub Request Shape
Activity-core should submit ops evidence through:
POST /api/v2/interaction-events
Authorization: Bearer ${OPS_HUB_KEY}
Content-Type: application/json
Each request body must use the Inter-Hub v2 interaction-event shape:
{
"widgetId": "<widget-uuid-from-OPS_HUB_WIDGET_MAPPING>",
"eventType": "ops-endpoint-verified",
"viewContext": "ops-inventory-probe",
"metadata": {
"type": "ops-endpoint-verified",
"version": "1.0",
"publisher": "activity-core",
"attributes": {}
}
}
Inter-Hub sets occurredAt on receipt. Activity-core must send the actual
probe timestamp as metadata.attributes.observed_at.
Shared Rules
widgetIdmust be a UUID for an existing ops-hub widget.eventTypemust exist in Inter-Hub's event type registry.- If the API consumer is bound to an active ops-hub manifest,
eventTypemust be declared by that manifest. viewContextshould beops-inventory-probeunless a more specific context is useful, such asops-inventory-probe/endpoints.metadata.typemust match the Inter-HubeventType.metadata.versionmust match the activity-core event definition version.metadata.publishermust beactivity-core.metadata.attributes.idempotency_keyis required, even though Inter-Hub does not currently enforce idempotency.- Duplicate tolerance is required on the reader side until Inter-Hub provides a unique idempotency constraint.
- Payloads must not include secrets, authorization headers, cookies, token-like values, private key material, raw response bodies, command output, or unredacted URL query strings.
Status Vocabulary
Use the activity-core status vocabulary:
okdegradeddownskipped
Use reason for compact machine-readable explanations, for example:
expected_status_mismatchexpected_signal_missingunsupported_access_path_typebackup_probe_not_implementedmissing_endpoint
Example: Service Observed
{
"widgetId": "<service-widget-uuid>",
"eventType": "ops-service-observed",
"viewContext": "ops-inventory-probe/services",
"metadata": {
"type": "ops-service-observed",
"version": "1.0",
"publisher": "activity-core",
"attributes": {
"activity_core_run_id": "12345678-aaaa-bbbb-cccc-123456789abc",
"idempotency_key": "12345678-aaaa-bbbb-cccc-123456789abc:state-hub:ops-service-observed",
"service_id": "state-hub",
"service_name": "State Hub",
"environment": "local",
"lifecycle_state": "observed",
"observed_status": "ok",
"observed_at": "2026-06-05T10:15:01Z"
}
}
}
Example: Endpoint Verified
{
"widgetId": "<endpoint-widget-uuid>",
"eventType": "ops-endpoint-verified",
"viewContext": "ops-inventory-probe/endpoints",
"metadata": {
"type": "ops-endpoint-verified",
"version": "1.0",
"publisher": "activity-core",
"attributes": {
"activity_core_run_id": "12345678-aaaa-bbbb-cccc-123456789abc",
"idempotency_key": "12345678-aaaa-bbbb-cccc-123456789abc:gitea:gitea-oci-registry:ops-endpoint-verified",
"service_id": "gitea",
"endpoint_id": "gitea-oci-registry",
"endpoint_type": "https",
"endpoint_url": "https://gitea.coulomb.social/v2/",
"expected_status": 401,
"status_code": 401,
"matched_expected_status": true,
"matched_expected_signal": true,
"observed_status": "ok",
"observed_at": "2026-06-05T10:15:01Z",
"widget_ref": "ops:endpoint:gitea-registry"
}
}
}
Example: Access Path Checked
{
"widgetId": "<access-path-widget-uuid>",
"eventType": "ops-access-path-checked",
"viewContext": "ops-inventory-probe/access-paths",
"metadata": {
"type": "ops-access-path-checked",
"version": "1.0",
"publisher": "activity-core",
"attributes": {
"activity_core_run_id": "12345678-aaaa-bbbb-cccc-123456789abc",
"idempotency_key": "12345678-aaaa-bbbb-cccc-123456789abc:gitea:gitea-access-1:ops-access-path-checked",
"service_id": "gitea",
"access_path_id": "gitea-access-1",
"access_path_type": "k8s",
"declared_status": "unknown",
"observed_status": "skipped",
"reason": "unsupported_access_path_type",
"observed_at": "2026-06-05T10:15:01Z"
}
}
}
Example: Backup Verified
{
"widgetId": "<backup-widget-uuid>",
"eventType": "ops-backup-verified",
"viewContext": "ops-inventory-probe/backups",
"metadata": {
"type": "ops-backup-verified",
"version": "1.0",
"publisher": "activity-core",
"attributes": {
"activity_core_run_id": "12345678-aaaa-bbbb-cccc-123456789abc",
"idempotency_key": "12345678-aaaa-bbbb-cccc-123456789abc:gitea:database:gitea-db:ops-backup-verified",
"service_id": "gitea",
"backing_store_ref": "database:gitea-db",
"backup_evidence_ref": "state-hub:progress:<progress-id>",
"restore_verified": false,
"observed_status": "skipped",
"reason": "backup_probe_not_implemented",
"observed_at": "2026-06-05T10:15:01Z"
}
}
}
Example: Inventory Drift
{
"widgetId": "<drift-widget-uuid>",
"eventType": "ops-inventory-drift",
"viewContext": "ops-inventory-probe/drift",
"metadata": {
"type": "ops-inventory-drift",
"version": "1.0",
"publisher": "activity-core",
"attributes": {
"activity_core_run_id": "12345678-aaaa-bbbb-cccc-123456789abc",
"idempotency_key": "12345678-aaaa-bbbb-cccc-123456789abc:gitea:gitea-oci-registry:ops-inventory-drift",
"service_id": "gitea",
"inventory_object_id": "gitea-oci-registry",
"drift_kind": "status_mismatch",
"declared_summary": "expected_status=401",
"observed_summary": "status_code=200",
"observed_status": "degraded",
"reason": "expected_status_mismatch",
"observed_at": "2026-06-05T10:15:01Z"
}
}
}
Expected API Errors
Activity-core should treat these as configuration or rollout errors:
| Error | Meaning | Recovery |
|---|---|---|
401 |
Missing or invalid OPS_HUB_KEY |
Check Secret provisioning; do not log the key. |
422 with unregistered_event_type |
Event type not in Inter-Hub registry | Activate the ops-hub manifest vocabulary. |
422 with event_type_not_in_manifest |
Runtime consumer manifest does not declare the event | Bind the consumer to the active manifest or activate a corrected manifest. |
422 with Widget not found |
Mapping points at a missing widget | Refresh OPS_HUB_WIDGET_MAPPING. |
422 with unregistered_policy_scope during widget seed |
Policy scope is absent | Declare and activate ops-evidence. |
For the first activity-core slice, a failed Inter-Hub submission should not fail the whole probe if State Hub fallback posting succeeds. It should return a compact sink result naming the non-secret failure class.