> ## Documentation Index
> Fetch the complete documentation index at: https://www.agentworldprotocol.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Requirement matrix

> Every normative requirement with its side, applicability, feature gate, and test.

<Note>
  219 requirements: 153 world-side, 15 agent-side, 51 both. 204 MUST, 8 SHOULD, 7 MAY. 5 require manual evidence; 10 are process or deployment policy and are not tested by the suite. CI fails if a bracketed ID in the specification has no row here, or a row names an ID the specification no longer defines.
</Note>

**Columns.** *Side*: who must implement it. *Applies*: time model(s) it applies to. *Gate*: `core` (every conformant implementation), `core (streaming)` / `core (non-loopback)` (Core when that mode is offered), `profile:<name>`, `capability:<key>` (only when the manifest advertises the key, AWP-VER-007), or `feature:<condition>`. *Test*: the conformance-suite assertion (named after the ID, AWP-CNF-004), `(warning)` for SHOULD, `manual:` for evidence attached to the report, `untestable:` for process rules.

## Actions — `AWP-ACT`

Defined in [/spec/loop/actions](/spec/loop/actions).

| ID                                | Level | Side  | Applies | Gate   | Test        | Requirement                                                                                                                                         |
| --------------------------------- | ----- | ----- | ------- | ------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-ACT-001](/spec/loop/actions) | MUST  | both  | all     | `core` | AWP-ACT-001 | `action_id` is client-generated and unique per session. A resubmission with the same `action_id` and identical `type`, `params`, `embodiment_id`,…  |
| [AWP-ACT-002](/spec/loop/actions) | MUST  | world | all     | `core` | AWP-ACT-002 | Worlds MUST validate `params` against the type's `params_schema` and reject invalid submissions with `AWP_PARAMS_INVALID` before any execution…     |
| [AWP-ACT-003](/spec/loop/actions) | MUST  | world | all     | `core` | AWP-ACT-003 | Submissions naming ungranted types or embodiments MUST be rejected with `AWP_FORBIDDEN`.                                                            |
| [AWP-ACT-004](/spec/loop/actions) | MUST  | world | all     | `core` | AWP-ACT-004 | `deadline_ms` is measured from the world's receipt of the submission and covers approval and queue waiting as well as execution. It is advisory in… |
| [AWP-ACT-005](/spec/loop/actions) | MUST  | world | all     | `core` | AWP-ACT-005 | The `preempt` field MUST be one of the policies the type declares (see preemption).                                                                 |
| [AWP-ACT-006](/spec/loop/actions) | MUST  | world | all     | `core` | AWP-ACT-006 | Worlds MUST retain the `action_id` and terminal state of every action for at least `reconnect_window_ms` after its terminal transition, and of…     |
| [AWP-ACT-007](/spec/loop/actions) | MUST  | both  | all     | `core` | AWP-ACT-007 | Basis and validity. `basis_ts_mono_ns` is the capture time of the newest observation the intent relies on, copied from that frame's `ts_mono_ns`;…  |

## Agent manifest — `AWP-AGM`

Defined in [/spec/session/agent-manifest](/spec/session/agent-manifest).

| ID                                          | Level  | Side  | Applies | Gate   | Test                  | Requirement                                                                             |
| ------------------------------------------- | ------ | ----- | ------- | ------ | --------------------- | --------------------------------------------------------------------------------------- |
| [AWP-AGM-001](/spec/session/agent-manifest) | MUST   | world | all     | `core` | AWP-AGM-001           | Worlds MUST NOT push modalities the agent did not declare in `consumes_modalities`.     |
| [AWP-AGM-002](/spec/session/agent-manifest) | SHOULD | world | all     | `core` | AWP-AGM-002 (warning) | Agents SHOULD declare a realistic `max_obs_rate_hz`; worlds MAY downsample to honor it. |

## Core agent — `AWP-AGT`

Defined in [/spec/profiles/core](/spec/profiles/core).

