Files
inter-hub/docs/contracts/ops-hub-activity-core-event-payloads.md

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

  • widgetId must be a UUID for an existing ops-hub widget.
  • eventType must exist in Inter-Hub's event type registry.
  • If the API consumer is bound to an active ops-hub manifest, eventType must be declared by that manifest.
  • viewContext should be ops-inventory-probe unless a more specific context is useful, such as ops-inventory-probe/endpoints.
  • metadata.type must match the Inter-Hub eventType.
  • metadata.version must match the activity-core event definition version.
  • metadata.publisher must be activity-core.
  • metadata.attributes.idempotency_key is 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:

  • ok
  • degraded
  • down
  • skipped

Use reason for compact machine-readable explanations, for example:

  • expected_status_mismatch
  • expected_signal_missing
  • unsupported_access_path_type
  • backup_probe_not_implemented
  • missing_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.