Preview: Quoderat is in early access. This site shows the concept and direction — onboarding is manual for now.
Quoderat

Events (SSE)

Events are ephemeral signals for live monitoring. The Evidence Envelope is the authoritative record.

What this page can (and cannot) claim

Mechanical claims

  • Real-time visibility: best-effort, low-latency stream of state changes during execution.
  • Typed signals: events are categorized (e.g., run_started, step_started, step_finished, needs_input).
  • Correlation: events include identifiers (#runId, #stepId, #gateId) to correlate UI state with an active run.
  • Finalization notification: the stream can indicate that an envelope is ready to fetch (run_finalized with #evidenceId).

No-claims

  • No guaranteed ordering: events may arrive out of sequence.
  • No exactly-once delivery: duplicates and gaps can occur.
  • No tamper-proof stream: SSE is transport-only (not sealed/signed).
  • No replay authority: the stream is not your audit history; the envelope is.

Two timelines: Stream vs. Record

FeatureEvents (SSE stream)Evidence Envelope (JSON record)
PersistenceEphemeral / transientPermanent / auditable
IntegrityTransport-onlySealed (RFC 8785 JCS + hash chain)
PurposeUX, progress monitoringVerification, compliance, audit
AuthorityInformational hintsAuthoritative proof
Consumer behaviorUpdate UI stateFetch, validate, store, decide

Typical event shapes (illustrative)

Illustrative only; not a strict schema. The envelope is the source of truth.

run_started

{ "type": "run_started", "run_id": "#runId", "timestamp": "..." }

step_started

{ "type": "step_started", "run_id": "#runId", "step_id": "#stepId", "kind": "test", "timestamp": "..." }

step_finished

{ "type": "step_finished", "run_id": "#runId", "step_id": "#stepId", "kind": "test", "exit_code": 0, "timestamp": "..." }

needs_input

{ "type": "needs_input", "run_id": "#runId", "gate_id": "#gateId", "reason": "Human approval required" }

run_finalized

{ "type": "run_finalized", "run_id": "#runId", "evidence_id": "#evidenceId", "timestamp": "..." }

run_failed / run_aborted

{ "type": "run_failed", "run_id": "#runId", "reason": "Step exited with non-zero", "status": "failed" }
{ "type": "run_aborted", "run_id": "#runId", "reason": "User cancelled", "status": "aborted" }

Consumer rules (recommended)

  • Events are UX hints only: never make audit-critical decisions based on events alone.
  • Idempotency: design consumers to tolerate duplicates and replays after reconnect.
  • On run_finalized: fetch the envelope, then validate integrity.hash_chain; only then treat it as evidence.
  • Fallback: if the final event is missing, poll run status and attempt to fetch the envelope.
  • Event-only data is non-existent for audit: if it's not in the envelope, ignore it for proof.

Mapping signals → envelope fields

step_* events correlate to execution.steps[] in the finalized envelope.

exit_code is recorded on the step entry in the envelope (authoritative).

Timestamps/durations: treat the envelope as the source of truth; do not audit based on event timestamps.

run_finalized means the envelope should now contain integrity.hash_chain and be in a “Still” state.

Failure modes you will see

Disconnects / timeouts

Long-lived connections may drop. Auto-reconnect; resume by querying current run status.

Server restarts

Stream terminates. Recover via API status poll + envelope fetch.

Gaps / duplicates / out-of-order

Expected behavior. UI must tolerate non-linear transitions.

Retries causing repeated step_started

Implement idempotent reducers; deduplicate by #runId + #stepId.

Stream not signed

Never treat SSE as tamper-evident. The envelope is the sealed record.

Troubleshooting checklist

“UI shows success but no envelope”

Finalization or storage failed. Check server finalization logs.

“No events arriving”

Auth, network, or proxy may be blocking SSE. Check CORS and connection headers.

“Stuck in needs_input

Gate pending resolution. User action or external approval required to proceed.

“Out-of-order events”

Expected behavior. UI must handle non-linear state transitions gracefully.

Next steps