| ID                                 | Level | Side  | Applies | Gate   | Test        | Requirement                                                                                                                                         |
| ---------------------------------- | ----- | ----- | ------- | ------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-AGT-001](/spec/profiles/core) | MUST  | agent | all     | `core` | AWP-AGT-001 | Negotiate the protocol version and tolerate unknown fields (AWP-VER-002..003).                                                                      |
| [AWP-AGT-002](/spec/profiles/core) | MUST  | agent | all     | `core` | AWP-AGT-002 | Parse the world manifest and refuse to open a session against a manifest it cannot validate against the canonical schema.                           |
| [AWP-AGT-003](/spec/profiles/core) | MUST  | agent | all     | `core` | AWP-AGT-003 | Submit only granted action types on granted embodiments and subscribe only to granted channels (AWP-PRM-001).                                       |
| [AWP-AGT-004](/spec/profiles/core) | MUST  | agent | all     | `core` | AWP-AGT-004 | Generate unique `action_id`s and resubmit only with identical content (AWP-ACT-001).                                                                |
| [AWP-AGT-005](/spec/profiles/core) | MUST  | agent | all     | `core` | AWP-AGT-005 | Handle every lifecycle state, including `pending_approval`, `queued`, `cancelling`, and `preempted`, and deduplicate redelivered statuses on…       |
| [AWP-AGT-006](/spec/profiles/core) | MUST  | agent | all     | `core` | AWP-AGT-006 | Send heartbeats at the negotiated interval carrying `origin_ns`, answer the world's pings with `receive_ns` and `transmit_ns`, and in lockstep…     |
| [AWP-AGT-007](/spec/profiles/core) | MUST  | agent | all     | `core` | AWP-AGT-007 | On `session.resume`, pass `last_status_seq` and treat the embodiment as being in safe state until a new action executes (AWP-CTL-008, AWP-SAF-008). |
| [AWP-AGT-008](/spec/profiles/core) | MUST  | agent | all     | `core` | AWP-AGT-008 | Maintain the clock-offset estimate from heartbeat exchanges and express every agent-originated session-clock value through it (AWP-CLK-008,…        |
| [AWP-AGT-009](/spec/profiles/core) | MUST  | agent | all     | `core` | AWP-AGT-009 | Expose `world.tick` as an explicit call and never advance time as a side effect of any other operation; an SDK helper that submits and ticks in…    |

## Approval — `AWP-APR`

Defined in [/spec/safety/approval](/spec/safety/approval).

| ID                                   | Level | Side  | Applies | Gate                        | Test                                     | Requirement                                                                                                                                         |
| ------------------------------------ | ----- | ----- | ------- | --------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-APR-001](/spec/safety/approval) | MUST  | world | all     | `feature:requires_approval` | AWP-APR-001                              | Action types marked `requires_approval: true` enter the `pending_approval` state after validation and before `accepted`. The world emits…           |
| [AWP-APR-002](/spec/safety/approval) | MUST  | world | all     | `feature:requires_approval` | AWP-APR-002                              | The approver responds via `safety.approval.respond` (`approve` `deny`). Approve → `accepted` (or `queued` if the concurrency group is busy and the… |
| [AWP-APR-003](/spec/safety/approval) | MUST  | world | all     | `feature:requires_approval` | AWP-APR-003                              | Approvals time out after `approval_timeout_ms` (safety policy; default 60000) → `rejected` with reason `approval_timeout`. If the submission's own… |
| [AWP-APR-004](/spec/safety/approval) | MUST  | world | all     | `feature:requires_approval` | AWP-APR-004                              | Approvals are per-action; worlds MAY support scoped standing approvals (type + parameter predicate + expiry), which MUST appear in the audit log.   |
| [AWP-APR-005](/spec/safety/approval) | MUST  | world | all     | `feature:requires_approval` | untestable: process or deployment policy | Who may approve is deployment configuration, out of protocol scope; the protocol only defines the messages and states.                              |
| [AWP-APR-006](/spec/safety/approval) | MUST  | world | all     | `feature:requires_approval` | AWP-APR-006                              | Approval request content is subject to the audit redaction rules (AWP-AUD-006): `params` fields and the task text listed in…                        |

## Audit log — `AWP-AUD`

Defined in [/spec/safety/audit-log](/spec/safety/audit-log).

| ID                                    | Level  | Side  | Applies | Gate   | Test                                           | Requirement                                                                                                                                        |
| ------------------------------------- | ------ | ----- | ------- | ------ | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-AUD-001](/spec/safety/audit-log) | MUST   | world | all     | `core` | AWP-AUD-001                                    | Worlds MUST record, per session, an append-only log of: manifests, granted subset, every control-channel message (both directions, after…          |
| [AWP-AUD-002](/spec/safety/audit-log) | MUST   | world | all     | `core` | AWP-AUD-002                                    | Records are JSON Lines; each record carries `ts_mono_ns`, `direction`, `kind`, and `body`.                                                         |
| [AWP-AUD-003](/spec/safety/audit-log) | SHOULD | world | all     | `core` | AWP-AUD-003 (warning)                          | Worlds SHOULD hash-chain records (`prev_hash`) for tamper evidence.                                                                                |
| [AWP-AUD-004](/spec/safety/audit-log) | MUST   | world | all     | `core` | untestable: process or deployment policy       | Retention policy is deployment-defined; the format is normative so logs are portable across tools.                                                 |
| [AWP-AUD-005](/spec/safety/audit-log) | MUST   | world | all     | `core` | AWP-AUD-005 (replay bundle drives AWP-REP-003) | Logs with full payloads plus a starting snapshot are sufficient for deterministic replay on worlds that advertise it.                              |
| [AWP-AUD-006](/spec/safety/audit-log) | MUST   | world | all     | `core` | AWP-AUD-006                                    | Before a control-channel message is written to the log, the world MUST replace the values of `session_token`, `transfer_token`, `snapshot_token`,… |
| [AWP-AUD-007](/spec/safety/audit-log) | MUST   | world | all     | `core` | AWP-AUD-007                                    | The same JSONL format serves three purposes with different completeness requirements. Tooling MUST label which class a file satisfies (`"class"`…  |

## Realtime A/V profile — `AWP-AV`

Defined in [/spec/profiles/realtime-av](/spec/profiles/realtime-av).

| ID                                       | Level | Side  | Applies | Gate                  | Test       | Requirement                                                                                                                                  |
| ---------------------------------------- | ----- | ----- | ------- | --------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-AV-001](/spec/profiles/realtime-av) | MUST  | world | all     | `profile:realtime-av` | AWP-AV-001 | Media channels: the world MUST offer at least one `image/*` channel at ≥ 15 Hz or one continuous `audio/pcm` channel, and each MUST declare… |
| [AWP-AV-002](/spec/profiles/realtime-av) | MUST  | world | all     | `profile:realtime-av` | AWP-AV-002 | Every `session.telemetry` notification MUST carry a `channels` entry for every media channel that sent frames in its window — AWP-TIM-006.   |

## Timestamps and clocks — `AWP-CLK`

Defined in [/spec/semantics/timestamps-and-clocks](/spec/semantics/timestamps-and-clocks).

| ID                                                   | Level | Side  | Applies | Gate   | Test        | Requirement                                                                                                                                        |
| ---------------------------------------------------- | ----- | ----- | ------- | ------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-CLK-001](/spec/semantics/timestamps-and-clocks) | MUST  | both  | all     | `core` | AWP-CLK-001 | All timestamps are `ts_mono_ns`: nanoseconds on the session monotonic clock, which starts ≥0 at session open and never goes backward.              |
| [AWP-CLK-002](/spec/semantics/timestamps-and-clocks) | MUST  | both  | all     | `core` | AWP-CLK-002 | `session.ready` carries a `clock_anchor`: the wall-clock time (RFC 3339, UTC) corresponding to monotonic 0, letting logs correlate across systems. |
| [AWP-CLK-003](/spec/semantics/timestamps-and-clocks) | MUST  | both  | all     | `core` | AWP-CLK-003 | Simulated worlds additionally carry `ts_sim_ns` (i64) on frames when sim time diverges from the monotonic clock (fast-forward, slow-mo), and…      |
| [AWP-CLK-004](/spec/semantics/timestamps-and-clocks) | MUST  | both  | all     | `core` | AWP-CLK-004 | Timestamps mark capture time (observation frames), event time (statuses and events), and issue time (command frames), never send time; send time…  |
| [AWP-CLK-005](/spec/semantics/timestamps-and-clocks) | MUST  | both  | all     | `core` | AWP-CLK-005 | In JSON, all timestamp and counter fields are integers bounded by 2^53 − 1 (AWP-CTL-009). Because the session clock starts at 0 this permits…      |
| [AWP-CLK-006](/spec/semantics/timestamps-and-clocks) | MUST  | agent | all     | `core` | AWP-CLK-006 | Agent clock. The agent keeps its own monotonic nanosecond counter, the agent clock, starting ≥0 and bounded per AWP-CTL-009. It appears on the…    |
| [AWP-CLK-007](/spec/semantics/timestamps-and-clocks) | MUST  | both  | all     | `core` | AWP-CLK-007 | Exchange. `ping` carries `origin_ns`, the sender's clock at transmission; its result carries `origin_ns` echoed, `receive_ns`, the responder's…    |
| [AWP-CLK-008](/spec/semantics/timestamps-and-clocks) | MUST  | agent | all     | `core` | AWP-CLK-008 | Estimate. On receipt of the result the initiator records `destination_ns`, its clock at receipt, and computes \`rtt\_ns = (destination\_ns −…      |
| [AWP-CLK-009](/spec/semantics/timestamps-and-clocks) | MUST  | agent | all     | `core` | AWP-CLK-009 | Agent-originated session timestamps. Every session-clock value the agent places on the wire that originates on its own clock — `ts_mono_ns` on…    |

## Command channels — `AWP-CMD`

Defined in [/spec/loop/command-channels](/spec/loop/command-channels).

| ID                                         | Level | Side  | Applies   | Gate                          | Test        | Requirement                                                                                                                                        |
| ------------------------------------------ | ----- | ----- | --------- | ----------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-CMD-001](/spec/loop/command-channels) | MUST  | world | streaming | `capability:command_channels` | AWP-CMD-001 | Command channels are gated on the `command_channels` capability, declared in the manifest's top-level `command_channels` list using the standard…  |
| [AWP-CMD-002](/spec/loop/command-channels) | MUST  | world | streaming | `capability:command_channels` | AWP-CMD-002 | Every action schema naming a `command_channel` MUST declare `duration: "streaming"` and reference a declared command channel; a granted streaming… |
| [AWP-CMD-003](/spec/loop/command-channels) | MUST  | world | streaming | `capability:command_channels` | AWP-CMD-003 | Frames are accepted on a command channel only while exactly one bound action is `executing`; worlds MUST discard frames received outside such a…   |
| [AWP-CMD-004](/spec/loop/command-channels) | MUST  | world | streaming | `capability:command_channels` | AWP-CMD-004 | A streaming action never completes on its own: it remains `executing` while the stream is live and reaches a terminal state only via…              |
| [AWP-CMD-005](/spec/loop/command-channels) | MUST  | world | streaming | `capability:command_channels` | AWP-CMD-005 | Streaming action types MUST declare `watchdog_ms`. If no valid frame arrives within `watchdog_ms` while the action is `executing`, the world MUST… |
| [AWP-CMD-006](/spec/loop/command-channels) | MUST  | world | streaming | `capability:command_channels` | AWP-CMD-006 | Every inbound frame MUST be envelope-checked world-side before actuation (AWP-ENV-001): `clamp` executes at the limit; `reject` drops the frame.…  |
| [AWP-CMD-007](/spec/loop/command-channels) | MUST  | world | streaming | `capability:command_channels` | AWP-CMD-007 | Frames carry the standard frame envelope with per-channel monotonically increasing `seq` and `ts_mono_ns` as the setpoint's issue time on the…     |
| [AWP-CMD-008](/spec/loop/command-channels) | MUST  | world | streaming | `capability:command_channels` | AWP-CMD-008 | The audit log records inbound frames — payload or SHA-256 hash plus header — exactly as observation frames.                                        |

## Conformance — `AWP-CNF`

Defined in [/spec/conformance](/spec/conformance).

| ID                               | Level | Side  | Applies | Gate               | Test                                     | Requirement                                                                                                                                       |
| -------------------------------- | ----- | ----- | ------- | ------------------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-CNF-001](/spec/conformance) | MUST  | world | all     | `core`             | untestable: process or deployment policy | Core World — implements every MUST in the Core profile on the world side.                                                                         |
| [AWP-CNF-002](/spec/conformance) | MUST  | world | all     | `core`             | untestable: process or deployment policy | Core Agent — implements every MUST in the Core profile on the agent side.                                                                         |
| [AWP-CNF-003](/spec/conformance) | MUST  | world | all     | `core`             | untestable: process or deployment policy | Profile conformance — a Core-conformant implementation additionally satisfying all MUSTs of a named profile. Claims are per-profile (e.g. "Core…  |
| [AWP-CNF-004](/spec/conformance) | MUST  | world | all     | `core`             | untestable: process or deployment policy | Every requirement ID has a row in the requirement matrix giving its side (world / agent / both), applicability (all / lockstep / streaming),…     |
| [AWP-CNF-005](/spec/conformance) | MUST  | world | all     | `core`             | untestable: process or deployment policy | Implementations MUST NOT claim "AWP-conformant" without passing the current suite for the claimed classes; while the suite is unpublished, any…   |
| [AWP-CNF-006](/spec/conformance) | MUST  | world | all     | `profile:robotics` | untestable: process or deployment policy | Profiles whose requirements depend on physical measurement — robotics in v0.1 — are experimental: no validated hardware harness exists, so their… |

## Control channel — `AWP-CTL`

Defined in [/spec/transport/control-channel](/spec/transport/control-channel).

| ID                                             | Level | Side | Applies | Gate   | Test        | Requirement                                                                                                                                               |
| ---------------------------------------------- | ----- | ---- | ------- | ------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-CTL-001](/spec/transport/control-channel) | MUST  | both | all     | `core` | AWP-CTL-001 | The control channel carries JSON-RPC 2.0 objects. Requests originate from either side; notifications (no `id`) are used for status and event pushes.      |
| [AWP-CTL-002](/spec/transport/control-channel) | MUST  | both | all     | `core` | AWP-CTL-002 | Method names are namespaced: `initialize`, `ping`, `world.*`, `session.*`, `task.*`, `obs.*`, `action.*`, `safety.*`. Unknown methods MUST return…        |
| [AWP-CTL-003](/spec/transport/control-channel) | MUST  | both | all     | `core` | AWP-CTL-003 | Per-direction ordering on the control channel MUST be preserved by the binding; recipients MUST NOT assume cross-direction ordering, nor ordering…        |
| [AWP-CTL-004](/spec/transport/control-channel) | MUST  | both | all     | `core` | AWP-CTL-004 | Heartbeats. `ping` is a JSON-RPC request either side may send, carrying `&#123; origin_ns &#125;`; its result is the pong, \`\{ origin\_ns, receive\_ns,… |
| [AWP-CTL-005](/spec/transport/control-channel) | MUST  | both | all     | `core` | AWP-CTL-005 | Reconnection. A lost control connection moves the session to `Suspended` and does not terminate it for `reconnect_window_ms` (declared in…                |
| [AWP-CTL-006](/spec/transport/control-channel) | MUST  | both | all     | `core` | AWP-CTL-006 | Batch requests MUST NOT be used.                                                                                                                          |
| [AWP-CTL-007](/spec/transport/control-channel) | MUST  | both | all     | `core` | AWP-CTL-007 | One session per connection. A control connection carries exactly one control channel and at most one session. A second `session.open` on a…               |
| [AWP-CTL-008](/spec/transport/control-channel) | MUST  | both | all     | `core` | AWP-CTL-008 | Every `action.status`, `world.event`, and `session.state` notification carries `status_seq`, a per-session integer that starts at 1 and increases…        |
| [AWP-CTL-009](/spec/transport/control-channel) | MUST  | both | all     | `core` | AWP-CTL-009 | 64-bit integers in JSON. `ts_mono_ns`, `ts_sim_ns`, `ts_send_ns`, `received_ts_mono_ns`, `basis_ts_mono_ns`, `valid_until_ns`, `origin_ns`,…              |

## Frames — `AWP-DAT`

Defined in [/spec/transport/frames](/spec/transport/frames).

| ID                                    | Level | Side | Applies | Gate   | Test                                           | Requirement                                                                                                                                         |
| ------------------------------------- | ----- | ---- | ------- | ------ | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-DAT-001](/spec/transport/frames) | MUST  | both | all     | `core` | AWP-DAT-001                                    | Frames MUST carry per-channel monotonically increasing `seq`; receivers detect loss by gaps.                                                        |
| [AWP-DAT-002](/spec/transport/frames) | MUST  | both | all     | `core` | AWP-DAT-002 (warning)                          | Channels declare their class in the manifest as `loss_class` (AWP-TRN-006): `reliable` (no loss permitted) or `latest-wins` (droppable; senders…    |
| [AWP-DAT-003](/spec/transport/frames) | MUST  | both | all     | `core` | AWP-DAT-003                                    | Senders MUST NOT exceed the negotiated per-channel rate; receivers MAY request a rate change via `obs.subscribe`.                                   |
| [AWP-DAT-004](/spec/transport/frames) | MUST  | both | all     | `core` | AWP-DAT-004                                    | Inline binding. In the `inline` binding a frame is carried as the params of an `obs.frame` (world→agent) or `cmd.frame` (agent→world) notification… |
| [AWP-DAT-005](/spec/transport/frames) | MUST  | both | all     | `core` | AWP-DAT-005                                    | Reserved flag bits. Senders MUST set flags bits 4–7 to zero. Receivers MUST ignore bits 4–7 and MUST NOT reject a frame because of them.            |
| [AWP-DAT-006](/spec/transport/frames) | MUST  | both | all     | `core` | AWP-DAT-006                                    | Extension block. Senders MUST set flags bit 2 if and only if an extension block is present, and MUST NOT emit two entries of the same type in one…  |
| [AWP-DAT-007](/spec/transport/frames) | MUST  | both | all     | `core` | AWP-DAT-007                                    | Metadata placement. `tick`, `ts_sim_ns`, and `ts_send_ns` MUST be carried in the extension block (binary) or as the named JSON fields (inline).…    |
| [AWP-DAT-008](/spec/transport/frames) | MUST  | both | all     | `core` | AWP-DAT-008 (schemas/test-vectors/frames.json) | Test vectors. Implementations MUST decode every vector in `schemas/test-vectors/frames.json` to the listed fields, and reject the vectors marked…   |
| [AWP-DAT-009](/spec/transport/frames) | MUST  | both | all     | `core` | AWP-DAT-009                                    | Resync. The `resync` flag (bit 3) marks the first frame a sender emits after a discontinuity it knows about — resumption (AWP-TRN-008), a keyframe… |

## Embodiments — `AWP-EMB`

Defined in [/spec/session/embodiments](/spec/session/embodiments).

| ID                                       | Level | Side  | Applies | Gate   | Test                              | Requirement                                                                                                                                        |
| ---------------------------------------- | ----- | ----- | ------- | ------ | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-EMB-001](/spec/session/embodiments) | MUST  | world | all     | `core` | AWP-EMB-001                       | Binding occurs at `session.open`; a non-shared embodiment already bound elsewhere yields `AWP_EMBODIMENT_UNAVAILABLE`.                             |
| [AWP-EMB-002](/spec/session/embodiments) | MUST  | world | all     | `core` | AWP-EMB-002                       | On session close or reconnect-window expiry, the world MUST release the embodiment after it has entered its declared safe state…                   |
| [AWP-EMB-003](/spec/session/embodiments) | MAY   | world | all     | `core` | AWP-EMB-003 (only if implemented) | Transfer. Worlds MAY support handoff: the receiving session calls `session.open` with `takeover: true` and a transfer token minted by the current… |
| [AWP-EMB-004](/spec/session/embodiments) | MUST  | world | all     | `core` | AWP-EMB-004                       | Observer sessions. A session with no embodiment binds observation grants only; action submission returns `AWP_FORBIDDEN`.                          |
| [AWP-EMB-005](/spec/session/embodiments) | MUST  | world | all     | `core` | AWP-EMB-005                       | Multiple embodiments per session are permitted when they share a `multi_bind_group` in the manifest; `session.open` then names them in…            |

