Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions docs/event-ui-conformance-harness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Event UI conformance harness

Shared regression contract for mapping public Traverse embedder events to UI
presentation state (Specs
[`001`](specs/001-ui-event-state-conformance/spec.md) /
[`002`](specs/002-capability-event-ui-subscription/spec.md), ADR
[`0001`](adr/0001-event-fixture-harness-first.md)).

## Fixtures (language-agnostic)

Path: [`fixtures/event-ui-conformance/`](../fixtures/event-ui-conformance/)

| Case | Expected state |
|---|---|
| `happy-path.json` | `loaded` |
| `error-path.json` | `error` |
| `blocked-path.json` | `blocked` |
| `ended-path.json` | `ended` |
| `multi-capability.json` | `loaded` (+ ordered capability progress) |
| `replay-late-subscriber.json` | `loaded` (prefix replay ≡ full map) |

Catalog index: `fixtures/event-ui-conformance/catalog.json`.

Fixtures are static JSON — no network calls.

## TypeScript package

Workspace: `packages/event-ui-conformance` (`event-ui-conformance`).

```ts
import {
loadFixtureCase,
mapCapabilityProgress,
mapPresentationState,
} from 'event-ui-conformance'

const fixture = loadFixtureCase('happy-path.json')
const ui = mapPresentationState(fixture.events)
// ui.state === 'loaded'; ui.output from capability_result only

const progress = mapCapabilityProgress(fixture.events)
```

Primary apps should import these helpers (or re-run the same fixtures with a
platform-native mapper) rather than inventing per-app event→state tables.

## Architecture boundary

- Subscribe / consume only public embedder envelopes (`state_changed`,
`capability_invoked`, `capability_result`, `error`).
- Do **not** emit synthetic embedder events from production app code.
- Do **not** invent business fields in the UI; render runtime-provided `output`.
20 changes: 20 additions & 0 deletions fixtures/event-ui-conformance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Event UI conformance fixtures

Language-agnostic embedder event streams for Specs
[`001-ui-event-state-conformance`](../../docs/specs/001-ui-event-state-conformance/spec.md) and
[`002-capability-event-ui-subscription`](../../docs/specs/002-capability-event-ui-subscription/spec.md).

| Case | File | Expected presentation state |
|---|---|---|
| Happy path | `happy-path.json` | `loaded` |
| Error path | `error-path.json` | `error` |
| Blocked path | `blocked-path.json` | `blocked` |
| Ended path | `ended-path.json` | `ended` |
| Multi-capability | `multi-capability.json` | `loaded` |
| Replay / late subscriber | `replay-late-subscriber.json` | `loaded` |

Index: [`catalog.json`](./catalog.json).

