AISA v2.0 / Technical documentation / realtime-events.schema.json
realtime-events.schema.json
JSON · 55 lines · 4,117 bytes · wiki path 10 Architecture/contracts/realtime-events.schema.json · download the raw file · cited from Contracts · Developer implementation guide
Same folder: Connectors.Abstractions.cs · configuration-change.schema.json · configuration-input.schema.json · connector-capability.schema.json · eval-set.schema.json · execution-obligations.schema.json · ledger-record.schema.json · message-envelope.schema.json · model-turn.schema.json · module-manifest.schema.json · openapi.yaml · runtime-state.schema.json · validate_case_journeys.py · validate_contracts.py · validate_runtime_contracts.py · write-shape.schema.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://aisa.ablera.com/contracts/realtime-events.schema.json",
"title": "Realtime event catalogue (SignalR hub /ai-support/hub)",
"description": "Software Architecture § 7 Realtime: SignalR on the estate's proven topology — hub + one-use Redis ticket + HMAC group alias + Rabbit fan-out + transactional outbox (OUTBOX_MESSAGES). The UI subscribes per case (group 'case:<id>') and per role inbox (group 'gates:<role>'). Every event is a projection of ledger records already committed — a client that reconnects re-reads from /cases/{id}/cards?after=<seq_no>; events carry the cursor. Transcript lag target < 5 s; at most 10 notifications/s per client (ui.transcript). Payloads are references, never bodies.",
"type": "object",
"additionalProperties": false,
"required": ["event", "version", "occurred_on", "seq_no"],
"properties": {
"event": { "type": "string", "enum": [
"case.opened", "case.state.changed", "case.parked", "case.resumed", "case.controller.changed", "case.viewers.changed",
"card.appended",
"gate.opened", "gate.decided", "gate.escalated", "gate.expired",
"held_batch.changed",
"shape.state.changed",
"arrival.received", "arrival.decided",
"connector.health.changed",
"budget.warning", "budget.stop",
"kill_switch.changed",
"ledger.export.lag",
"eval_run.finished", "governance.changed",
"client.request.changed" ] },
"version": { "type": "integer", "const": 1 },
"occurred_on": { "type": "string", "format": "date-time" },
"seq_no": { "type": "integer", "description": "the ledger SEQ_NO of the record this event projects — the reconnect cursor" },
"case_id": { "type": "string" },
"group": { "type": "string", "description": "the SignalR group it was fanned out to: case:<id> · gates:<role> · control · client:<customer>" },
"ref": {
"type": "object", "additionalProperties": false,
"description": "references only; the client fetches detail over HTTP",
"properties": {
"card_seq_no": { "type": "integer" }, "gate_id": { "type": "string" }, "arrival_id": { "type": "string" },
"batch_id": { "type": "string" }, "shape_id": { "type": "string" }, "eval_run_id": { "type": "string" },
"connector": { "type": "string" }, "environment": { "type": "string" }, "subject": { "type": "string" }, "key": { "type": "string" }, "version": { "type": "integer" }
}
},
"state": { "type": "string", "description": "the new state, for *.state.changed / parked / health events" },
"reason": { "type": "string" },
"actor": { "type": "object", "properties": { "kind": { "type": "string", "enum": ["agent", "person", "policy", "system"] }, "id": { "type": "string" } } },
"where": { "type": "object", "properties": { "environment": { "type": "string" }, "system": { "type": "string" }, "object": { "type": "string" }, "mode": { "type": "string" } } }
},
"allOf": [
{ "if": { "properties": { "event": { "const": "card.appended" } } }, "then": { "required": ["case_id", "ref"], "properties": { "ref": { "required": ["card_seq_no"] } } } },
{ "if": { "properties": { "event": { "pattern": "^gate\\." } } }, "then": { "required": ["case_id", "ref"], "properties": { "ref": { "required": ["gate_id"] } } } },
{ "if": { "properties": { "event": { "pattern": "^case\\." } } }, "then": { "required": ["case_id"] } },
{ "if": { "properties": { "event": { "const": "connector.health.changed" } } }, "then": { "required": ["ref", "state"], "properties": { "ref": { "required": ["connector", "environment"] } } } }
],
"x-hub": {
"url": "/ai-support/hub",
"auth": "one-use ticket from POST /ai-support/api/v1/realtime/ticket (Authority JWT) — case-keyed; the ticket carries the role set",
"client_methods": ["Subscribe(caseId)", "Unsubscribe(caseId)", "SubscribeGates()", "SubscribeControl()"],
"server_methods": ["Event(payload)"],
"reconnect": "re-read /cases/{id}/cards?after=<last seq_no>; the hub never replays"
}
}