## Envelopes — `AWP-ENV`

Defined in [/spec/safety/envelopes](/spec/safety/envelopes).

| ID                                    | Level | Side  | Applies | Gate                         | Test                                                      | Requirement                                                                                                                                      |
| ------------------------------------- | ----- | ----- | ------- | ---------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| [AWP-ENV-001](/spec/safety/envelopes) | MUST  | world | all     | `feature:envelopes declared` | AWP-ENV-001                                               | Enforcement is world-side and unconditional: no agent input may cause envelope violation.                                                        |
| [AWP-ENV-002](/spec/safety/envelopes) | MUST  | world | all     | `feature:envelopes declared` | AWP-ENV-002                                               | `on_violation` is `clamp` (execute at the limit, report `clamped: true` in status) or `reject` (`AWP_ENVELOPE_EXCEEDED`). Declared per envelope. |
| [AWP-ENV-003](/spec/safety/envelopes) | MUST  | world | all     | `feature:envelopes declared` | manual: requires physical disturbance and sensor evidence | Violations of physical envelopes during execution (external disturbance) MUST fail the action (reason `envelope`) and emit \`world.event:…       |
| [AWP-ENV-004](/spec/safety/envelopes) | MUST  | world | all     | `feature:envelopes declared` | AWP-ENV-004                                               | Rate limiting applies to `action.submit` admission; excess returns `AWP_ENVELOPE_EXCEEDED` with `retryable: true` and `retry_after_ms`.          |
| [AWP-ENV-005](/spec/safety/envelopes) | MUST  | world | all     | `feature:envelopes declared` | AWP-ENV-005                                               | Each envelope declares `enforcement`: `command_check` (requested commands are clamped or rejected before actuation; the default), `measured`…    |

## Errors — `AWP-ERR`

Defined in [/spec/loop/events-and-errors](/spec/loop/events-and-errors).

| ID                                          | Level | Side  | Applies | Gate   | Test        | Requirement                                                                                                                       |
| ------------------------------------------- | ----- | ----- | ------- | ------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-ERR-001](/spec/loop/events-and-errors) | MUST  | agent | all     | `core` | AWP-ERR-001 | Every error object marks `retryable: true false` in `data`. Agents MUST NOT retry non-retryable errors with identical parameters. |

## Events — `AWP-EVT`

Defined in [/spec/loop/events-and-errors](/spec/loop/events-and-errors).

| ID                                          | Level | Side  | Applies | Gate   | Test        | Requirement                                                                                                                                     |
| ------------------------------------------- | ----- | ----- | ------- | ------ | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-EVT-001](/spec/loop/events-and-errors) | MUST  | world | all     | `core` | AWP-EVT-001 | Worlds emit `world.event` notifications for state changes not tied to a specific action: `entity_appeared`, `entity_removed`, `collision`,…     |
| [AWP-EVT-002](/spec/loop/events-and-errors) | MUST  | world | all     | `core` | AWP-EVT-002 | `e_stop_engaged` MUST terminate every non-terminal action: `executing` actions → `failed` (reason `e_stop`); `pending_approval`, `queued`, and… |
| [AWP-EVT-003](/spec/loop/events-and-errors) | MUST  | world | all     | `core` | AWP-EVT-003 | `world.event` notifications travel only on the control channel, where `status_seq` orders them against action statuses and resumption replays…  |

## GUI profile — `AWP-GUI`

Defined in [/spec/profiles/gui](/spec/profiles/gui).

| ID                                | Level | Side  | Applies | Gate          | Test        | Requirement                                                                                                                                    |
| --------------------------------- | ----- | ----- | ------- | ------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-GUI-001](/spec/profiles/gui) | MUST  | world | all     | `profile:gui` | AWP-GUI-001 | Channels: a GUI world MUST offer `screenshot` (`image/jpeg` or `image/raw`) and at least one of `dom` or `a11y_tree` (`text/event+json`) with… |
| [AWP-GUI-002](/spec/profiles/gui) | MUST  | world | all     | `profile:gui` | AWP-GUI-002 | Action types: a GUI world MUST offer `pointer_move`, `pointer_click`, `key_input`, `scroll`, and `navigate` with the normative param schemas…  |
| [AWP-GUI-003](/spec/profiles/gui) | MUST  | world | all     | `profile:gui` | AWP-GUI-003 | Time model: streaming is REQUIRED; lockstep is OPTIONAL and, when offered, MUST follow the sim-profile lockstep rules (AWP-TIM-009..012) for…  |
| [AWP-GUI-004](/spec/profiles/gui) | MUST  | world | all     | `profile:gui` | AWP-GUI-004 | Approval: `navigate` to a URL outside the manifest's declared allowlist and every action class that enters credentials MUST be declared…       |
| [AWP-GUI-005](/spec/profiles/gui) | MUST  | world | all     | `profile:gui` | AWP-GUI-005 | Safe state: `safety_policy.safe_state.behavior` MUST be `hold` (no further input is injected) with `watchdog_ms` ≤ 10000.                      |

## Action lifecycle — `AWP-LIF`

Defined in [/spec/loop/action-lifecycle](/spec/loop/action-lifecycle).

| ID                                         | Level  | Side  | Applies | Gate   | Test                  | Requirement                                                                                                                                         |
| ------------------------------------------ | ------ | ----- | ------- | ------ | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-LIF-001](/spec/loop/action-lifecycle) | MUST   | world | all     | `core` | AWP-LIF-001           | The world MUST send an `action.status` notification on every transition after admission. Terminal states are `rejected`, `completed`, `failed`,…    |
| [AWP-LIF-002](/spec/loop/action-lifecycle) | MUST   | world | all     | `core` | AWP-LIF-002           | Admission acknowledgement. The `action.submit` result MUST report the post-validation state — `pending_approval`, `queued`, or `accepted` —…        |
| [AWP-LIF-003](/spec/loop/action-lifecycle) | SHOULD | world | all     | `core` | AWP-LIF-003 (warning) | During `executing`, worlds SHOULD send progress updates (`progress` ∈ \[0,1]) for `duration: extended` types at ≥1 Hz in streaming mode and at…     |
| [AWP-LIF-004](/spec/loop/action-lifecycle) | MUST   | world | all     | `core` | AWP-LIF-004           | `failed`, `rejected`, and `cancelled` statuses MUST carry a machine-readable `reason` from the status reason registry and MAY carry human-readable… |
| [AWP-LIF-005](/spec/loop/action-lifecycle) | MUST   | world | all     | `core` | AWP-LIF-005           | Cancellation. `action.cancel` on a pre-execution action transitions it directly to `cancelled` (reason `cancelled_by_agent`). On an `executing`…    |
| [AWP-LIF-006](/spec/loop/action-lifecycle) | MUST   | world | all     | `core` | AWP-LIF-006           | Replay. Undelivered `action.status` notifications MUST be replayed on `session.resume` according to the delivery contract.                          |
| [AWP-LIF-007](/spec/loop/action-lifecycle) | MUST   | world | all     | `core` | AWP-LIF-007           | Streaming duration. `duration: streaming` actions (command channels) have no self-completion: they remain `executing` while their stream is live…   |
| [AWP-LIF-008](/spec/loop/action-lifecycle) | MUST   | world | all     | `core` | AWP-LIF-008           | Precedence. When several terminating causes coincide, the world MUST apply the first that applies in this order: e-stop → safe-state entry →…       |
| [AWP-LIF-009](/spec/loop/action-lifecycle) | MUST   | both  | all     | `core` | AWP-LIF-009           | Transition vs delivery. A transition happens once, in the world, at a single `ts_mono_ns`. Its `action.status` notification MAY be delivered more…  |
| [AWP-LIF-010](/spec/loop/action-lifecycle) | MUST   | world | all     | `core` | AWP-LIF-010           | Abort bound. An action type MAY declare `max_abort_ms`; when it does, the world MUST report the terminal status of any `cancelling` action of that… |

## Multi-agent — `AWP-MA`

Defined in [/spec/multi-agent](/spec/multi-agent).

| ID                              | Level  | Side  | Applies | Gate                        | Test                             | Requirement                                                                                                                                    |
| ------------------------------- | ------ | ----- | ------- | --------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-MA-001](/spec/multi-agent) | MAY    | world | all     | `feature:multiple sessions` | AWP-MA-001 (only if implemented) | A world MAY host any number of concurrent sessions. Each session's grants and envelopes are independent.                                       |
| [AWP-MA-002](/spec/multi-agent) | SHOULD | world | all     | `feature:multiple sessions` | AWP-MA-002 (warning)             | Other agents' embodiments appear as ordinary entities in observations; worlds SHOULD tag such entities `"controlled_by": "session"` (without…  |
| [AWP-MA-003](/spec/multi-agent) | MUST   | world | all     | `feature:multiple sessions` | AWP-MA-003                       | An embodiment is bound to at most one session unless the world declares `shared_control` for it, in which case the world MUST document its…    |
| [AWP-MA-004](/spec/multi-agent) | MUST   | world | all     | `feature:multiple sessions` | AWP-MA-004                       | Worlds MUST isolate sessions: one session's subscriptions or errors MUST NOT alter another session's granted behavior.                         |
| [AWP-MA-005](/spec/multi-agent) | MUST   | world | all     | `feature:multiple sessions` | AWP-MA-005                       | Mutations that affect other sessions — `world.reset`, `world.restore`, and `world.tick` on a shared lockstep world — are administrative: they… |

## World manifest — `AWP-MAN`

Defined in [/spec/session/world-manifest](/spec/session/world-manifest).

| ID                                          | Level | Side  | Applies | Gate   | Test                                                                  | Requirement                                                                                                                                         |
| ------------------------------------------- | ----- | ----- | ------- | ------ | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-MAN-001](/spec/session/world-manifest) | MUST  | world | all     | `core` | AWP-MAN-001                                                           | Every `channel` and `action_type` referenced by an embodiment MUST be defined in the top-level lists.                                               |
| [AWP-MAN-002](/spec/session/world-manifest) | MUST  | world | all     | `core` | AWP-MAN-002 (schema: params\_schema validates as JSON Schema 2020-12) | `params_schema` values MUST be valid JSON Schema (2020-12).                                                                                         |
| [AWP-MAN-003](/spec/session/world-manifest) | MUST  | world | all     | `core` | AWP-MAN-003                                                           | Manifests MUST be stable for the life of the connection; changes require re-`initialize`.                                                           |
| [AWP-MAN-004](/spec/session/world-manifest) | MUST  | world | all     | `core` | AWP-MAN-004                                                           | `capabilities` is an open map. v0.1 standard keys: `seed`, `snapshot`, `replay`, `command_channels`, `task`. Unknown keys MUST be ignored; vendor…  |
| [AWP-MAN-005](/spec/session/world-manifest) | MUST  | world | all     | `core` | AWP-MAN-005                                                           | Worlds declaring the `command_channels` capability additionally list `command_channels` — agent→world channels, same schema as observation…         |
| [AWP-MAN-006](/spec/session/world-manifest) | MUST  | world | all     | `core` | AWP-MAN-006 (schema conditional)                                      | Worlds offering `lockstep` MUST declare `tick_policy` (`on_tick`) and `tick_authority` (`any_session` `barrier`); worlds offering `streaming` MUST… |
| [AWP-MAN-007](/spec/session/world-manifest) | MUST  | world | all     | `core` | AWP-MAN-007                                                           | Embodiments that may be bound together by one session share a `multi_bind_group`; `session.open` names them in `embodiments` and submissions then…  |

## Modalities — `AWP-MOD`

Defined in [/spec/semantics/modalities](/spec/semantics/modalities).

| ID                                        | Level | Side  | Applies | Gate   | Test                                     | Requirement                                                                                                  |
| ----------------------------------------- | ----- | ----- | ------- | ------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| [AWP-MOD-001](/spec/semantics/modalities) | MUST  | world | all     | `core` | AWP-MOD-001                              | Payloads MUST validate against the channel's declared modality and schema.                                   |
| [AWP-MOD-002](/spec/semantics/modalities) | MUST  | both  | all     | `core` | AWP-MOD-002                              | Vendor modalities use `x-&lt;vendor>.&lt;name>`; agents ignore channels whose modality they did not declare. |
| [AWP-MOD-003](/spec/semantics/modalities) | MUST  | world | all     | `core` | untestable: process or deployment policy | New standard modalities are added by RFD (MINOR version bump).                                               |

## Negotiation — `AWP-NEG`

Defined in [/spec/session/negotiation](/spec/session/negotiation).

| ID                                       | Level | Side  | Applies | Gate   | Test                              | Requirement                                                                                                                                         |
| ---------------------------------------- | ----- | ----- | ------- | ------ | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-NEG-001](/spec/session/negotiation) | MUST  | world | all     | `core` | AWP-NEG-001                       | The world resolves each request to a granted subset and MUST enumerate the outcome exactly in `session.ready` (granted channels with actual rates,… |
| [AWP-NEG-002](/spec/session/negotiation) | MUST  | world | all     | `core` | AWP-NEG-002                       | The world MUST reject `session.open` (not silently downgrade) when the requested time model is unsupported or the embodiment is unavailable:…       |
| [AWP-NEG-003](/spec/session/negotiation) | MAY   | world | all     | `core` | AWP-NEG-003 (only if implemented) | Channel rates MAY be granted lower than requested; action types are granted whole or not at all.                                                    |
| [AWP-NEG-004](/spec/session/negotiation) | MUST  | world | all     | `core` | AWP-NEG-004                       | Renegotiation: `obs.subscribe` adds or re-rates channels and `obs.unsubscribe` removes them mid-session; both return the session's complete…        |

## Observations — `AWP-OBS`

Defined in [/spec/loop/observations](/spec/loop/observations).

| ID                                     | Level | Side  | Applies   | Gate               | Test                  | Requirement                                                                                                                                        |
| -------------------------------------- | ----- | ----- | --------- | ------------------ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-OBS-001](/spec/loop/observations) | MUST  | world | all       | `core`             | AWP-OBS-001           | Every frame MUST carry: channel id, per-channel monotonically increasing `seq`, `ts_mono_ns` (session monotonic clock, time of capture), and a…    |
| [AWP-OBS-002](/spec/loop/observations) | MUST  | world | all       | `core`             | AWP-OBS-002           | In lockstep, per-tick channels additionally carry `tick` (u64) in the frame's extension block (type `0x01`) or as the `tick` field in the inline…  |
| [AWP-OBS-003](/spec/loop/observations) | MUST  | both  | all       | `core`             | AWP-OBS-003           | Worlds MUST NOT reorder frames within a channel; agents MUST tolerate interleaving across channels.                                                |
| [AWP-OBS-004](/spec/loop/observations) | MUST  | world | all       | `core`             | AWP-OBS-004           | A world MAY mark a frame `keyframe` (self-contained) vs delta; every channel using deltas MUST emit a keyframe at subscription start and at least… |
| [AWP-OBS-005](/spec/loop/observations) | MUST  | world | all       | `core`             | AWP-OBS-005           | On subscription, the first frame MUST be a current snapshot, not a historical replay.                                                              |
| [AWP-OBS-006](/spec/loop/observations) | MUST  | world | streaming | `core (streaming)` | AWP-OBS-006           | Send time. In streaming sessions every observation frame MUST carry `ts_send_ns`, the session-clock time at which the world handed the frame to…   |
| [AWP-OBS-007](/spec/loop/observations) | MUST  | agent | streaming | `core (streaming)` | AWP-OBS-007 (warning) | Receiver report. In streaming sessions the agent SHOULD send an `obs.report` notification (schema) at least every 5 s covering the preceding…      |

## Preemption — `AWP-PRE`

Defined in [/spec/loop/preemption](/spec/loop/preemption).

| ID                                   | Level | Side  | Applies | Gate   | Test                              | Requirement                                                                                                                                        |
| ------------------------------------ | ----- | ----- | ------- | ------ | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-PRE-001](/spec/loop/preemption) | MUST  | world | all     | `core` | AWP-PRE-001                       | Each action type declares its preemption policy in the manifest; the submitter selects one of the declared options per submission.                 |
| [AWP-PRE-002](/spec/loop/preemption) | MUST  | world | all     | `core` | AWP-PRE-002                       | `queue` New action enters the `queued` state and becomes `accepted` when the group frees, in submission order. Queue depth bounded by `max_queue`… |
| [AWP-PRE-003](/spec/loop/preemption) | MUST  | world | all     | `core` | AWP-PRE-003                       | `replace` Current `executing` action → `preempted` (after safe transition); current pre-execution actions in the group → `cancelled` (reason…      |
| [AWP-PRE-004](/spec/loop/preemption) | MUST  | world | all     | `core` | AWP-PRE-004                       | `blend` World merges trajectories (continuous control); both actions report status, the replaced one ends `preempted` with `blended: true`.        |
| [AWP-PRE-005](/spec/loop/preemption) | MUST  | world | all     | `core` | AWP-PRE-005                       | `reject` New submission is rejected with `AWP_BUSY` while one is `executing` or pre-execution in the group.                                        |
| [AWP-PRE-006](/spec/loop/preemption) | MAY   | world | all     | `core` | AWP-PRE-006 (only if implemented) | Concurrency groups. Each action type MAY name a `concurrency_group` (string) in its schema. Types sharing a group name preempt one another; types… |

## Permissions — `AWP-PRM`

Defined in [/spec/safety/permissions](/spec/safety/permissions).

| ID                                      | Level | Side  | Applies | Gate   | Test                              | Requirement                                                                                                                                         |
| --------------------------------------- | ----- | ----- | ------- | ------ | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-PRM-001](/spec/safety/permissions) | MUST  | world | all     | `core` | AWP-PRM-001                       | Sessions operate default-deny: only explicitly granted action types, channels, embodiments, and administrative operations are usable; everything…   |
| [AWP-PRM-002](/spec/safety/permissions) | MUST  | world | all     | `core` | AWP-PRM-002                       | Grants are enumerated exactly in `session.ready` and are immutable for the session except channel subscriptions (negotiation).                      |
| [AWP-PRM-003](/spec/safety/permissions) | MAY   | world | all     | `core` | AWP-PRM-003 (only if implemented) | Grants MAY carry `expires_at` (monotonic ns); expired grants behave as never granted, and the world emits `world.event: grant_expired`.             |
| [AWP-PRM-004](/spec/safety/permissions) | MAY   | world | all     | `core` | AWP-PRM-004 (only if implemented) | Worlds MAY scope grants further per action type (e.g. `move_to_pose` limited to a named spatial region); such scopes appear in the granted schema.  |
| [AWP-PRM-005](/spec/safety/permissions) | MUST  | world | all     | `core` | AWP-PRM-005                       | Administrative operations are default-deny like everything else. A world that hosts a single session MAY grant `admin` operations by default; a…    |
| [AWP-PRM-006](/spec/safety/permissions) | MUST  | world | all     | `core` | AWP-PRM-006                       | `world.restore` and `world.reset` MUST: (1) emit `world.event: world_resetting` to every session, naming the initiating session id; (2) transition… |

## Reproducibility — `AWP-REP`

Defined in [/spec/reproducibility](/spec/reproducibility).

| ID                                   | Level | Side  | Applies | Gate                  | Test                                                                      | Requirement                                                                                                                                       |
| ------------------------------------ | ----- | ----- | ------- | --------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-REP-001](/spec/reproducibility) | MUST  | world | all     | `capability:seed`     | AWP-REP-001 (two seeded runs compared)                                    | Seeding. If `seed` is advertised, `session.open` MAY carry `seed`; two sessions with equal seeds and identical action sequences MUST produce…     |
| [AWP-REP-002](/spec/reproducibility) | MUST  | world | all     | `capability:snapshot` | AWP-REP-002                                                               | Snapshot / restore. `world.snapshot` returns an opaque token; `world.restore` with that token MUST return the world to the exact captured state.… |
| [AWP-REP-003](/spec/reproducibility) | MUST  | world | all     | `capability:replay`   | AWP-REP-003 (record, restore, replay, compare hashes and state sequences) | Deterministic replay. If `replay` is advertised, feeding a recorded audit log's action sequence — `action.submit` and `action.cancel` messages,…  |

## Robotics profile — `AWP-ROB`

Defined in [/spec/profiles/robotics](/spec/profiles/robotics).

| ID                                     | Level | Side  | Applies   | Gate               | Test                                                      | Requirement                                                                                                                                        |
| -------------------------------------- | ----- | ----- | --------- | ------------------ | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-ROB-001](/spec/profiles/robotics) | MUST  | world | streaming | `profile:robotics` | AWP-ROB-001                                               | Command-side checking (`enforcement: command_check` or `both`) is REQUIRED for every envelope the world declares: spatial, velocity, force, and…   |
| [AWP-ROB-002](/spec/profiles/robotics) | MUST  | world | streaming | `profile:robotics` | manual: requires physical disturbance and sensor evidence | Measured monitoring (`enforcement: measured` or `both`) is REQUIRED for `spatial` and `max_velocity_mps` — the world MUST observe executed motion… |
| [AWP-ROB-003](/spec/profiles/robotics) | MUST  | world | streaming | `profile:robotics` | manual: review of claim wording                           | Claim wording. A robotics-profile claim MUST enumerate which limits are enforced under `both` and which under `command_check` only. A world…       |
| [AWP-ROB-004](/spec/profiles/robotics) | MUST  | world | streaming | `profile:robotics` | manual: requires physical disturbance and sensor evidence | Evidence. The conformance report MUST record, per declared limit: the sensor or estimator used for measured monitoring, its sampling rate, the…    |
| [AWP-ROB-005](/spec/profiles/robotics) | MUST  | world | streaming | `profile:robotics` | AWP-ROB-005                                               | A robotics-profile world MUST declare `safety_policy.max_basis_age_ms` ≤ 500 and MUST reject with `AWP_STALE_INTENT` every `action.submit` that…   |
| [AWP-ROB-006](/spec/profiles/robotics) | MUST  | world | streaming | `profile:robotics` | AWP-ROB-006                                               | A robotics-profile world MUST offer, for every `latest-wins` observation or command channel, at least one stream binding with independent flow…    |

## Liveness and safe state — `AWP-SAF`

Defined in [/spec/safety/safe-state](/spec/safety/safe-state).

| ID                                     | Level  | Side  | Applies   | Gate                                 | Test                                                                   | Requirement                                                                                                                                         |
| -------------------------------------- | ------ | ----- | --------- | ------------------------------------ | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-SAF-001](/spec/safety/safe-state) | MUST   | both  | all       | `core`                               | AWP-SAF-001                                                            | `session.ready` declares `heartbeat_interval_ms` (default 5000). Each side MUST send `ping` at least every `heartbeat_interval_ms` and MUST answer… |
| [AWP-SAF-002](/spec/safety/safe-state) | MUST   | both  | all       | `core`                               | AWP-SAF-002                                                            | A side MUST treat the control connection as lost after three consecutive intervals without a `pong` (or any other message) from the peer, and the…  |
| [AWP-SAF-003](/spec/safety/safe-state) | MUST   | world | streaming | `core (streaming)`                   | AWP-SAF-003                                                            | Every world with a streaming time model MUST declare `safety_policy.safe_state` with `behavior` (`hold`, `safe_stop`, `park`, or a vendor value)…   |
| [AWP-SAF-004](/spec/safety/safe-state) | MUST   | world | streaming | `core (streaming)`                   | AWP-SAF-004                                                            | When the watchdog expires, the world MUST, in order: (1) begin the declared `behavior` on every embodiment bound to the session; (2) transition…    |
| [AWP-SAF-005](/spec/safety/safe-state) | SHOULD | world | streaming | `core (streaming)`                   | AWP-SAF-005 (warning)                                                  | Safe-state entry is independent of the heartbeat: a connection that answers pings but carries no agent traffic still trips the watchdog once…       |
| [AWP-SAF-006](/spec/safety/safe-state) | MUST   | world | streaming | `core (streaming)`                   | AWP-SAF-006                                                            | Streaming command channels have their own, tighter, per-action watchdog (`watchdog_ms` on the action type, AWP-CMD-005). Both apply; the…           |
| [AWP-SAF-007](/spec/safety/safe-state) | MUST   | world | streaming | `core (streaming)`                   | AWP-SAF-007                                                            | `reconnect_window_ms` governs only how long the world retains the session (token, grants, undelivered statuses, `action_id` history) after…         |
| [AWP-SAF-008](/spec/safety/safe-state) | MUST   | world | streaming | `core (streaming)`                   | AWP-SAF-008                                                            | On `session.resume` the embodiment remains in its safe state. The world MUST NOT resume any action terminated by safe-state entry, and MUST NOT…    |
| [AWP-SAF-009](/spec/safety/safe-state) | MUST   | world | streaming | `feature:reliable channels declared` | AWP-SAF-009                                                            | If the world cannot deliver frames on a `reliable` observation channel for longer than that channel's `stale_after_ms` (manifest, default 2 × the…  |
| [AWP-SAF-010](/spec/safety/safe-state) | SHOULD | agent | streaming | `core (streaming)`                   | AWP-SAF-010 (warning)                                                  | Agents SHOULD NOT submit an action whose basis observation is stale — its staleness at the moment of use exceeding the channel's `stale_after_ms`…  |
| [AWP-SAF-011](/spec/safety/safe-state) | MUST   | both  | streaming | `core (streaming)`                   | AWP-SAF-011 (deadline enforcement while the agent is alive but silent) | A stalled agent (alive connection, no new intents) is not a fault the watchdog is designed to catch: an `executing` extended action continues to…   |
| [AWP-SAF-012](/spec/safety/safe-state) | MUST   | world | streaming | `profile:robotics`                   | manual: measured watchdog reaction time attached to the report         | Adapters MUST verify their watchdog with a measured test: disconnect the agent abruptly during an `executing` extended action and record, on the…   |
| [AWP-SAF-013](/spec/safety/safe-state) | MUST   | world | streaming | `feature:max_basis_age_ms declared`  | AWP-SAF-013                                                            | Stale-intent enforcement. When the manifest declares `safety_policy.max_basis_age_ms`, the world MUST reject with `AWP_STALE_INTENT` any…           |

## Scene graphs — `AWP-SCN`

Defined in [/spec/semantics/scene-graphs](/spec/semantics/scene-graphs).

| ID                                          | Level  | Side  | Applies | Gate                            | Test                  | Requirement                                                                                                           |
| ------------------------------------------- | ------ | ----- | ------- | ------------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------- |
| [AWP-SCN-001](/spec/semantics/scene-graphs) | MUST   | world | all     | `feature:scene channel offered` | AWP-SCN-001           | Entity `id`s MUST be stable for the life of an entity and never reused within a session.                              |
| [AWP-SCN-002](/spec/semantics/scene-graphs) | SHOULD | world | all     | `feature:scene channel offered` | AWP-SCN-002 (warning) | `affordances` values SHOULD correspond to granted action types where the mapping exists (e.g. `graspable` ↔ `grasp`). |
| [AWP-SCN-003](/spec/semantics/scene-graphs) | MUST   | world | all     | `feature:scene channel offered` | AWP-SCN-003           | Scene frames are full snapshots (keyframes) or deltas per observation rules.                                          |

## Security — `AWP-SEC`

Defined in [/spec/transport/security](/spec/transport/security).

| ID                                      | Level | Side  | Applies | Gate                  | Test        | Requirement                                                                                                                                       |
| --------------------------------------- | ----- | ----- | ------- | --------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-SEC-001](/spec/transport/security) | MUST  | world | all     | `core`                | AWP-SEC-001 | Connections on loopback or stdio — the common deployment — MAY be plaintext; any connection that leaves the machine MUST use TLS (`wss://`, gRPC… |
| [AWP-SEC-002](/spec/transport/security) | MUST  | world | all     | `core (non-loopback)` | AWP-SEC-002 | Worlds MUST authenticate agents before `initialize` completes on any non-loopback connection; defined schemes: bearer token (\`Authorization:…    |
| [AWP-SEC-003](/spec/transport/security) | MUST  | world | all     | `core (non-loopback)` | AWP-SEC-003 | `session.ready` returns an unguessable session token used for `session.resume` and for binding stream connections to the session. Tokens MUST be… |
| [AWP-SEC-004](/spec/transport/security) | MUST  | world | all     | `core (non-loopback)` | AWP-SEC-004 | Stream endpoints MUST reject connections that do not present a valid session token.                                                               |

## Session lifecycle — `AWP-SES`

Defined in [/spec/session/lifecycle](/spec/session/lifecycle).

| ID                                     | Level | Side  | Applies | Gate   | Test        | Requirement                                                                                                                                                  |
| -------------------------------------- | ----- | ----- | ------- | ------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [AWP-SES-001](/spec/session/lifecycle) | MUST  | world | all     | `core` | AWP-SES-001 | Connecting `initialize` succeeds Negotiating                                                                                                                 |
| [AWP-SES-002](/spec/session/lifecycle) | MUST  | world | all     | `core` | AWP-SES-002 | Negotiating `session.open` accepted Ready                                                                                                                    |
| [AWP-SES-003](/spec/session/lifecycle) | MUST  | world | all     | `core` | AWP-SES-003 | Ready/Active control connection lost (AWP-SAF-002) Suspended; the watchdog (AWP-SAF-003) keeps running independently                                         |
| [AWP-SES-004](/spec/session/lifecycle) | MUST  | world | all     | `core` | AWP-SES-004 | Suspended `session.resume` with valid token and `last_status_seq` within window Active; statuses replayed (AWP-CTL-008); embodiment stays in safe…           |
| [AWP-SES-005](/spec/session/lifecycle) | MUST  | world | all     | `core` | AWP-SES-005 | Suspended window expires Closed; world MUST apply safe state if not already entered, then release embodiments (AWP-EMB-002)                                  |
| [AWP-SES-006](/spec/session/lifecycle) | MUST  | world | all     | `core` | AWP-SES-006 | any `session.close` Closed; pre-execution actions → `cancelled` (`session_closed`), `executing` actions → `cancelling` → `cancelled`…                        |
| [AWP-SES-007](/spec/session/lifecycle) | MUST  | world | all     | `core` | AWP-SES-007 | Worlds MUST emit a `session.state` notification — `&#123; state, status_seq, ts_mono_ns, reason? &#125;`, schema — on every transition from `Ready` onward;… |
| [AWP-SES-008](/spec/session/lifecycle) | MUST  | both  | all     | `core` | AWP-SES-008 | Recovery in v0.1 covers loss of the control connection while the world process is alive. If the world has restarted or otherwise no longer holds…            |
| [AWP-SES-009](/spec/session/lifecycle) | MAY   | world | all     | `core` | AWP-SES-009 | `session.ready` carries `session_id`, a world-assigned identifier stable for the life of the session and unique within the world process. It names…          |

## Sim profile — `AWP-SIM`

Defined in [/spec/profiles/sim](/spec/profiles/sim).

| ID                                | Level | Side  | Applies  | Gate          | Test        | Requirement                                                                                                                                                |
| --------------------------------- | ----- | ----- | -------- | ------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-SIM-001](/spec/profiles/sim) | MUST  | world | lockstep | `profile:sim` | AWP-SIM-001 | `world.reset`: the manifest MUST list at least one entry in `initial_states`, and `world.reset &#123; initial_state &#125;` MUST return the world to that… |