TypeScript mappers and Vitest consumers live in
[`packages/event-ui-conformance`](../../packages/event-ui-conformance/).
See [`docs/event-ui-conformance-harness.md`](../../docs/event-ui-conformance-harness.md).
40 changes: 40 additions & 0 deletions fixtures/event-ui-conformance/blocked-path.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"id": "blocked-path",
"description": "Runtime state_changed with waiting-for-human → blocked",
"expected_presentation_state": "blocked",
"expected_error_message": null,
"events": [
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0001",
"sequence": 1,
"event_type": "capability_invoked",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-blocked",
"data": {
"execution_id": "exec_blocked",
"capability_id": "fixture.approve",
"capability_version": "1.0.0"
}
},
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0002",
"sequence": 2,
"event_type": "state_changed",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-blocked",
"data": {
"state": "waiting_for_human",
"previous_state": "running",
"capability_id": "fixture.approve"
}
}
]
}
37 changes: 37 additions & 0 deletions fixtures/event-ui-conformance/catalog.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"schema_version": "1.0.0",
"description": "Shared embedder event streams for UI presentation-state + capability-progress conformance (Specs 001/002).",
"cases": [
{
"id": "happy-path",
"file": "happy-path.json",
"expected_presentation_state": "loaded"
},
{
"id": "error-path",
"file": "error-path.json",
"expected_presentation_state": "error"
},
{
"id": "blocked-path",
"file": "blocked-path.json",
"expected_presentation_state": "blocked"
},
{
"id": "ended-path",
"file": "ended-path.json",
"expected_presentation_state": "ended"
},
{
"id": "multi-capability",
"file": "multi-capability.json",
"expected_presentation_state": "loaded"
},
{
"id": "replay-late-subscriber",
"file": "replay-late-subscriber.json",
"expected_presentation_state": "loaded",
"notes": "Same ordered stream is mapped fully and via prefix replay; both must agree."
}
]
}
41 changes: 41 additions & 0 deletions fixtures/event-ui-conformance/ended-path.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"id": "ended-path",
"description": "Terminal capability_result with no renderable output → ended",
"expected_presentation_state": "ended",
"expected_error_message": null,
"events": [
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0001",
"sequence": 1,
"event_type": "capability_invoked",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-ended",
"data": {
"execution_id": "exec_ended",
"capability_id": "fixture.cancel",
"capability_version": "1.0.0"
}
},
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0002",
"sequence": 2,
"event_type": "capability_result",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-ended",
"data": {
"execution_id": "exec_ended",
"capability_id": "fixture.cancel",
"status": "completed",
"output": null
}
}
]
}
45 changes: 45 additions & 0 deletions fixtures/event-ui-conformance/error-path.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"id": "error-path",
"description": "capability_invoked then embedder error → error with payload message",
"expected_presentation_state": "error",
"expected_error_message": "capability failed under runtime governance",
"events": [
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0001",
"sequence": 1,
"event_type": "capability_invoked",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-error",
"data": {
"execution_id": "exec_error",
"capability_id": "fixture.process",
"capability_version": "1.0.0"
}
},
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0002",
"sequence": 2,
"event_type": "error",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-error",
"data": {
"execution_id": "exec_error",
"capability_id": "fixture.process",
"status": "error",
"error": {
"code": "execution_failed",
"message": "capability failed under runtime governance",
"details": {}
}
}
}
]
}
59 changes: 59 additions & 0 deletions fixtures/event-ui-conformance/happy-path.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"id": "happy-path",
"description": "Non-terminal progress then capability_result with renderable output → loaded",
"expected_presentation_state": "loaded",
"expected_error_message": null,
"events": [
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0001",
"sequence": 1,
"event_type": "state_changed",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-happy",
"data": {
"state": "running",
"previous_state": "idle"
}
},
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0002",
"sequence": 2,
"event_type": "capability_invoked",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-happy",
"data": {
"execution_id": "exec_happy",
"capability_id": "fixture.process",
"capability_version": "1.0.0"
}
},
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0003",
"sequence": 3,
"event_type": "capability_result",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-happy",
"data": {
"execution_id": "exec_happy",
"capability_id": "fixture.process",
"status": "completed",
"output": {
"title": "runtime-owned title",
"summary": "fields come only from the fixture output"
}
}
}
]
}
84 changes: 84 additions & 0 deletions fixtures/event-ui-conformance/multi-capability.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"id": "multi-capability",
"description": "Two capabilities invoke→result in order; terminal output from B only",
"expected_presentation_state": "loaded",
"expected_error_message": null,
"expected_capability_order": [
{ "capability_id": "fixture.analyze", "phase": "invoked" },
{ "capability_id": "fixture.analyze", "phase": "result" },
{ "capability_id": "fixture.recommend", "phase": "invoked" },
{ "capability_id": "fixture.recommend", "phase": "result" }
],
"events": [
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0001",
"sequence": 1,
"event_type": "capability_invoked",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-multi",
"data": {
"execution_id": "exec_a",
"capability_id": "fixture.analyze",
"capability_version": "1.0.0"
}
},
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0002",
"sequence": 2,
"event_type": "capability_result",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-multi",
"data": {
"execution_id": "exec_a",
"capability_id": "fixture.analyze",
"status": "completed",
"output": {
"analysis": "runtime-owned analysis"
}
}
},
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0003",
"sequence": 3,
"event_type": "capability_invoked",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-multi",
"data": {
"execution_id": "exec_b",
"capability_id": "fixture.recommend",
"capability_version": "1.0.0"
}
},
{
"kind": "embedder_event",
"schema_version": "1.0.0",
"embedder_api_version": "embedder-api/1.0.0",
"event_id": "evt-0004",
"sequence": 4,
"event_type": "capability_result",
"workspace_id": "local-default",
"app_id": "fixture-app",
"session_id": "sess-multi",
"data": {
"execution_id": "exec_b",
"capability_id": "fixture.recommend",
"status": "completed",
"output": {
"recommendation": "runtime-owned recommendation"
}
}
}
]
}
Loading
Loading