## Time models — `AWP-TIM`

Defined in [/spec/loop/time-models](/spec/loop/time-models).

| ID                                    | Level | Side  | Applies   | Gate   | Test                                   | Requirement                                                                                                                                            |
| ------------------------------------- | ----- | ----- | --------- | ------ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [AWP-TIM-001](/spec/loop/time-models) | MUST  | world | all       | `core` | AWP-TIM-001                            | A world declares supported time models in its manifest; a session runs in exactly one.                                                                 |
| [AWP-TIM-002](/spec/loop/time-models) | MUST  | world | lockstep  | `core` | AWP-TIM-002                            | A lockstep world MUST declare `tick_policy: "on_tick"` and MUST advance only in response to `world.tick`.                                              |
| [AWP-TIM-003](/spec/loop/time-models) | MUST  | both  | lockstep  | `core` | AWP-TIM-003                            | After each advance, the world MUST send every `action.status` and `world.event` produced by the advance on the control channel before the…             |
| [AWP-TIM-004](/spec/loop/time-models) | MUST  | world | lockstep  | `core` | AWP-TIM-004 (two seeded runs compared) | Wall-clock time MUST NOT influence world state in lockstep mode (determinism requirement; see reproducibility).                                        |
| [AWP-TIM-005](/spec/loop/time-models) | MUST  | world | streaming | `core` | AWP-TIM-005                            | The world advances in real time regardless of agent activity. Observation frames are pushed at negotiated rates, each carrying its capture time…       |
| [AWP-TIM-006](/spec/loop/time-models) | MUST  | world | streaming | `core` | AWP-TIM-006                            | Telemetry. In streaming sessions the world MUST send a `session.telemetry` notification at least once per second aggregating, over the preceding…      |
| [AWP-TIM-007](/spec/loop/time-models) | MUST  | world | streaming | `core` | AWP-TIM-007                            | Worlds MUST declare `safety_policy.safe_state` (behavior and `watchdog_ms`) and enforce it as specified in Liveness and safe state…                    |
| [AWP-TIM-008](/spec/loop/time-models) | MUST  | world | all       | `core` | AWP-TIM-008                            | Worlds offering both models MUST implement identical manifests, schemas, and action lifecycles across them; only advancement and delivery…             |
| [AWP-TIM-009](/spec/loop/time-models) | MUST  | world | lockstep  | `core` | AWP-TIM-009                            | Initial observations. Immediately after `session.ready`, and after every `obs.subscribe`, the world MUST send one frame carrying the current tick…     |
| [AWP-TIM-010](/spec/loop/time-models) | MUST  | world | lockstep  | `core` | AWP-TIM-010                            | Staging. `action.submit` in lockstep is admitted immediately (AWP-LIF-002) and the action is *staged*: the world MUST NOT begin executing it…          |
| [AWP-TIM-011](/spec/loop/time-models) | MUST  | world | lockstep  | `core` | AWP-TIM-011                            | Advances. `world.tick &#123; expected_tick, count &#125;` performs `count` sequential advances (default 1) from `expected_tick`, which MUST equal the… |
| [AWP-TIM-012](/spec/loop/time-models) | MUST  | world | lockstep  | `core` | AWP-TIM-012                            | Tick authority. The manifest declares `tick_authority`: `any_session` (the default for worlds that admit one lockstep session at a time) or…           |

## Transport and channels — `AWP-TRN`

Defined in [/spec/transport/overview](/spec/transport/overview).

| ID                                      | Level | Side  | Applies   | Gate               | Test        | Requirement                                                                                                                                        |
| --------------------------------------- | ----- | ----- | --------- | ------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-TRN-001](/spec/transport/overview) | MUST  | both  | all       | `core`             | AWP-TRN-001 | The control channel is carried on one control connection per session (AWP-CTL-007); worlds MUST offer the WebSocket binding for it. Optional…      |
| [AWP-TRN-002](/spec/transport/overview) | MUST  | both  | all       | `core`             | AWP-TRN-002 | Bindings MUST preserve the order of every channel they carry.                                                                                      |
| [AWP-TRN-003](/spec/transport/overview) | MUST  | both  | all       | `core`             | AWP-TRN-003 | Channels ≥ 1 are carried either inline on the control connection or on stream connections negotiated in `session.ready`. A stream binding either…  |
| [AWP-TRN-004](/spec/transport/overview) | MUST  | both  | all       | `core`             | AWP-TRN-004 | The inline binding — frames as `obs.frame` and `cmd.frame` notifications on the control channel (AWP-DAT-004) — is REQUIRED as the fallback when…  |
| [AWP-TRN-005](/spec/transport/overview) | MUST  | both  | all       | `core`             | AWP-TRN-005 | Every message belongs to exactly one channel. Channel `0` is the control channel, present in every session and carrying every JSON-RPC message;…   |
| [AWP-TRN-006](/spec/transport/overview) | MUST  | both  | all       | `core`             | AWP-TRN-006 | Classes. `control`: no loss, in order, replayed on resume by `status_seq`, audited in full. `reliable`: no loss, in `seq` order, resumed from a…   |
| [AWP-TRN-007](/spec/transport/overview) | MUST  | both  | all       | `core`             | AWP-TRN-007 | Ordering. Order is guaranteed within a channel and never across channels; the only cross-channel relations are those the specification states…     |
| [AWP-TRN-008](/spec/transport/overview) | MUST  | both  | all       | `core`             | AWP-TRN-008 | Resumption. On `session.resume` the control channel replays per AWP-CTL-008; the agent re-establishes stream connections from the re-issued…       |
| [AWP-TRN-009](/spec/transport/overview) | MUST  | world | streaming | `core (streaming)` | AWP-TRN-009 | Dependent streams. On a binding without independent flow control, including inline, a `latest-wins` channel cannot drop in transit, so the sender… |
| [AWP-TRN-010](/spec/transport/overview) | MUST  | both  | streaming | `core (streaming)` | AWP-TRN-010 | Stream reconnection. If a stream connection is lost while the control connection remains, the agent MAY reconnect to the same endpoint with the…   |
| [AWP-TRN-011](/spec/transport/overview) | MUST  | both  | all       | `core`             | AWP-TRN-011 | Frame size. Each stream endpoint MAY declare `max_frame_bytes` (default 16 MiB); senders MUST NOT emit a larger frame on it, and a world MUST NOT… |

## Task — `AWP-TSK`

Defined in [/spec/session/task](/spec/session/task).

| ID                                | Level  | Side  | Applies | Gate              | Test                  | Requirement                                                                                                                                                   |
| --------------------------------- | ------ | ----- | ------- | ----------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-TSK-001](/spec/session/task) | MUST   | world | all     | `capability:task` | AWP-TSK-001           | Worlds advertising the `task` capability accept an optional `task` on `session.open` and a `task.update` request mid-session; without the…                    |
| [AWP-TSK-002](/spec/session/task) | MUST   | world | all     | `capability:task` | AWP-TSK-002           | A task is `&#123; content: [ …content blocks… ] &#125;`. Worlds MUST support `text` blocks, whose `text` is Markdown; other block types MAY be supported per… |
| [AWP-TSK-003](/spec/session/task) | MUST   | world | all     | `capability:task` | AWP-TSK-003           | `task.update` replaces the task whole (no diffing) and takes effect on acknowledgement; running actions are unaffected — the task conditions the…             |
| [AWP-TSK-004](/spec/session/task) | MUST   | world | all     | `capability:task` | AWP-TSK-004           | The task confers nothing: grants, envelopes, and approval requirements are independent of its content.                                                        |
| [AWP-TSK-005](/spec/session/task) | SHOULD | world | all     | `capability:task` | AWP-TSK-005 (warning) | The initial task and every update appear in the audit log like any control-channel message, subject to `safety_policy.audit.redact_paths`…                    |

## Units and frames — `AWP-UNI`

Defined in [/spec/semantics/units-and-frames](/spec/semantics/units-and-frames).

| ID                                              | Level | Side  | Applies | Gate   | Test        | Requirement                                                                                                                                  |
| ----------------------------------------------- | ----- | ----- | ------- | ------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-UNI-001](/spec/semantics/units-and-frames) | MUST  | world | all     | `core` | AWP-UNI-001 | All physical quantities use SI units. Field names carry unit suffixes: `_m`, `_rad`, `_s`, `_ns`, `_mps`, `_radps`, `_n` (newtons), `_nm`…   |
| [AWP-UNI-002](/spec/semantics/units-and-frames) | MUST  | world | all     | `core` | AWP-UNI-002 | Coordinate systems are right-handed; rotations are unit quaternions `q: [x, y, z, w]`.                                                       |
| [AWP-UNI-003](/spec/semantics/units-and-frames) | MUST  | world | all     | `core` | AWP-UNI-003 | The world publishes a frame tree in `session.ready`: named frames with parent links and static or timestamped transforms. Every pose in any… |
| [AWP-UNI-004](/spec/semantics/units-and-frames) | MUST  | world | all     | `core` | AWP-UNI-004 | Dynamic transforms (e.g. `base` → `world` for a mobile robot) are published on the reserved `awp.tf` channel.                                |

## Versioning — `AWP-VER`

Defined in [/spec/versioning-policy](/spec/versioning-policy).

| ID                                     | Level | Side | Applies | Gate   | Test                                     | Requirement                                                                                                                                        |
| -------------------------------------- | ----- | ---- | ------- | ------ | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AWP-VER-001](/spec/versioning-policy) | MUST  | both | all     | `core` | AWP-VER-001                              | The protocol uses semver (`MAJOR.MINOR.PATCH`). Wire-visible breaking changes bump MAJOR; additive capabilities bump MINOR.                        |
| [AWP-VER-002](/spec/versioning-policy) | MUST  | both | all     | `core` | AWP-VER-002                              | Agents send the list of protocol versions they support in `initialize`; the world MUST select the highest mutually supported version and echo it,… |
| [AWP-VER-003](/spec/versioning-policy) | MUST  | both | all     | `core` | AWP-VER-003                              | Unknown fields in any message MUST be ignored, never treated as errors (forward compatibility).                                                    |
| [AWP-VER-004](/spec/versioning-policy) | MUST  | both | all     | `core` | AWP-VER-004                              | Extension fields and modalities MUST use the `x-&lt;vendor>.` prefix.                                                                              |
| [AWP-VER-005](/spec/versioning-policy) | MUST  | both | all     | `core` | untestable: process or deployment policy | Deprecated features remain functional for at least one MINOR release after the deprecation notice appears in the changelog.                        |
| [AWP-VER-006](/spec/versioning-policy) | MUST  | both | all     | `core` | AWP-VER-006                              | The negotiated protocol version alone determines wire compatibility. Schema artifact releases and SDK package versions describe those artifacts —… |
| [AWP-VER-007](/spec/versioning-policy) | MUST  | both | all     | `core` | AWP-VER-007                              | Within a wire version, optional features are discovered through the `capabilities` maps exchanged in manifests — never by version sniffing. A…     |
