@xema/omni-protocol 0.1.95 → 0.1.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/guide.md CHANGED
@@ -19,27 +19,28 @@ are used precisely throughout and mean nothing looser here.
19
19
  | Word | What it means |
20
20
  | --- | --- |
21
21
  | **Omni** | The desktop application an agent works in. It composes several providers into one agent-facing experience and owns everything outside a provider's own system. |
22
- | **Host** | Omni, named that way where the contrast with a provider is the point — *the host carries the audio*, *host-side input*. |
22
+ | **Agent application** | The software the agent uses, such as Omni, whether web or desktop. It presents provider tasks and controls and manages local audio where supported. Existing API names use `Host` and `host` for this role. |
23
23
  | **Provider** | One independently connected external system: a voice platform, a chat platform, a mail platform. |
24
24
  | **Adapter** | The package implementing this contract for one provider. One adapter is one provider, so the words are often interchangeable; *provider* names the system, *adapter* the code speaking for it. |
25
25
  | **Agent** | The person signed in and taking work. On `onCall`, `agent` is a person on the call by user id; transfer destinations may include an agent when the provider publishes that directory item. |
26
26
  | **Lead** | An agent whose login declares `capabilities.team`. The provider publishes a `TeamMembers` object to them and to nobody else: **the login is the permission**. |
27
- | **Provisioning** | Omni-side policy about this agent, configured outside the protocol and never sent to a provider. It gates whether an offer may be rejected, whether the agent goes ready on login, and whether tasks are auto-accepted. Where a capability and provisioning disagree, the stricter wins. |
28
- | **Call** | The caller’s complete phone call, which may continue through IVRs, queues and several agents. |
29
- | **Interaction** | One agent’s part in the call or conversation. The same call may return to that agent for a new interaction. |
30
- | **Task** | The agent’s assigned work and its workspace, controls and completion work. A voice task represents one interaction, not the caller’s whole call. |
27
+ | **Local policy** | Rules configured by the agent application about this agent, outside the provider protocol and never sent to a provider. It gates whether an offer may be rejected, whether the agent goes ready on login, and whether tasks are auto-accepted. Where a capability and local policy disagree, the stricter wins. |
28
+ | **Call** | The caller’s complete phone call, which may continue through IVRs, queues and several agents. The protocol never describes the IVR or the queue; it carries the call's history and details to whichever agent holds it now. |
29
+ | **Assignment** | The call routed to this agent, from the offer until the task ends. It is the one thing that crosses: the provider assigns, names the assignment with `assignmentId`, and that is the only name the desk ever uses back. A call that comes back is a new assignment on the same call, and a declined or lapsed offer is an assignment that became nothing more. What the platform calls its own record, and whether it reuses that name, is the adapter's business and unknown to the desk. |
30
+ | **Interaction** | The agent's time on the call, from answer until their audio ends: the `in-progress` and `paused` phases. An assignment produces at most one interaction, and a call that returns produces a new assignment and so a new interaction. |
31
+ | **Task** | The desk's record of one assignment, from offer through wrap: the workspace, controls and completion work the agent has for it, described by the provider and held by the desk. A task is identified by the assignment it is the record of. `pending`, `confirmed` and `preview` are assigned and not yet interacting; `in-progress` and `paused` are the interaction; `completing` is the assignment outliving its interaction. A voice task is one assignment, never the caller's whole call. |
31
32
  | **Channel** | The kind of work a provider carries: `voice`, `chat`, or `email`. Fixed per provider by its manifest. |
32
33
  | **Task type** | The provider's own name for a category of work — a queue, a mailbox folder, a chat source. Free-form, and finer-grained than a channel. |
33
- | **Capability** | A provider's declaration that a control exists for a task or a session. It says *offer this*; the provider performs it, and the host only offers it — see **Where a command executes**. |
34
+ | **Capability** | A provider's declaration that a control exists for a task or a session. It says *offer this*; the provider performs it, and the agent application only offers it — see **Where a command executes**. |
34
35
  | **Login** | One authenticated sign-in to one provider, identified by `loginId`. A transport reconnect keeps it; signing in again replaces it, and nothing tied to the old `loginId` survives. |
35
36
  | **Transport** | The adapter's connection to its platform: a WebSocket or SignalR connection, required to be persistent and ordered. Which one and how it reconnects are the adapter's business; losing it does not end a login. |
36
37
  | **Connection** | The `Connection` object Omni holds for one login: the methods it can call and the events it receives. |
37
- | **Concurrent capacity** | How many tasks this provider may have allocated to the agent at once — an absolute ceiling, stated as `AgentCapacity.count` and standing until Omni restates it. The provider counts its own outstanding tasks against it. |
38
+ | **Concurrent capacity** | How many tasks this provider may have assigned to the agent at once — an absolute ceiling, stated as `AgentCapacity.count` and standing until Omni restates it. The provider counts its own outstanding tasks against it. |
38
39
  | **Snapshot** | The provider's complete state at one moment. It replaces what Omni holds; it is never a patch. |
39
40
  | **Event** | One completed transaction reported after a snapshot established the baseline. |
40
41
  | **Break** | A reported, supervised state in which the agent is not working — one with a reason, a decision behind it and a return. It covers what a platform may call *not-ready*, including equipment trouble. An agent who is merely at capacity is not on a break. |
41
42
  | **Workspace** | What Omni shows the agent. The **task workspace** holds the selected task, its controls and its browsers; the **idle workspace** holds what a provider contributes when no task is selected — dialpad, contacts, calendar, team member list. |
42
- | **Dial** | One outbound call the host asks a provider to place — from the idle dialpad, a cold or warm transfer, a conference add, or a connect-back. Identified by the host's `dialId`, accepted as `dialling`, and ended by exactly one `dial-outcome`. See **Every dial has an outcome**. |
43
+ | **Dial** | One outbound call the agent application asks a provider to place — from the idle dialpad, a cold or warm transfer, a conference add, or a connect-back. Identified by the agent application's `dialId`, accepted as `dialling`, and ended by exactly one `dial-outcome`. See **Every dial has an outcome**. |
43
44
  | **Listen** | A lead listening to a member's call unasked, from the team member list: `listen` in silence, `coach` heard by the agent alone, `join-call` heard by everyone. Nothing of it reaches the member's task, and there is no take-over in it. See **Listening to a call**. |
44
45
  | **On the call** | Who a voice task's audio joins, or is bringing in, as the provider states it on `Task.onCall`: the party, the agents, and anyone consulted or conferenced in from the moment their dial is placed. |
45
46
 
@@ -55,6 +56,11 @@ state use `status`; name the object when discussing them to avoid ambiguity.
55
56
  | `status` | The agent’s break lifecycle | `not-requested`, `awaiting-approval`, `granted`, `starting-after-task`, `on-break` |
56
57
  | `availability` | A team member | `ready`, `on-task`, `on-break`, `signed-out` |
57
58
 
59
+ Migration: describeUsers is now `getUserDetails`, and validateDescribedUsers is now
60
+ `validateUserDetails`. Related diagnostics use getUserDetails. Hosts and providers must
61
+ update together; the old method and validator have no compatibility aliases. The requested
62
+ user IDs, returned user details and directory requirements are unchanged.
63
+
58
64
  ## Versioning
59
65
 
60
66
  ### `OMNI_PROTOCOL_VERSION`
@@ -67,12 +73,12 @@ An adapter declares **every** version it can speak, not just the one it was comp
67
73
 
68
74
  ```ts
69
75
  supportedProtocolVersions: [1] // v1 only
70
- supportedProtocolVersions: [1, 2] // can serve either host
76
+ supportedProtocolVersions: [1, 2] // can serve either agent application
71
77
  ```
72
78
 
73
79
  A single pinned version would make migration impossible: recompiling against a newer package
74
80
  would silently move an adapter to the new version with no window in which both sides
75
- interoperate. Declaring a set lets an adapter support the old and new host at once, so the two
81
+ interoperate. Declaring a set lets an adapter support the old and new agent application at once, so the two
76
82
  can be deployed independently.
77
83
 
78
84
  ### `negotiateProtocolVersion(adapterVersions, hostVersions?)`
@@ -99,8 +105,7 @@ the semantic name in every contract field rather than repeating the primitive ty
99
105
  ```ts
100
106
  type IsoTimestamp = string;
101
107
  type UserId = string;
102
- type TaskId = string;
103
- type AllocationId = string;
108
+ type AssignmentId = string;
104
109
  type DialId = string;
105
110
  type DurationSeconds = number;
106
111
  ```
@@ -109,7 +114,7 @@ type DurationSeconds = number;
109
114
  | --- | --- | --- |
110
115
  | `IsoTimestamp` | `string` | An RFC-3339 timestamp with `Z` or an explicit numeric offset. Timezone-less values are invalid. It must pass the shared runtime validator. A JavaScript `Date` never crosses the protocol boundary. |
111
116
  | `UserId` | `string` | A non-empty, opaque, stable identifier for a person, **issued by the provider** and drawn from the same directory as `AuthenticationState.identity.id`. It names agents and managers alike; the role is established by where the value appears, not by its type. Compare it exactly and only within one provider; do not parse it or infer meaning from its format. |
112
- | `TaskId` | `string` | A non-empty, opaque task identifier unique within one provider. Omni scopes it with the provider ID. |
117
+ | `AssignmentId` | `string` | A non-empty, opaque identifier for one assignment, **issued by the provider**: unique within the provider and never reused while the provider is still speaking about it. Whether it is the platform's own handle passed through or one the adapter minted is the adapter's business. Omni scopes it with the provider ID -- see `taskKey()`. |
113
118
  | `DurationSeconds` | `number` | A non-negative integer duration measured in seconds. |
114
119
 
115
120
  ### There is no Omni-wide user identity
@@ -119,7 +124,7 @@ identifier of its own for an agent or a manager, and none crosses this boundary
119
124
  operating-system account, not a directory identity, not a licence.
120
125
 
121
126
  So a `UserId` means nothing outside the provider that issued it. Provider A's
122
- `interactionHistory[].by` and provider B's team member list `memberId` are unrelated strings that will
127
+ `history[].by` and provider B's team member list `memberId` are unrelated strings that will
123
128
  eventually collide, and one person on several providers has several identities that nothing here
124
129
  pairs. Scope every user identifier with its provider ID before storing or comparing it, exactly as
125
130
  `taskKey()` already does for tasks — see `userKey()` under **Utilities**.
@@ -322,8 +327,7 @@ type RecordingCommand = {
322
327
  | { action: "pause" | "resume" | "stop" | "cancel"; recordingId: string }
323
328
  );
324
329
  interface HostRecordingReport {
325
- taskId: TaskId;
326
- allocationId: AllocationId;
330
+ assignmentId: AssignmentId;
327
331
  state: RecordingState;
328
332
  }
329
333
  interface HostRecording {
@@ -334,8 +338,7 @@ interface HostRecording {
334
338
  }
335
339
  type RecordingCommandResult = Exclude<TaskCommandResult, { status: "dialling" }>;
336
340
  interface HostRecordingRequest {
337
- taskId: TaskId;
338
- allocationId: AllocationId;
341
+ assignmentId: AssignmentId;
339
342
  command: RecordingCommand & { source: "host" };
340
343
  }
341
344
 
@@ -460,15 +463,15 @@ type SetPreferenceRequest =
460
463
  | { id: PreferenceId; enabled: boolean }
461
464
  | { id: PreferenceId; inherit: true };
462
465
 
463
- type InteractionReport = { taskId: TaskId; allocationId: AllocationId; at: IsoTimestamp } & (
466
+ type HistoryReport = { assignmentId: AssignmentId; at: IsoTimestamp } & (
464
467
  | { step: "muted"; mutedBy: MutedBy }
465
- | { step: Exclude<InteractionStep, "muted">; mutedBy?: never }
468
+ | { step: Exclude<HistoryStep, "muted">; mutedBy?: never }
466
469
  ) & (
467
470
  | { ended: true; seconds: DurationSeconds }
468
471
  | { ended?: never; seconds?: DurationSeconds }
469
472
  );
470
473
 
471
- type InteractionReportResult =
474
+ type HistoryReportResult =
472
475
  | { status: "recorded"; at: IsoTimestamp }
473
476
  | { status: "failed"; failure: ProtocolFailure };
474
477
 
@@ -488,7 +491,7 @@ type Snapshot = {
488
491
  };
489
492
 
490
493
  type AgentCapacity = {
491
- count: number; // absolute ceiling, zero or more; zero is host-stopped
494
+ count: number; // absolute ceiling, zero or more; zero is agent application-stopped
492
495
  };
493
496
 
494
497
  type CapacityResult = { status: "applied" };
@@ -613,8 +616,7 @@ type PersonalBrowser = Browser;
613
616
 
614
617
  type BrowserSessionKeyInput = {
615
618
  providerId: string;
616
- taskId: TaskId;
617
- allocationId: AllocationId;
619
+ assignmentId: AssignmentId;
618
620
  taskType: string;
619
621
  browser: TaskBrowser;
620
622
  };
@@ -647,7 +649,7 @@ type TaskAttribute = TaskAttributeBase & (
647
649
  | { type: "timestamp"; at: IsoTimestamp }
648
650
  );
649
651
 
650
- type InteractionStep =
652
+ type HistoryStep =
651
653
  | "queued"
652
654
  | "offered"
653
655
  | "answered"
@@ -657,16 +659,16 @@ type InteractionStep =
657
659
  | "conferenced"
658
660
  | "unanswered";
659
661
 
660
- type TaskInteractionHistory = {
661
- steps: TaskInteractionStep[];
662
+ type TaskHistory = {
663
+ steps: TaskHistoryStep[];
662
664
  interactionSeconds?: DurationSeconds;
663
665
  holdSeconds?: DurationSeconds;
664
666
  queueSeconds?: DurationSeconds;
665
667
  transfers?: number;
666
668
  };
667
669
 
668
- type TaskInteractionStep = {
669
- step: InteractionStep;
670
+ type TaskHistoryStep = {
671
+ step: HistoryStep;
670
672
  at: IsoTimestamp;
671
673
  dialId?: DialId;
672
674
  destinationId?: string;
@@ -697,14 +699,14 @@ type TaskLeadAssist = { note?: string; since: IsoTimestamp } & (
697
699
 
698
700
  type TaskAssisting = {
699
701
  memberId: UserId;
702
+ assignmentId: AssignmentId;
700
703
  note?: string;
701
704
  since: IsoTimestamp;
702
705
  };
703
706
 
704
707
  type TaskListening = {
705
708
  memberId: UserId;
706
- taskId: TaskId;
707
- allocationId: AllocationId;
709
+ assignmentId: AssignmentId;
708
710
  mode: ListeningMode;
709
711
  since: IsoTimestamp;
710
712
  };
@@ -728,8 +730,7 @@ type TaskMediaState = "started" | "ended";
728
730
  type CapabilitySource = "queue" | "ungoverned" | "undetermined";
729
731
 
730
732
  type Task<C extends Channel = Channel> = {
731
- id: TaskId;
732
- allocationId: AllocationId;
733
+ assignmentId: AssignmentId;
733
734
  title: string;
734
735
  channel: C;
735
736
  taskType: string;
@@ -743,7 +744,7 @@ type Task<C extends Channel = Channel> = {
743
744
  atDeadline?: PreviewDeadline;
744
745
  reference?: string;
745
746
  attributes?: TaskAttribute[];
746
- interactionHistory?: TaskInteractionHistory;
747
+ history?: TaskHistory;
747
748
  } & TaskCompletion & (
748
749
  C extends "voice"
749
750
  ? { recording?: { provider?: RecordingState }; onCall?: OnCall[]; leadAssist?: TaskLeadAssist; assisting?: TaskAssisting; listening?: TaskListening; media?: TaskMediaState }
@@ -835,8 +836,7 @@ type TaskCommand<C extends Channel = Channel> =
835
836
  | CustomTaskCommand;
836
837
 
837
838
  type TaskCommandRequest<C extends Channel = Channel> = {
838
- taskId: TaskId;
839
- allocationId: AllocationId;
839
+ assignmentId: AssignmentId;
840
840
  command: TaskCommand<C>;
841
841
  };
842
842
 
@@ -870,7 +870,7 @@ leaves out does not exist — a structure with no site level declares `org`, `te
870
870
  at: a label with no policy behind it decides nothing. A manifest that declares none has exactly
871
871
  the four. `lockedBy` is any level in force except `person`, who never locks their own value;
872
872
  `setBy` is any level in force, or `provider`, the protocol's word for "no level has said
873
- anything and the provider's own configuration supplied the value". A host renders "who decided" from the
873
+ anything and the provider's own configuration supplied the value". An agent application renders "who decided" from the
874
874
  declared labels and needs no others, and validates every republished `authenticated` state
875
875
  against them, not only the sign-in. What the wire carries is the resolution:
876
876
 
@@ -897,7 +897,7 @@ The adapter is the one that knows the value, so it is the one held to it: given
897
897
  queue locked, the validator refuses any other field carrying one, digits compared as digits so no
898
898
  formatting hides them (`task.locked.leak`), and a conformance run whose tasks lock a party's number
899
899
  or email states those values in `lockedValues`, since a run that cannot ask the question is not a
900
- pass. A host never has the value and never asks. A name is not locked. What the queue provides rather than permits — browsers, outcomes, custom
900
+ pass. An agent application never has the value and never asks. A name is not locked. What the queue provides rather than permits — browsers, outcomes, custom
901
901
  controls — is content, and is never locked.
902
902
 
903
903
  **A lead sets the team's policy from their team member list.** A login that declares
@@ -921,9 +921,9 @@ person's preference from their own screen, which arrives the same way. A prefere
921
921
  the capability's own name because it is the same capability at another level: effective in
922
922
  `Task.capabilities`, set for the team in `policies`, left to the person in `preferences`. The
923
923
  command `hold` acts on one call; the preference `hold` says whether the person wants the control
924
- at all, and a host renders it in its settings, never as the button on a call. Mute is in none of
925
- these ladders: the microphone is the host's, and nobody on the provider's side allows, locks or
926
- keeps a choice about it. See **The station is the host's**.
924
+ at all, and an agent application renders it in its settings, never as the button on a call. Mute is in none of
925
+ these ladders: the microphone is the agent application's, and nobody on the provider's side allows, locks or
926
+ keeps a choice about it. See **The station is the agent application's**.
927
927
 
928
928
  ## Breaks
929
929
 
@@ -996,8 +996,7 @@ type TeamMember = {
996
996
  type LeadRequest = {
997
997
  id: string;
998
998
  memberId: UserId;
999
- taskId: TaskId;
1000
- allocationId: AllocationId;
999
+ assignmentId: AssignmentId;
1001
1000
  note?: string;
1002
1001
  since: IsoTimestamp;
1003
1002
  };
@@ -1076,8 +1075,7 @@ type OpenMediaResult =
1076
1075
  | { status: "unavailable"; failure: ProtocolFailure };
1077
1076
 
1078
1077
  type OpenMediaRequest = {
1079
- taskId: TaskId;
1080
- allocationId: AllocationId;
1078
+ assignmentId: AssignmentId;
1081
1079
  localAudio?: MediaStream;
1082
1080
  };
1083
1081
  ```
@@ -1105,16 +1103,16 @@ type ProviderEvent =
1105
1103
  | {
1106
1104
  type: "task-offered";
1107
1105
  task: Task;
1108
- allocationExpiresAt?: IsoTimestamp;
1106
+ assignmentExpiresAt?: IsoTimestamp;
1109
1107
  }
1110
1108
  | { type: "task-updated"; task: Task }
1111
- | { type: "task-media-started"; taskId: TaskId; allocationId: AllocationId }
1112
- | { type: "task-media-ended"; taskId: TaskId; allocationId: AllocationId }
1113
- | { type: "task-ended"; taskId: TaskId; allocationId: AllocationId; outcome: TaskOutcome }
1114
- | { type: "dial-outcome"; dialId: DialId; outcome: DialOutcome; taskId?: TaskId; allocationId?: AllocationId; destinationId?: string; reason?: string }
1109
+ | { type: "task-media-started"; assignmentId: AssignmentId }
1110
+ | { type: "task-media-ended"; assignmentId: AssignmentId }
1111
+ | { type: "task-ended"; assignmentId: AssignmentId; outcome: TaskOutcome }
1112
+ | { type: "dial-outcome"; dialId: DialId; outcome: DialOutcome; assignmentId?: AssignmentId; destinationId?: string; reason?: string }
1115
1113
  | { type: "announcement"; text: string; html?: string; announcedAt: IsoTimestamp; expiresAt?: IsoTimestamp }
1116
1114
  | { type: "queue-summary"; summary: QueueSummary }
1117
- | { type: "diagnostic"; expected: string; observed: string; taskId?: TaskId; allocationId?: AllocationId }
1115
+ | { type: "diagnostic"; expected: string; observed: string; assignmentId?: AssignmentId }
1118
1116
  | { type: "team-updated"; team: TeamMembers }
1119
1117
  | { type: "contacts-updated"; contacts: Contact[] }
1120
1118
  | { type: "calendar-updated"; scheduledActivities: ScheduledActivity[] };
@@ -1163,7 +1161,7 @@ type Connection<C extends Channel = Channel> = {
1163
1161
  execute(request: TaskCommandRequest<C>): Promise<TaskCommandResult>;
1164
1162
  disconnect(): Promise<void>;
1165
1163
 
1166
- describeUsers?(ids: UserId[]): Promise<User[]>;
1164
+ getUserDetails?(ids: UserId[]): Promise<User[]>;
1167
1165
  dial?(request: DialRequest): Promise<DialResult>;
1168
1166
 
1169
1167
  requestBreak?(request: BreakRequest): Promise<BreakRequestResult>;
@@ -1176,7 +1174,7 @@ type Connection<C extends Channel = Channel> = {
1176
1174
  executeTeamListen?(request: TeamListenCommandRequest): Promise<TeamCommandResult>;
1177
1175
  openMedia?(request: OpenMediaRequest): Promise<OpenMediaResult>;
1178
1176
  setPreference?(request: SetPreferenceRequest): Promise<PreferenceResult>;
1179
- recordStep?(report: InteractionReport): Promise<InteractionReportResult>;
1177
+ recordStep?(report: HistoryReport): Promise<HistoryReportResult>;
1180
1178
  executeTeamPolicy?(request: TeamPolicyCommandRequest): Promise<TeamCommandResult>;
1181
1179
  };
1182
1180
 
@@ -1224,7 +1222,7 @@ const BREAK_KINDS = [
1224
1222
 
1225
1223
  type BreakKind = (typeof BREAK_KINDS)[number];
1226
1224
 
1227
- const INTERACTION_STEPS_WITH_A_PERSON = [
1225
+ const HISTORY_STEPS_WITH_A_PERSON = [
1228
1226
  "offered",
1229
1227
  "answered",
1230
1228
  "held",
@@ -1247,8 +1245,8 @@ const OMNI_FAILURE_CODES = [
1247
1245
  type OmniFailureCode = (typeof OMNI_FAILURE_CODES)[number];
1248
1246
  ```
1249
1247
 
1250
- `INTERACTION_STEPS_WITH_A_PERSON` is every `InteractionStep` except `queued`, which is the one nobody
1251
- takes part in. `interactionStepExpectsAPerson()` tests membership.
1248
+ `HISTORY_STEPS_WITH_A_PERSON` is every `HistoryStep` except `queued`, which is the one nobody
1249
+ takes part in. `historyStepExpectsAPerson()` tests membership.
1252
1250
 
1253
1251
  ### Failure and validation
1254
1252
 
@@ -1401,7 +1399,7 @@ fact.
1401
1399
 
1402
1400
  Omitting a field says *I cannot see this*. An empty value says *I looked, and there is nothing*.
1403
1401
 
1404
- Send whichever is true. A host renders them differently and cannot recover the distinction once
1402
+ Send whichever is true. An agent application renders them differently and cannot recover the distinction once
1405
1403
  it is lost.
1406
1404
 
1407
1405
  The same distinction applies to nested fields. Omit a nested field only when its value is unknown;
@@ -1457,8 +1455,8 @@ is never the provider's answer: an answer travels only as a resolved `{ status:
1457
1455
  and every rejection is transport loss, whatever the last `transport-status` said and whatever the
1458
1456
  rejection carries.
1459
1457
 
1460
- A command therefore carries no key. The provider names its own records — a task, a lead request, a
1461
- member — and Omni refers to them by those names; **Omni never asks a provider to remember a name
1458
+ A command therefore carries no key. The provider names the assignment, the lead request and the
1459
+ member, and Omni refers to them by those names; **Omni never asks a provider to remember a name
1462
1460
  Omni made up.**
1463
1461
 
1464
1462
  A command whose second execution changes nothing needs no protection: committing a break that is
@@ -1480,11 +1478,11 @@ fired into a state that has moved on.
1480
1478
 
1481
1479
  ### 7. Work is pulled, never pushed
1482
1480
 
1483
- Allocate only within the concurrent capacity Omni has stated for this agent.
1481
+ Assign only within the concurrent capacity Omni has stated for this agent.
1484
1482
 
1485
- An allocation beyond that capacity, or with none currently stated, is invalid and Omni rejects it
1483
+ An assignment beyond that capacity, or with none currently stated, is invalid and Omni rejects it
1486
1484
  as a protocol violation. Work the agent was already working on when the connection came back is
1487
- reported in the snapshot; it is not an allocation.
1485
+ reported in the snapshot; it is not an assignment.
1488
1486
 
1489
1487
  ### 8. State is authoritative at the provider
1490
1488
 
@@ -1494,13 +1492,13 @@ replaces its local provider view; it does not overwrite the provider.
1494
1492
 
1495
1493
  ### 9. Define a vocabulary; do not merely list it
1496
1494
 
1497
- Every member of a closed set — break kinds, interaction steps, destination kinds — must have a
1495
+ Every member of a closed set — break kinds, history steps, destination kinds — must have a
1498
1496
  normative definition; matching names alone do not establish shared meaning.
1499
1497
 
1500
1498
  ### 10. Order on the wire is display order
1501
1499
 
1502
1500
  A list the provider publishes — a destination directory, outcome codes, a task's custom
1503
- controls, its browsers — is in the order the provider wants it shown, and a host keeps that order.
1501
+ controls, its browsers — is in the order the provider wants it shown, and an agent application keeps that order.
1504
1502
  A reader will find meaning in position unless something says there is none, so the provider
1505
1503
  decides: where it has an intention, an administrator's sequence, it lists in that order; where it
1506
1504
  has none, it orders by the label, so the order is visibly arbitrary and does not move under the
@@ -1533,20 +1531,20 @@ Request/response polling does not have those properties and is not a transport f
1533
1531
  ### 3. An adapter's memory is the platform's and the login's, never the connection's
1534
1532
 
1535
1533
  Everything an adapter publishes about a task is derived from what the platform states, or kept in
1536
- the login's store where the platform cannot hold it. Per offer, the `allocationId` comes from what
1534
+ the login's store where the platform cannot hold it. Per offer, the `assignmentId` comes from what
1537
1535
  the offer itself states; per call, the media follows `task-media-started` and `task-media-ended`,
1538
1536
  never a flag set when the audio was opened; per session, the phone the agent holds is what the
1539
1537
  platform restates on activation, not a mapping read once over HTTP. What the platform cannot hold
1540
- -- a host's muted leg -- goes in `ConnectContext.store`, keyed by the task and gone with it.
1538
+ -- an agent application's muted leg -- goes in `ConnectContext.store`, keyed by the task and gone with it.
1541
1539
 
1542
- A fact read once over a connection and kept in the adapter object dies with the client. A host
1540
+ A fact read once over a connection and kept in the adapter object dies with the client. An agent application
1543
1541
  reload is the first client dying and a second coming up for the same login, and the second
1544
1542
  publishes the same truth about the same task as the first did, or the first was publishing
1545
- something it made up: an allocation minted for the connection, media remembered as a boolean, a
1543
+ something it made up: an assignment minted for the connection, media remembered as a boolean, a
1546
1544
  phone the second never read. Three pieces of exactly that state were found in one adapter in an
1547
1545
  afternoon, and none of it was visible until the adapter was built twice. The drive's `rebuild` is the test of this
1548
1546
  principle: given a way to build the adapter again, the run hands the login over and holds the
1549
- second to what the first published (`drive.reload.allocation`, `.history`, `.openMedia`, and the
1547
+ second to what the first published (`drive.reload.snapshot`, `.history`, `.openMedia`, and the
1550
1548
  stream's own rules across the resync). An adapter that cannot be built twice against its platform
1551
1549
  and publish the same task is not a conformant adapter yet, whatever a single run says.
1552
1550
 
@@ -1608,11 +1606,11 @@ compile time.
1608
1606
  | `phaseLabels` | Optional static adapter-defined display names for canonical `TaskPhase` values. They cannot vary at runtime. |
1609
1607
  | `taskTypePresentation` | Optional static adapter-defined presentation keyed by exact `taskType`. It names the item and its optional agent-facing reference. |
1610
1608
  | `orgLevels` | The organisation's whole ladder as the provider calls it, each level with the label a desk shows for "who decided". Stated outright, `person` included: what it leaves out does not exist. Omitted for the typical four, `DEFAULT_LEVELS`. See **Who decides what an agent may do**. |
1611
- | `phones` | Voice only, and required there: the phones this platform can put an agent on, `softphone` (the call's audio lands in the host) and/or `deskPhone` (a handset the platform rings; the host shows the call and opens nothing). The host picks one per login. See **How the agent hears the call**. |
1609
+ | `phones` | Voice only, and required there: the phones this platform can put an agent on, `softphone` (the call's audio lands in the agent application) and/or `deskPhone` (a handset the platform rings; the agent application shows the call and opens nothing). The agent application picks one per login. See **How the agent hears the call**. |
1612
1610
  | `dialOutcomes` | Voice only. How a dial can end on this platform, as it distinguishes them: `answered` and at least one way of not reaching the destination. Required of a provider that dials at all — an idle dialpad, or tasks that transfer, conference or call back — and a `dial-outcome` carries only a declared member. See **Every dial has an outcome**. |
1613
- | `timeCheck` | Optional `true`: implements `checkTime` for fresh provider-clock samples; host polling is independently opt-in. |
1614
- | `timestampAuthority` | Optional `"provider"`: provider timestamps are final; host instants are advisory. Omission makes no trust promise. |
1615
- | `runningStepReports` | The provider takes running reports of a host-performed step — `recordStep` with `seconds` so far and no `ended`. Omitted, the host sends exactly two reports per leg, when it began and when it ended, and a running one is refused. See **The host records what it performs**. |
1611
+ | `timeCheck` | Optional `true`: implements `checkTime` for fresh provider-clock samples; agent application polling is independently opt-in. |
1612
+ | `timestampAuthority` | Optional `"provider"`: provider timestamps are final; agent application instants are advisory. Omission makes no trust promise. |
1613
+ | `runningStepReports` | The provider takes running reports of an agent application-performed step — `recordStep` with `seconds` so far and no `ended`. Omitted, the agent application sends exactly two reports per leg, when it began and when it ended, and a running one is refused. See **The agent application records what it performs**. |
1616
1614
  | `completionSettleMs` | Required. How long after an applied completion -- `complete`, or a lead's `take-over-call` -- the provider's `task-ended` is owed, a positive whole number of milliseconds (`manifest.completionSettleMs`). A warm transfer's `complete` is not final task completion: the agent's wrap runs after it. Stated per provider, since platforms settle at different speeds. See **`task-ended`**. |
1617
1615
 
1618
1616
  ### Authentication methods
@@ -1867,8 +1865,8 @@ Creates the provider-scoped authentication session.
1867
1865
  | --- | --- |
1868
1866
  | `protocolVersion` | The negotiated version, fixed for this login. |
1869
1867
  | `loginId` | Omni-generated identity for this login. The same value Omni later passes as `ConnectContext.loginId`, and how an adapter ties a connection back to the session that authenticated it. |
1870
- | `timeZone` | The zone the agent's day is reckoned in, as an IANA name from the host's clock, stated before any identity exists so the first `authenticated` state already carries it. The same value Omni later passes as `ConnectContext.timeZone`. See **The agent's day**. |
1871
- | `phone` | How this login hears its calls, chosen by the host from the manifest's `phones`: required for a voice provider, absent for any other. The same value Omni later passes as `ConnectContext.phone`. See **How the agent hears the call**. |
1868
+ | `timeZone` | The zone the agent's day is reckoned in, as an IANA name from the agent application's clock, stated before any identity exists so the first `authenticated` state already carries it. The same value Omni later passes as `ConnectContext.timeZone`. See **The agent's day**. |
1869
+ | `phone` | How this login hears its calls, chosen by the agent application from the manifest's `phones`: required for a voice provider, absent for any other. The same value Omni later passes as `ConnectContext.phone`. See **How the agent hears the call**. |
1872
1870
  | `secrets` | Omni-provided `SecretStore`, scoped to this provider's manifest id. |
1873
1871
  | `signal` | Optional cancellation signal. |
1874
1872
  | `log` | Optional structured logging callback. Never include credentials, tokens, or sensitive contact data. |
@@ -1930,7 +1928,7 @@ them from what arrives later.
1930
1928
  | `team.policyControl` | This lead sets the team's policy per capability — on, off, or the person's — within what the queue allows. Requires `executeTeamPolicy`; the team member list carries `policies`. |
1931
1929
  | `preferences` | What the team left to this person, with where each stands and who set it. Omitted when nothing was. Requires `setPreference`. See **Who decides what an agent may do**. |
1932
1930
 
1933
- A session action is available only when both the capability and Omni provisioning permit it.
1931
+ A session action is available only when both the capability and Omni local policy permit it.
1934
1932
 
1935
1933
  **Capabilities are current, not fixed.** They describe the login as of its latest `authenticated`
1936
1934
  state. A provider that reads roles live — a lead demoted mid-shift — republishes `authenticated`
@@ -1954,7 +1952,7 @@ short-lived, opaque `flowId`; rejection returns `AuthenticationFailure`.
1954
1952
 
1955
1953
  #### Browser SSO
1956
1954
 
1957
- For `browser-sso`, Omni allocates a one-time callback URL and passes it to `start()`:
1955
+ For `browser-sso`, Omni issues a one-time callback URL and passes it to `start()`:
1958
1956
 
1959
1957
  ```ts
1960
1958
  {
@@ -2023,7 +2021,7 @@ failure:
2023
2021
  ```
2024
2022
 
2025
2023
  The `User` it carries is the **root of this provider's user namespace**. Every other person this
2026
- provider names — a team member, the manager on a forced break, the agent on an interaction step —
2024
+ provider names — a team member, the manager on a forced break, the agent on a history step —
2027
2025
  is identified from the same directory and carries the same `UserId` type.
2028
2026
 
2029
2027
  | Field | Contract |
@@ -2072,11 +2070,11 @@ Creates one live provider connection for the signed-in agent.
2072
2070
  | --- | --- |
2073
2071
  | `protocolVersion` | Version negotiated before authentication. Fixed for this login. |
2074
2072
  | `loginId` | Omni-generated identity for this login. It is the same value passed as `AuthenticationContext.loginId`, so an adapter can correlate this connection with the session that authenticated it. Stable across transport reconnects and changed only by a new login. |
2075
- | `autoAcceptTasks` | Agent provisioning policy relayed to the provider at login, stated by the host on every connection and never assumed from its absence. When `true`, a pending task states its `acceptance`; when `false`, every task requires agent acceptance. Fixed for this connection, like everything else here: the provider states or omits `acceptance` by the value it was sent, and Omni validates by that same value, not by a policy that has since moved — a change reaches the provider through a fresh `connect()`. |
2073
+ | `autoAcceptTasks` | Agent local policy policy relayed to the provider at login, stated by the agent application on every connection and never assumed from its absence. When `true`, a pending task states its `acceptance`; when `false`, every task requires agent acceptance. Fixed for this connection, like everything else here: the provider states or omits `acceptance` by the value it was sent, and Omni validates by that same value, not by a policy that has since moved — a change reaches the provider through a fresh `connect()`. |
2076
2074
  | `timeZone` | The same value passed as `AuthenticationContext.timeZone`. The provider stores it on the agent and carries it on the identity. See **The agent's day**. |
2077
- | `phone` | The same value passed as `AuthenticationContext.phone`: how this login hears its calls. The type ties `host.mute` to it: a `softphone` login's host states what its Mute does, and a desk-phone or conversation login's host cannot, so the omission is a compile error rather than a live seat's discovery. See **The station is the host's**. |
2078
- | `store` | The login's operational store, kept by the host for the life of the login, across a reload of the host, and cleared at sign-out: where an adapter that composes a record keeps what its platform cannot hold for it, such as the interaction legs a host reported. Three functions, by key. Never for anything sensitive, which is `AuthenticationContext.secrets`, a store a host may clear aggressively. **A task's keys carry the task id and go with the task**: a key written about a task names the task's id in the key, and is deleted before the task's end is published, because a platform retires a task id minutes after closing it and a requeue takes seconds, so a key that outlives its task is inherited by the next offer of the same id -- a record with legs the host never reported against it. A login-scoped key carries no task id and outlives any task. The harness requires the store of every connection (`store.shape`, `store.get`, `.set`, `.delete`), watches the one it hands over, and names a task's key still held after `task-ended` (`drive.store.retained`) or written about the task after its end -- a persist hung off a timer that saw the task as it was (`drive.store.late`). The ordinary late write is the host's, not the adapter's: a host reports a leg without waiting for the answer, so an unmute can follow `complete` by a tick, and the adapter answers a report about a task that has ended `failed` with `omni.task-not-found` and writes nothing -- the host ends its own open legs at the task's end, so such a report is the host's error to see, and a host reads every `recordStep` answer and awaits the one for the leg it closes at a task's end, the only moment a refusal is expected, since a report nobody waits for is an error nobody can see; an adapter that names no task in its keys gets no cleanup check, which is a gap rather than a pass, never an exemption: the obligation is that nothing of a closed task survives its ending, and an adapter that keeps every open task in one login-scoped value owes exactly that inside the value, where the harness cannot look. One key per task, named for it, is the shape the harness can hold, and the shape to reach for. The store lists nothing, so an adapter that needs to find its tasks keeps a login-scoped index of ids beside them; at the task's end it deletes the body first and reindexes after, since a crash between the two then leaves an index naming a task with no body, which a reader skips, where the other order leaves a body for a task that has ended, which is the hazard itself. A reader of the index tolerates an id with no body as an ending that was underway, not as corruption. |
2079
- | `host` | The host's report of the agent's station — devices, permissions, network — to consult before declaring the agent ready to the platform, and on every change. See **The host reports, the adapter decides**. |
2075
+ | `phone` | The same value passed as `AuthenticationContext.phone`: how this login hears its calls. The type ties `host.mute` to it: a `softphone` login's agent application states what its Mute does, and a desk-phone or conversation login's agent application cannot, so the omission is a compile error rather than a live seat's discovery. See **The station is the agent application's**. |
2076
+ | `store` | The login's operational store, kept by the agent application for the life of the login, across a reload of the agent application, and cleared at sign-out: where an adapter that composes a record keeps what its platform cannot hold for it, such as the interaction legs an agent application reported. Three functions, by key. Never for anything sensitive, which is `AuthenticationContext.secrets`, a store an agent application may clear aggressively. **A task's keys carry its assignment id and go with the task**: a key written about a task names the assignment id in the key, and is deleted before the task's end is published, so that nothing of a closed task survives its ending and nothing is left for whatever comes next -- a record with legs the agent application never reported against it. A login-scoped key carries no assignment id and outlives any task. The harness requires the store of every connection (`store.shape`, `store.get`, `.set`, `.delete`), watches the one it hands over, and names a task's key still held after `task-ended` (`drive.store.retained`) or written about the task after its end -- a persist hung off a timer that saw the task as it was (`drive.store.late`). The ordinary late write is the agent application's, not the adapter's: an agent application reports a leg without waiting for the answer, so an unmute can follow `complete` by a tick, and the adapter answers a report about a task that has ended `failed` with `omni.task-not-found` and writes nothing -- the agent application ends its own open legs at the task's end, so such a report is the agent application's error to see, and an agent application reads every `recordStep` answer and awaits the one for the leg it closes at a task's end, the only moment a refusal is expected, since a report nobody waits for is an error nobody can see; an adapter that names no task in its keys gets no cleanup check, which is a gap rather than a pass, never an exemption: the obligation is that nothing of a closed task survives its ending, and an adapter that keeps every open task in one login-scoped value owes exactly that inside the value, where the harness cannot look. One key per task, named for it, is the shape the harness can hold, and the shape to reach for. The store lists nothing, so an adapter that needs to find its tasks keeps a login-scoped index of ids beside them; at the task's end it deletes the body first and reindexes after, since a crash between the two then leaves an index naming a task with no body, which a reader skips, where the other order leaves a body for a task that has ended, which is the hazard itself. A reader of the index tolerates an id with no body as an ending that was underway, not as corruption. |
2077
+ | `host` | The agent application's report of the agent's station — devices, permissions, network — to consult before declaring the agent ready to the platform, and on every change. See **The agent application reports, the adapter decides**. |
2080
2078
  | `signal` | Optional cancellation signal. Stop startup promptly when aborted and do not begin new work. |
2081
2079
  | `log` | Optional structured logging callback. Never include credentials, tokens, or sensitive contact data. |
2082
2080
 
@@ -2088,12 +2086,12 @@ target, an answer streak, a per-queue count for today -- anything bucketed by da
2088
2086
  by somebody's day, and a platform that was never told whose uses its own. An agent in Chennai
2089
2087
  then finds their day rolling at 05:30, and a night shift in Chicago lands in two buckets.
2090
2088
 
2091
- So the host says whose day it is, and it says so first. `AuthenticationContext.timeZone` is the
2089
+ So the agent application says whose day it is, and it says so first. `AuthenticationContext.timeZone` is the
2092
2090
  agent's zone as an IANA name -- `Asia/Kolkata`, `America/Chicago` -- never an offset, since an
2093
2091
  offset cannot survive a daylight-saving boundary and a day boundary is exactly where that bites
2094
2092
  (`context.timeZone`). It is stated before any identity exists, and `ConnectContext.timeZone` is the
2095
2093
  same value again. The provider **stores it on the agent** and carries it as `identity.timeZone` on
2096
- every `authenticated` state and on every `User` it returns from `describeUsers()`, so a lead
2094
+ every `authenticated` state and on every `User` it returns from `getUserDetails()`, so a lead
2097
2095
  reading a colleague's yesterday sees the colleague's yesterday and a summary is bucketed by the
2098
2096
  right day after a session has ended. A roaming agent corrects it by signing in from where they are.
2099
2097
 
@@ -2102,12 +2100,12 @@ field to fill in later: an identity without one is refused (`authentication.iden
2102
2100
  so is a zone that is not an IANA name, wherever it appears. Nothing is ever assumed in its place --
2103
2101
  not the viewer's browser, which gives a different answer per reader for the same record, and not the
2104
2102
  provider's clock. The harness holds a provider to the round trip: the identity carries the zone the
2105
- host stated (`authentication.identity.timeZone.republished`), judged by what the name denotes:
2103
+ agent application stated (`authentication.identity.timeZone.republished`), judged by what the name denotes:
2106
2104
  `Asia/Kolkata` and `Asia/Calcutta` are one zone, and a provider that keeps the canonical name has
2107
2105
  kept the zone. **The round trip is not the store.**
2108
2106
  An adapter that echoes the stated zone back onto the identity passes that check with nothing kept,
2109
2107
  and a lead reading a colleague's day would still get the wrong one. What proves the store is a zone
2110
- the run never sent: a colleague's `User` from `describeUsers()` carrying theirs. A provider's own
2108
+ the run never sent: a colleague's `User` from `getUserDetails()` carrying theirs. A provider's own
2111
2109
  tests are where that is shown, with a second agent whose zone arrived through another session.
2112
2110
 
2113
2111
  ### Who the agent is
@@ -2150,10 +2148,10 @@ surface in one place, and what obliges an adapter to implement each one.
2150
2148
  | `checkTime(request)` | The manifest declares `timeCheck: true`. Read-only clock check; no task command or accuracy guarantee. |
2151
2149
  | `subscribe(listener)` | Always. |
2152
2150
  | `disconnect()` | Always. |
2153
- | `refused(report)` | Always. The host tells the adapter what it would not take -- a snapshot it did not replace its state with, an event it dropped -- with every rule broken, so a refusal is visible on both sides. See **What the host does with what it refuses**. |
2154
- | `setCapacity(capacity)` | Always. Nothing may be allocated until a capacity is stated, so there is no connection that does not receive it. |
2151
+ | `refused(report)` | Always. The agent application tells the adapter what it would not take -- a snapshot it did not replace its state with, an event it dropped -- with every rule broken, so a refusal is visible on both sides. See **What the agent application does with what it refuses**. |
2152
+ | `setCapacity(capacity)` | Always. Nothing may be assigned until a capacity is stated, so there is no connection that does not receive it. |
2155
2153
  | `execute(request)` | Always. Every channel has commands no capability gates — see **Which commands need a capability**. |
2156
- | `describeUsers(ids)` | The adapter publishes any `UserId`: on `ForcedBreak.by`, a team member list, or `interactionHistory[].by`. Each `User` carries its `timeZone`; a person whose zone the provider cannot name is omitted from the answer, as any unresolvable id is. |
2154
+ | `getUserDetails(ids)` | The adapter publishes any `UserId`: on `ForcedBreak.by`, a team member list, or `history[].by`. Each `User` carries its `timeZone`; a person whose zone the provider cannot name is omitted from the answer, as any unresolvable id is. |
2157
2155
  | `dial(request)` | The manifest declares `idleCapabilities.dial`, and with it `dialOutcomes`. |
2158
2156
  | `requestBreak(request)` | The login declares `capabilities.breaks`. |
2159
2157
  | `commitBreak()` | The login declares `capabilities.breaks`. Commit and cancel are not optional halves of it. |
@@ -2163,7 +2161,7 @@ surface in one place, and what obliges an adapter to implement each one.
2163
2161
  | `executeTeamLeadAssist(command)` | The login declares `capabilities.team.leadAssistControl`. |
2164
2162
  | `executeTeamListen(command)` | The login declares `capabilities.team.listeningControl`. |
2165
2163
  | `setPreference(request)` | The login declares `capabilities.preferences`: the person's choice has to have somewhere to go. |
2166
- | `recordStep(report)` | The manifest lists `softphone` among its `phones`. On a softphone the host mutes its own microphone on any call, and the provider's record has to have somewhere to take that leg; a desk phone's microphone is the phone's. See **The host records what it performs**. |
2164
+ | `recordStep(report)` | The manifest lists `softphone` among its `phones`. On a softphone the agent application mutes its own microphone on any call, and the provider's record has to have somewhere to take that leg; a desk phone's microphone is the phone's. See **The agent application records what it performs**. |
2167
2165
  | `executeTeamPolicy(command)` | The login declares `capabilities.team.policyControl`. |
2168
2166
  | `openMedia(request)` | The manifest lists `softphone` among its `phones`. On a softphone the call's audio lands in Omni, so the adapter has to open it; a platform of desk phones alone never does. |
2169
2167
 
@@ -2203,16 +2201,16 @@ Registers a listener for provider changes and returns an idempotent unsubscribe
2203
2201
  while disconnected without requiring a durable event log.
2204
2202
  - After unsubscribe, the listener must receive no further events.
2205
2203
 
2206
- ### `Connection.describeUsers(ids)`
2204
+ ### `Connection.getUserDetails(ids)`
2207
2205
 
2208
2206
  Turns `UserId` values into something an agent can read.
2209
2207
 
2210
2208
  ```ts
2211
- describeUsers(ids: UserId[]): Promise<User[]>
2209
+ getUserDetails(ids: UserId[]): Promise<User[]>
2212
2210
  ```
2213
2211
 
2214
2212
  Required of any adapter that publishes a `UserId` — on `ForcedBreak.by`, a team member list, or
2215
- `interactionHistory[].by`. Publishing an identifier Omni cannot resolve puts a name on screen
2213
+ `history[].by`. Publishing an identifier Omni cannot resolve puts a name on screen
2216
2214
  that reads as a database key.
2217
2215
 
2218
2216
  - **Omit an id you cannot resolve; do not invent a name for it.** A missing entry says *I do not
@@ -2226,7 +2224,7 @@ that reads as a database key.
2226
2224
  particular value, or on Omni asking again at any particular moment.
2227
2225
 
2228
2226
  This is the only place a name comes from. Task data carries identifiers alone —
2229
- `interactionHistory[].by` is an id and nothing more — so a name is never copied into a task, never
2227
+ `history[].by` is an id and nothing more — so a name is never copied into a task, never
2230
2228
  duplicated across tasks, and never stale.
2231
2229
 
2232
2230
  ### `Connection.disconnect()`
@@ -2238,19 +2236,19 @@ Stops the connection and releases adapter-owned resources.
2238
2236
  - Must remove event handlers and release media resources owned by the adapter.
2239
2237
  - Does not imply that active tasks were completed or removed.
2240
2238
 
2241
- ## Task allocation lifecycle
2239
+ ## Task assignment lifecycle
2242
2240
 
2243
- The task-allocation lifecycle has five ordered stages:
2241
+ The task-assignment lifecycle has five ordered stages:
2244
2242
 
2245
2243
  **1. The agent signs in.** Nothing on the wire says ready or not-ready: the agent is not ready
2246
- until the host has stated a capacity, and ready once it has. A provider allocates nothing before a
2244
+ until the agent application has stated a capacity, and ready once it has. A provider assigns nothing before a
2247
2245
  capacity is stated, and needs no other word for it.
2248
2246
 
2249
- **2. The agent becomes ready.** The host states the capacity when its provisioning says: at once,
2247
+ **2. The agent becomes ready.** The agent application states the capacity when its local policy says: at once,
2250
2248
  or when the agent presses Ready. A successful connection, a healthy provider, or the absence of a
2251
2249
  break does not imply readiness. After that, the only way an agent stops taking work is a break,
2252
2250
  under `capabilities.breaks`; a login that declares no breaks cannot go not-ready once its capacity
2253
- is stated, and `count: 0` is the host's division of capacity, not the agent's choice.
2251
+ is stated, and `count: 0` is the agent application's division of capacity, not the agent's choice.
2254
2252
 
2255
2253
  **3. Omni states their concurrent capacity.** Only now does Omni ask providers for work, saying how
2256
2254
  much the agent can take at once. It is a standing declaration rather than a poll: Omni restates the
@@ -2271,13 +2269,13 @@ intent.
2271
2269
 
2272
2270
  During login, Omni sends the agent's `autoAcceptTasks` value to the provider. When it is `true`, the
2273
2271
  provider states `acceptance` on each pending task — on the task rather than the offer, so a
2274
- reconnect snapshot says it too and an offer the host never received is not accepted on the
2272
+ reconnect snapshot says it too and an offer the agent application never received is not accepted on the
2275
2273
  person's behalf for want of a word:
2276
2274
 
2277
2275
  | Directive | Contract |
2278
2276
  | --- | --- |
2279
2277
  | `no-preference` | The provider leaves acceptance to Omni; with `autoAcceptTasks: true`, Omni accepts automatically. |
2280
- | `consent` | The provider requires the person's explicit consent: Omni presents **Accept** and waits, whatever its own policy would have done. A host that declares `guarantees.personConsent` promises exactly this; a provider checks it before offering work only a person may take. |
2278
+ | `consent` | The provider requires the person's explicit consent: Omni presents **Accept** and waits, whatever its own policy would have done. An agent application that declares `guarantees.personConsent` promises exactly this; a provider checks it before offering work only a person may take. |
2281
2279
  | `automatic` | Omni accepts immediately without agent interaction. |
2282
2280
 
2283
2281
  When Omni sent `autoAcceptTasks: false`, the provider omits `acceptance` and every task the
@@ -2287,20 +2285,20 @@ no-auto-accept policy puts no word on the wire at all — the field is absent, a
2287
2285
  press is Omni's doing, not the provider's.
2288
2286
 
2289
2287
  **The value is stated, never assumed.** `autoAcceptTasks` is required of every connection: a
2290
- host says which policy the deployment provisioned, and a validator that is not told checks
2288
+ agent application says which policy the deployment provisioned, and a validator that is not told checks
2291
2289
  neither rule rather than guess the permissive one (`task.acceptance.required` and
2292
2290
  `.unexpected` fire only against a stated value). `acceptance` is the provider's own control and
2293
2291
  outranks the policy: `consent` puts the decision back in the agent's hands for any task where it
2294
- belongs, whatever the host was configured with.
2292
+ belongs, whatever the agent application was configured with.
2295
2293
 
2296
2294
  An automatically accepted task still arrives through `task-offered`.
2297
2295
 
2298
2296
  **Work the agent originated is accepted by the command that created it.** A task born of the
2299
- agent's own act — a dialpad call or a connect-back, recognisable by the host's `dialId` on
2297
+ agent's own act — a dialpad call or a connect-back, recognisable by the agent application's `dialId` on
2300
2298
  `onCall`; a lead's join, carrying `assisting`; a lead's listen, carrying `listening` — arrives
2301
2299
  through `task-offered` with `acceptance: "automatic"` whatever `autoAcceptTasks` says, and the
2302
- validator holds it there under either provisioning and under none (`task.acceptance.originated`):
2303
- the desk shows no **Accept** for a call the agent placed. The provisioning governs work the queue
2300
+ validator holds it there under either local policy and under none (`task.acceptance.originated`):
2301
+ the desk shows no **Accept** for a call the agent placed. The local policy governs work the queue
2304
2302
  routes to the agent, and nothing else.
2305
2303
 
2306
2304
  ### Pending
@@ -2313,15 +2311,15 @@ automatic or requires the agent. A provider that requires automatic acceptance s
2313
2311
  ```ts
2314
2312
  declare const task: Task;
2315
2313
 
2316
- const allocation = {
2314
+ const assignment = {
2317
2315
  type: "task-offered",
2318
2316
  task: { ...task, phase: "pending", acceptance: "consent" },
2319
- allocationExpiresAt: "2026-08-25T10:41:07.000Z",
2317
+ assignmentExpiresAt: "2026-08-25T10:41:07.000Z",
2320
2318
  } satisfies Extract<ProviderEvent, { type: "task-offered" }>;
2321
2319
  ```
2322
2320
 
2323
2321
  The rule the phase exists to express: **nothing is acquired on the agent's behalf while a task
2324
- is pending.** A host that carries media must not open the microphone until the task is
2322
+ is pending.** An agent application that carries media must not open the microphone until the task is
2325
2323
  accepted. Omni does not open the task's browsers either — a task that rings out costs nothing.
2326
2324
 
2327
2325
  When consent is required, Omni offers the agent an **Accept** control. The call is the
@@ -2334,7 +2332,7 @@ on a desk phone — and is not in question per call. See **How the agent hears t
2334
2332
 
2335
2333
  Automatic acceptance still begins with `task-offered`.
2336
2334
 
2337
- `allocationExpiresAt` is the deadline after which the offer lapses. Where present, Omni counts
2335
+ `assignmentExpiresAt` is the deadline after which the offer lapses. Where present, Omni counts
2338
2336
  down and stops offering **Accept** once it passes; the provider ends the lapsed offer with
2339
2337
  `task-ended` and an `expired` outcome naming `pending`, since nobody cancelled it. **Omit it unless the provider can observe it.**
2340
2338
  A provider that reports only elapsed ring time after the fact cannot say when an offer is due
@@ -2348,7 +2346,7 @@ A provider may withdraw a pending task by emitting `task-ended` with a `cancelle
2348
2346
  `agent` for a decline, `provider` for a withdrawal or a re-route, `party` for a caller who abandoned
2349
2347
  the ring. One word for the three left a supervisor's record unable to tell them apart, so `by` is
2350
2348
  required and closed (`event.taskEnded.outcome.cancelled.by`). An offer nobody acted on before
2351
- `allocationExpiresAt` is not cancelled by anyone: it lapses, and ends `expired` naming `pending`.
2349
+ `assignmentExpiresAt` is not cancelled by anyone: it lapses, and ends `expired` naming `pending`.
2352
2350
 
2353
2351
  ### Tasks already in progress
2354
2352
 
@@ -2356,7 +2354,7 @@ The provider does not introduce new work as already `in-progress`.
2356
2354
 
2357
2355
  A task appears already `in-progress` only in a snapshot taken after a reconnect or a resync,
2358
2356
  reporting work that began earlier in this login and never stopped. A fresh login has none to
2359
- report: nothing has been allocated yet, and work the agent was working elsewhere is not carried
2357
+ report: nothing has been assigned yet, and work the agent was working elsewhere is not carried
2360
2358
  into a new session.
2361
2359
 
2362
2360
  ## Tasks
@@ -2373,28 +2371,27 @@ time. Runtime conformance checks also require the task channel to match its prov
2373
2371
 
2374
2372
  | Field | Contract |
2375
2373
  | --- | --- |
2376
- | `id` | Required `TaskId`, the platform's own identity for the task. Unique among the tasks open at once; a platform retires an id minutes after closing it, so the same id comes back for another customer. Omni scopes it with the provider ID. |
2377
- | `allocationId` | Required `AllocationId`: this life of the task, minted once per offer and never reused for the life of the login, whatever the id does. Every event, command and report that names a task names its allocation too, so a late dial outcome or a late interaction report for the first customer never lands on the next under the same id. The stream refuses an offer reusing one (`stream.taskOffered.allocation`), an update restating another life of the id (`stream.taskUpdated.allocation`), and a media or ending event naming a life that has ended or that nobody has seen (`stream.allocation.ended`, `.unknown`); a `dial-outcome` may name an ended life, since a dial placed late routinely outlives its call, and the host routes it there. See **A task's life on the wire**. |
2374
+ | `assignmentId` | Required `AssignmentId`: the assignment this task is the record of, and its one identity. Issued by the provider, unique within the provider, never reused. Every event, command and report that names a task names it by this, so a late dial outcome or a late history report for one customer never lands on the next. The stream refuses an assignment introduced twice (`stream.taskOffered.duplicate`) and a media or ending event naming one that has ended or that nobody has seen (`stream.assignment.ended`, `.unknown`); a `dial-outcome` may name an ended assignment, since a dial placed late routinely outlives its call, and the agent application routes it there. See **A task's life on the wire**. |
2378
2375
  | `title` | Agent-facing task title. |
2379
2376
  | `channel` | Channel used for this task. It must equal the source provider's manifest channel. |
2380
2377
  | `taskType` | Required provider-defined source or category of work, such as a voice `Queue Name`, `Mailbox Folder`, `Chat Source`, `Support`, `Billing`, or `Returns`. |
2381
2378
  | `capabilities` | Controls and workspace features available for this specific task. |
2382
- | `capabilitySource` | Required. Who chose the capabilities: `queue` when somebody configured these terms, `ungoverned` when nothing handed the work over -- an agent's own outbound -- and `undetermined` when a queue was named and its terms could not be read, in which case `capabilities` is what the provider will honour, not what the platform permits. A host shows `undetermined` where the agent works. See **Task capabilities**. |
2379
+ | `capabilitySource` | Required. Who chose the capabilities: `queue` when somebody configured these terms, `ungoverned` when nothing handed the work over -- an agent's own outbound -- and `undetermined` when a queue was named and its terms could not be read, in which case `capabilities` is what the provider will honour, not what the platform permits. An agent application shows `undetermined` where the agent works. See **Task capabilities**. |
2383
2380
  | `browsers` | Named browser definitions for the task workspace: at least one when the task declares the `browsers` capability, empty when it does not. |
2384
2381
  | `party` | The person or entity on the other end of this task, as a `Contact`: often a name and one address; a withheld caller ID may leave nothing to send at all. Optional. The party is who the task is *with*; `contacts` is the directory. |
2385
2382
  | `phase` | Current canonical task phase: `pending`, `confirmed`, `preview`, `in-progress`, `paused`, or `completing`. `preview` is voice only. |
2386
- | `media` | Voice only. The task's real-time audio as the provider holds it: `started` while audio is attached, `ended` once it ended, omitted while none is. The provider's word — see **`task-media-started`**. Media names a task whose work has begun, or whose party the host is dialling: on a `pending`, `confirmed` or `preview` task with nobody ringing it is refused (`task.media.beforeWork`), on a snapshot as on the event, since a host opens the microphone on it; with the party ringing by a host dial or provider-triggered preview dial, actual ring-back media may precede answer. |
2383
+ | `media` | Voice only. The task's real-time audio as the provider holds it: `started` while audio is attached, `ended` once it ended, omitted while none is. The provider's word — see **`task-media-started`**. Media names a task whose work has begun, or whose party the agent application is dialling: on a `pending`, `confirmed` or `preview` task with nobody ringing it is refused (`task.media.beforeWork`), on a snapshot as on the event, since an agent application opens the microphone on it; with the party ringing by an agent application dial or provider-triggered preview dial, actual ring-back media may precede answer. |
2387
2384
  | `acceptance` | How this offer is accepted — `no-preference`, `consent`, or `automatic` — stated on the pending task so a reconnect snapshot says it too. Required while `pending` when `autoAcceptTasks` was `true`, forbidden when it was `false`, and absent past `pending`. See **Acceptance modes**. |
2388
2385
  | `previewEndsAt` | Voice only, in `preview`: the preparation target instant. Absent, the agent has as long as they need without a preparation countdown. Always with `atDeadline`. See **Preview: the agent presses Call**. |
2389
- | `atDeadline` | Voice only, in `preview`, with `previewEndsAt`: what the system does at the deadline -- `calls` makes the provider initiate dialing, `host-calls` makes the host issue Call, `waits` keeps the task in preview awaiting the agent. |
2386
+ | `atDeadline` | Voice only, in `preview`, with `previewEndsAt`: what the system does at the deadline -- `calls` makes the provider initiate dialing, `host-calls` makes the agent application issue Call, `waits` keeps the task in preview awaiting the agent. |
2390
2387
  | `reference` | Optional agent-facing reference such as a case, call, conversation, ticket, or message number. It is distinct from the protocol `id`. |
2391
2388
  | `completionMode` | `agent-command` waits for the channel's `complete` command; `provider-automatic` completes without one. |
2392
2389
  | `wrapAllowance` | Fixed time allowed to complete the task after primary interaction ends. For real-time media, it begins after `task-media-ended`. Required under `provider-automatic`, where the provider acts on it. Optional under `agent-command`: omitted says the provider imposes no deadline, and Omni counts nothing down. |
2393
2390
  | `attributes` | Optional ordered, typed `TaskAttribute` entries with keys unique within the task. Each contact or timestamp is a separate array item; new attribute shapes require new union members. |
2394
- | `interactionHistory` | The call record: `steps` — the ordered interaction history of this open task, one entry per occurrence, oldest first — and what they add up to before this agent, `interactionSeconds`, `holdSeconds`, `queueSeconds`, `transfers`, each present when the provider knows it. Live task data restated with the task, not a permanent archive. See **Interaction history**. |
2395
- | `onCall` | Voice only. Who is on the call, or being brought onto it, as the provider states it, replaced whole with the task: `party` is the customer -- carrying a `stage` while being dialled again on the same task, a connect-back with the host's `dialId` or a platform's callback without, ringing from the moment the dial is placed and joined on its answered outcome --, `agent` a person by user id, `consulted` and `conferenced` somebody a dial is bringing in, listed from the moment the dial is placed -- with the `destinationId` dialled, the `dialId` where a host placed it, the `stage` reached (`ringing` until answered, `joined` after), and `held: true` on anyone joined and parked. A `consulted` entry is what makes `transfer` `complete` and `cancel` issuable. `label` names a destination -- a person, a queue -- not a phrase; the host supplies the verb. Present when the provider knows the room, absent when it does not. See **Every dial has an outcome**. |
2391
+ | `history` | The call record: `steps` — the ordered interaction history of this open task, one entry per occurrence, oldest first — and what they add up to before this agent, `interactionSeconds`, `holdSeconds`, `queueSeconds`, `transfers`, each present when the provider knows it. Live task data restated with the task, not a permanent archive. See **Interaction history**. |
2392
+ | `onCall` | Voice only. Who is on the call, or being brought onto it, as the provider states it, replaced whole with the task: `party` is the customer -- carrying a `stage` while being dialled again on the same task, a connect-back with the agent application's `dialId` or a platform's callback without, ringing from the moment the dial is placed and joined on its answered outcome --, `agent` a person by user id, `consulted` and `conferenced` somebody a dial is bringing in, listed from the moment the dial is placed -- with the `destinationId` dialled, the `dialId` where an agent application placed it, the `stage` reached (`ringing` until answered, `joined` after), and `held: true` on anyone joined and parked. A `consulted` entry is what makes `transfer` `complete` and `cancel` issuable. `label` names a destination -- a person, a queue -- not a phrase; the agent application supplies the verb. Present when the provider knows the room, absent when it does not. See **Every dial has an outcome**. |
2396
2393
  | `leadAssist` | Voice only. Present from the agent's request for a lead until the lead leaves or the request ends: `requested` while nobody has joined, `joined` with the lead's `leadId` once somebody has. See **Lead assist**. |
2397
- | `assisting` | Voice only, on the lead's own task for a call they joined: which member asked, with their note. Its presence is what makes `lead-assist` `take-over-call` and `leave` issuable. See **Lead assist**. |
2394
+ | `assisting` | Voice only, on the lead's own task for a call they joined: which member asked, the member's `assignmentId`, and their note. The lead's task has an assignment of its own, so the member's is named, or the copy no longer says which call it joined. Its presence is what makes `lead-assist` `take-over-call` and `leave` issuable. See **Lead assist**. |
2398
2395
  | `listening` | Voice only, on the lead's own task while they listen to a member's call: whose call, which call, and the `mode` they are heard in, restated on every change. Never on the member's task, and never together with `assisting`. See **Listening to a call**. |
2399
2396
 
2400
2397
  `TaskAttribute` entries carry typed detail alongside the task:
@@ -2423,15 +2420,15 @@ The canonical task transitions are:
2423
2420
 
2424
2421
  | From | Decision or event | To |
2425
2422
  | --- | --- | --- |
2426
- | No task | Provider allocates a task | `pending` |
2423
+ | No task | Provider assigns a task | `pending` |
2427
2424
  | `pending` | Task is accepted | `confirmed` |
2428
2425
  | `confirmed` | The customer's record is put in front of the agent before any call goes out (voice) | `preview` |
2429
2426
  | `confirmed` | Work begins | `in-progress` |
2430
2427
  | `preview` | Agent presses Call (`call`) and the customer answers, or the deadline `calls` and they answer | `in-progress` |
2431
2428
  | `preview` | The call goes out and nobody answers | `completing` |
2432
2429
  | `preview` | The preparation target passes with `atDeadline: "waits"` | Remains `preview`, waiting for the agent to press Call |
2433
- | `pending` | Provider withdraws the allocation, the agent declines, or the party abandons the ring | Removed by `task-ended` with `cancelled` outcome, `by` saying which |
2434
- | `pending` | The offer lapses at `allocationExpiresAt` | Removed by `task-ended` with `expired` outcome naming `pending` |
2430
+ | `pending` | Provider withdraws the assignment, the agent declines, or the party abandons the ring | Removed by `task-ended` with `cancelled` outcome, `by` saying which |
2431
+ | `pending` | The offer lapses at `assignmentExpiresAt` | Removed by `task-ended` with `expired` outcome naming `pending` |
2435
2432
  | No task | Snapshot reports work already underway | `in-progress` |
2436
2433
  | `in-progress` | Provider or agent pauses the task | `paused` |
2437
2434
  | `in-progress` | Agent starts a warm transfer (`transfer` `warm`); the customer is parked | `paused` |
@@ -2443,23 +2440,26 @@ The canonical task transitions are:
2443
2440
 
2444
2441
  #### A task's life on the wire
2445
2442
 
2446
- A task id is the platform's, and platforms reuse them: a closed id is retired minutes later, a
2447
- requeue takes seconds, and on one platform a call was offered twice, thirteen seconds apart, under
2448
- one id, through a close and a re-offer. Everything that names a task after the fact -- a dial
2449
- outcome, a media event, an ending, an interaction report, a command -- would land on whichever life of
2450
- the id is open when it arrives. So every offer mints an `allocationId`, unique for the life of the
2451
- login, and every one of those names it beside the `taskId`. The host keys its state on the pair, a
2452
- late event finds the life it belongs to or is refused, and a task-scoped browser session
2453
- (`PROVIDER_NAME__TASK_ID__TAB_NAME`) lives one allocation, never the next customer's cookies under
2454
- a reused id. A dial the host placed was already safe, since its outcome is placed by the host's own
2455
- `dialId`; where the allocation earns its place is everything the host does not mint --
2443
+ A task has one name, the assignment it is the record of, and the provider issues it. Platforms
2444
+ reuse their own handles: a closed one is retired minutes later, a requeue takes seconds, and on
2445
+ one platform a call was offered twice, thirteen seconds apart, under one handle, through a close
2446
+ and a re-offer. Everything that names a task after the fact -- a dial outcome, a media event, an
2447
+ ending, a history report, a command -- would land on whichever assignment is open when it arrives.
2448
+ So the assignment id is unique within the provider and never reused: where the platform's handle
2449
+ never comes back, the adapter passes it through; where it does, the adapter mints the assignment id
2450
+ and keeps the mapping, and the desk never learns which. A late event finds the assignment it
2451
+ belongs to or is refused, and a task-scoped browser session (`PROVIDER_NAME__TASK_ID__TAB_NAME`)
2452
+ lives one assignment, never the next customer's cookies. A dial the agent application placed was
2453
+ already safe, since its outcome is placed by the agent application's own `dialId`; where the
2454
+ assignment earns its place is everything the agent application does not mint --
2456
2455
  `task-media-started`, `task-media-ended`, `task-ended`, a `recordStep` naming a task -- any of which
2457
- would otherwise find the new task under the old id and act on it. The allocation is part of the task
2458
- the adapter keeps, not a field held in memory beside it: a rebuilt adapter comes back with the same
2459
- allocation on the same task, or every late event it was minted to catch mismatches
2460
- (`drive.reload.allocation`).
2456
+ would otherwise find the next customer under a reused handle and act on them. A minted id is part
2457
+ of the task the adapter keeps, not a field held in memory beside it: it lives in the login's
2458
+ `store` with the task, or is derived from a platform handle that itself never reuses, so a rebuilt
2459
+ adapter comes back with the same assignment on the same task, or every late event it was minted to
2460
+ catch mismatches and the second adapter's snapshot no longer carries the task (`drive.reload.snapshot`).
2461
2461
 
2462
- Allocation, acceptance, and progress are distinct. Acceptance follows `autoAcceptTasks` and the
2462
+ Assignment, acceptance, and progress are distinct. Acceptance follows `autoAcceptTasks` and the
2463
2463
  task's `acceptance`, moving the task from `pending` to `confirmed`. The provider reports
2464
2464
  subsequent transitions to `preview` or `in-progress`; Omni does not infer them from the acceptance
2465
2465
  command.
@@ -2486,9 +2486,9 @@ const previewed = {
2486
2486
  const pressed: TaskCommand<"voice"> = { type: "call", dialId: "dial-7f2" };
2487
2487
  ```
2488
2488
 
2489
- **Call is a dial.** It carries the host's `dialId`, is answered `dialling`, and ends in exactly one
2489
+ **Call is a dial.** It carries the agent application's `dialId`, is answered `dialling`, and ends in exactly one
2490
2490
  `dial-outcome`; the phase is its gate and there is no capability, since a record put in front of an
2491
- agent is there to be called. Its media starts on `dialling`, as every host-placed dial's does --
2491
+ agent is there to be called. Its media starts on `dialling`, as every agent application-placed dial's does --
2492
2492
  ring-back is audio the agent hears -- so `task-media-started` arrives on the `preview` task with
2493
2493
  its party ringing. On `answered` the task is `in-progress`; on any other outcome the media ends,
2494
2494
  `task-media-ended` starts the wrap clock as on every voice task, and the task goes to
@@ -2503,8 +2503,8 @@ carries the provider's authoritative preparation-end instant and exactly one tri
2503
2503
 
2504
2504
  | Declaration | At preparation end |
2505
2505
  | --- | --- |
2506
- | `atDeadline: "calls"` | The provider initiates dialing. The host never sends a timer-triggered Call. |
2507
- | `atDeadline: "host-calls"` | The host sends the ordinary `call` command with a fresh host `dialId`. The provider does not independently auto-dial this task. |
2506
+ | `atDeadline: "calls"` | The provider initiates dialing. The agent application never sends a timer-triggered Call. |
2507
+ | `atDeadline: "host-calls"` | The agent application sends the ordinary `call` command with a fresh agent application `dialId`. The provider does not independently auto-dial this task. |
2508
2508
  | `atDeadline: "waits"` | Neither side auto-dials. The task remains in preview until the agent presses Call. |
2509
2509
 
2510
2510
  The agent may press Call early in either fixed-preparation dialing mode, or at any time in
@@ -2518,53 +2518,52 @@ answer at that exact instant. Scheduling/dispatch delay must remain visible, and
2518
2518
  prevented initiation must be reported rather than leaving a silently expired countdown.
2519
2519
  A source eligibility threshold that may never trigger an attempt is not this promise.
2520
2520
 
2521
- The two deadline fields travel together and only in preview. The host uses trusted provider-domain
2522
- time; clock estimation is allowed only under the explicit host-triggered preview exception below.
2521
+ The two deadline fields travel together and only in preview. The agent application uses trusted provider-domain
2522
+ time; clock estimation is allowed only under the explicit agent application-triggered preview exception below.
2523
2523
  Without usable provider-domain time
2524
2524
  it cannot safely auto-trigger and must expose the uncertainty and reconcile. No zero-duration,
2525
2525
  receipt-time or local-default deadline is inferred. Neither elapsed time nor submission changes
2526
2526
  the task phase: subsequent authoritative events state ringing, answer, media and completion.
2527
2527
 
2528
- A host must serialize manual clicks and its timer under the exact provider/login/task/allocation
2528
+ An agent application must serialize manual clicks and its timer under the exact provider/login/task/assignment
2529
2529
  scope, allowing at most one unresolved submission. Recheck the current phase, deadline owner,
2530
- allocation and whether an attempt already exists before dispatch. A new snapshot or policy update
2531
- cancels an obsolete timer; login loss, disconnect, task end and allocation replacement fence its
2530
+ assignment and whether an attempt already exists before dispatch. A new snapshot or policy update
2531
+ cancels an obsolete timer; login loss, disconnect, task end and assignment replacement fence its
2532
2532
  callback. Reconnect past a deadline first reconciles current task and attempt state; it must not
2533
2533
  blindly submit again. An uncertain prior submission remains unresolved, without automatic retry.
2534
2534
  The provider atomically arbitrates any residual manual/timer race and does not accept a second
2535
2535
  command as ownership of an already-running independent attempt.
2536
2536
 
2537
- Host-triggered automatic dialing is an ordinary host dial: its result is `dialling` with the same
2538
- host `dialId`, followed by exactly one correlated terminal `dial-outcome`. A provider-triggered
2539
- dial has no invented host ID or host dial outcome. It reports source-evidenced party ringing,
2537
+ Agent application-triggered automatic dialing is an ordinary agent application dial: its result is `dialling` with the same
2538
+ agent application `dialId`, followed by exactly one correlated terminal `dial-outcome`. A provider-triggered
2539
+ dial has no invented agent application ID or agent application dial outcome. It reports source-evidenced party ringing,
2540
2540
  actual media and customer answer separately. In preview with `atDeadline: "calls"`, a ringing
2541
- party without a host ID may carry actual pre-answer media; the deadline alone permits no media.
2541
+ party without an agent application ID may carry actual pre-answer media; the deadline alone permits no media.
2542
2542
  Media is still introduced/ended by the corresponding events and must not imply customer answer.
2543
2543
  Submission acceptance is never an answered outcome or permission to publish `in-progress` early.
2544
2544
  Unsupported source correlation/outcome/media evidence remains an integration blocker.
2545
2545
 
2546
2546
  **Drop both fields when the phase moves.** A provider that builds the `in-progress` task by
2547
- spreading the `preview` one carries `previewEndsAt` and `atDeadline` with it, and the host refuses
2547
+ spreading the `preview` one carries `previewEndsAt` and `atDeadline` with it, and the agent application refuses
2548
2548
  the update (`task.preview.deadline.unexpected`): the desk keeps the task as it last stood, and the
2549
2549
  provider is told through `refused` exactly which rule, so the state that looked right on its side
2550
2550
  is named on its side. The task past preview has no deadline to wait for, so it carries neither
2551
2551
  field.
2552
2552
 
2553
- **Provider execution and host controls are distinct.** Answer, hold/resume, transfer (including
2553
+ **Provider execution and agent application controls are distinct.** Answer, hold/resume, transfer (including
2554
2554
  IVR routing), conference and interaction completion are executed by the provider
2555
2555
  through the adapter. The task's applicable capability, phase, completion mode and command-specific
2556
- prerequisites decide which controls are offered. Caller disconnect also executes at the provider. Microphone mute is host-owned, never a provider
2557
- TaskCommand or task capability. The separately declared host recording facility keeps its existing
2558
- recording contract; this distinction does not remove it or move provider call operations to the host.
2559
-
2560
- A caller journey may revisit the same agent while an earlier interaction still wraps. Public task
2561
- IDs must remain distinct for concurrently open interactions. For source-owned interaction IDs allocated
2562
- before offer and never reused per assignment, both public task ID and allocation ID may equal that
2563
- interaction ID. Restore them unchanged on reconnect. Commands, media, endings and interaction reports
2564
- retain the exact pair; never retarget an old command to the newest interaction of a journey.
2565
- `validateTaskCommandRequest` checks the request's pair against the supplied published task and
2566
- then its command prerequisites. The caller must select that task within the correct provider/login
2567
- and recheck at the provider; the validator cannot prove source freshness or authorization.
2556
+ prerequisites decide which controls are offered. Caller disconnect also executes at the provider. Microphone mute is agent application-owned, never a provider
2557
+ TaskCommand or task capability. The separately declared agent application recording facility keeps its existing
2558
+ recording contract; this distinction does not remove it or move provider call operations to the agent application.
2559
+
2560
+ A caller journey may revisit the same agent while an earlier interaction still wraps. Each is its
2561
+ own assignment, and two open at once carry two assignment ids. Restore them unchanged on
2562
+ reconnect. Commands, media, endings and history reports name the exact assignment; never retarget
2563
+ an old command to the newest interaction of a journey. `validateTaskCommandRequest` checks the
2564
+ request's assignment against the supplied published task and then its command prerequisites. The
2565
+ caller must select that task within the correct provider/login and recheck at the provider; the
2566
+ validator cannot prove source freshness or authorization.
2568
2567
  `task-ended` retires only that interaction's resources. Another interaction, caller channel or IVR/queue
2569
2568
  portion must not be cleared because this task ended. Snapshot counts include all still-owned wrap
2570
2569
  and active interactions; task completion is not caller hangup.
@@ -2615,7 +2614,7 @@ whether the channel carries real-time media:
2615
2614
  | Other non-media channels | The `task-updated` that moves the task to `completing` |
2616
2615
 
2617
2616
  **Off voice, `completing` is the provider's word that interaction ended.** There is no media event to
2618
- carry it, so the phase does; a host starts the wrap clock at that publication and nowhere else. It
2617
+ carry it, so the phase does; an agent application starts the wrap clock at that publication and nowhere else. It
2619
2618
  is optional: a conversation with nothing to wrap moves from `in-progress` to `task-ended` and
2620
2619
  `completing` is never published. Under `provider-automatic` with a non-zero `wrapAllowance` it is
2621
2620
  required, because the clock has to start somewhere: a chat or email task the provider completes
@@ -2661,7 +2660,7 @@ A task that declares `connectBack` lets the agent connect back to the party whil
2661
2660
  whoever placed the call in the first place. Most such calls came in, so this is not a redial: the
2662
2661
  agent rings a party who rang them. Omni issues `{ type: "connect-back", dialId }`; it is issuable
2663
2662
  only in `completing`, and only where the capability is declared. The provider knows who the party
2664
- is; the command carries no destination, and it is a dial like any other, so it carries the host's
2663
+ is; the command carries no destination, and it is a dial like any other, so it carries the agent application's
2665
2664
  `dialId`, is answered `dialling`, and ends in one `dial-outcome`.
2666
2665
 
2667
2666
  On `dialling` the provider is placing the call and the task returns to `in-progress`: the agent is
@@ -2672,15 +2671,15 @@ whose outcome says so and a call whose media ended: the task returns to `complet
2672
2671
  same event and the clock starts again from there. At no point is an agent dialling against a
2673
2672
  deadline.
2674
2673
 
2675
- **The room shows the party being dialled.** From the moment any host dial places the party -- a
2674
+ **The room shows the party being dialled.** From the moment any agent application dial places the party -- a
2676
2675
  dialpad call, a preview Call, a connect-back -- the `party` entry carries `stage: "ringing"` and
2677
- the host's `dialId`, exactly as a consulted or conferenced entry does from its dial; `joined` on
2676
+ the agent application's `dialId`, exactly as a consulted or conferenced entry does from its dial; `joined` on
2678
2677
  the publication that follows the answered `dial-outcome` and never before it
2679
2678
  (`stream.taskUpdated.stage`); and no stage from the next publication on, so `joined` is transient
2680
- and a later copy still carrying it is stale (`stream.taskUpdated.stage.lingering`). A host shows a
2679
+ and a later copy still carrying it is stale (`stream.taskUpdated.stage.lingering`). An agent application shows a
2681
2680
  call being placed, not a party it asserts is on a call that is still ringing. A callback the platform places itself on the same task -- the first
2682
2681
  call over, the platform dialling the party again without a command -- shows the same thing with no
2683
- host `dialId`, as any platform-placed dial does. A party with no stage is on the call, and a dial
2682
+ agent application `dialId`, as any platform-placed dial does. A party with no stage is on the call, and a dial
2684
2683
  with no stage is half a claim (`task.onCall.party.dial`). The stage is also what lets the stream
2685
2684
  tell a task coming back from one going backwards (`stream.taskUpdated.phase`).
2686
2685
 
@@ -2714,37 +2713,46 @@ const immediateProviderCompletion = {
2714
2713
  } satisfies Pick<Task, "completionMode" | "wrapAllowance">;
2715
2714
  ```
2716
2715
 
2717
- ### Interaction history
2716
+ ### History
2718
2717
 
2719
- The API uses the same interaction terminology: `interactionHistory`, `InteractionReport`,
2720
- `InteractionReportResult`, and the corresponding step types and validators. Hosts and providers
2721
- must adopt these names together; no legacy aliases are provided. The manifest's
2722
- `completionSettleMs` bounds final task completion, not entry into the `completing` wrap-up phase.
2723
- The `recordStep` method and `complete` command keep their existing names and behavior.
2718
+ The record is the call's, not the task's: most of what it holds happened before this agent, and
2719
+ `queued` and `offered` are not interactions at all, so the field is `history` and its types are
2720
+ `TaskHistory`, `TaskHistoryStep`, `HistoryStep`, `HistoryReport` and `HistoryReportResult`.
2721
+ *Interaction* keeps the one meaning **Terms** gives it, the agent's time on the call, which is why
2722
+ the total of earlier agents' time is `interactionSeconds` and the phase rules are
2723
+ `command.phase.interaction`. Hosts and providers adopt these names together; no legacy aliases
2724
+ are provided. The manifest's `completionSettleMs` bounds final task completion, not entry into
2725
+ the `completing` wrap-up phase. The `recordStep` method and `complete` command keep their names.
2724
2726
 
2725
- Migration from the earlier spelling:
2727
+ Migration from the earlier spellings:
2726
2728
 
2727
2729
  | Former API | Current API |
2728
2730
  | --- | --- |
2729
- | Task.handlingHistory | `Task.interactionHistory` |
2730
- | TaskHandlingHistory, TaskHandlingStep, HandlingStep | `TaskInteractionHistory`, `TaskInteractionStep`, `InteractionStep` |
2731
- | HandlingReport, HandlingReportResult, validateHandlingReport | `InteractionReport`, `InteractionReportResult`, `validateInteractionReport` |
2732
- | HANDLING_STEPS_WITH_A_PERSON, HANDLING_STEPS_THAT_DIAL | `INTERACTION_STEPS_WITH_A_PERSON`, `INTERACTION_STEPS_THAT_DIAL` |
2733
- | handlingStepExpectsAPerson, handlingStepDials | `interactionStepExpectsAPerson`, `interactionStepDials` |
2731
+ | Task.handlingHistory, Task.interactionHistory | `Task.history` |
2732
+ | TaskHandlingHistory, TaskInteractionHistory | `TaskHistory` |
2733
+ | TaskHandlingStep, HandlingStep, TaskInteractionStep, InteractionStep | `TaskHistoryStep`, `HistoryStep` |
2734
+ | HandlingReport, HandlingReportResult, validateHandlingReport, and their Interaction spellings | `HistoryReport`, `HistoryReportResult`, `validateHistoryReport` |
2735
+ | HANDLING_STEPS_WITH_A_PERSON, HANDLING_STEPS_THAT_DIAL, and their INTERACTION spellings | `HISTORY_STEPS_WITH_A_PERSON`, `HISTORY_STEPS_THAT_DIAL` |
2736
+ | handlingStepExpectsAPerson, handlingStepDials, and their interaction spellings | `historyStepExpectsAPerson`, `historyStepDials` |
2734
2737
  | handleSeconds | `interactionSeconds` |
2738
+ | Task.allocationId, AllocationId, allocationExpiresAt | `Task.assignmentId`, `AssignmentId`, `assignmentExpiresAt` |
2739
+ | Task.id, TaskId, and `taskId` on every event, command, report and lead request | gone: a task is named by `assignmentId` alone, and `taskKey(providerId, assignmentId)` scopes it |
2735
2740
  | Manifest.disposalSettleMs | `Manifest.completionSettleMs` |
2736
2741
 
2737
2742
  Update producers, consumers, saved task snapshots, and validation-rule assertions together.
2738
- History/report rule names now use `interactionHistory`/`interactionReport`; phase and conformance
2739
- rules use `interaction` and final-task rules use `completion`. Legacy fields are rejected even
2740
- when the new field is also supplied.
2743
+ History and report rule names use `history` and `historyReport`; assignment rules use
2744
+ `assignment` (`task.assignmentId`, `stream.taskOffered.duplicate`, `stream.assignment.ended`);
2745
+ phase and conformance rules use `interaction` and final-task rules use `completion`. The former
2746
+ fields are refused even when the new field is also supplied (`task.history.renamed`,
2747
+ `task.assignmentId.renamed` for a task's `id` or `allocationId`, `event.assignmentId.renamed`,
2748
+ `command.request.assignmentId.renamed` and `historyReport.assignmentId.renamed` for a `taskId`).
2741
2749
 
2742
2750
 
2743
- `Task.interactionHistory` is the call record: the steps that brought the task to the agent, oldest
2751
+ `Task.history` is the call record: the steps that brought the task to the agent, oldest
2744
2752
  first, and what they add up to before this agent:
2745
2753
 
2746
2754
  ```ts
2747
- interactionHistory: {
2755
+ history: {
2748
2756
  steps: [
2749
2757
  { step: "queued", at: "2026-08-21T00:59:00Z", seconds: 41 },
2750
2758
  { step: "answered", at: "2026-08-21T00:59:41Z", seconds: 312, by: "a-17" },
@@ -2767,7 +2775,7 @@ something else, which will arrive under its own name and must not be folded in h
2767
2775
  It rides in the snapshot and is replaced whole like everything else there.
2768
2776
 
2769
2777
  Steps are `queued`, `offered`, `answered`, `held`, `muted`, `transferred`, `conferenced`,
2770
- `unanswered`, and each is defined on `TaskInteractionStep`.
2778
+ `unanswered`, and each is defined on `TaskHistoryStep`.
2771
2779
 
2772
2780
  **The record is one entry per occurrence, oldest first.** Each hold is its own `held` entry — `at`
2773
2781
  when it began, `seconds` once it ended and omitted while it runs — and a second hold is a second
@@ -2775,20 +2783,20 @@ entry after the first, never a revision of it. A leg that has ended states its d
2775
2783
  task says whether a leg can still be running: a hold runs only while the task is `paused`, a mute
2776
2784
  only while its media is up, so a `held` entry without `seconds` on a task that is not paused, or a
2777
2785
  `muted` one on a call that is over, is a leg nobody closed and reads exactly like a leg running now
2778
- (`task.interactionHistory.held.open`, `.muted.open`). Whoever performs the leg closes it — the
2779
- provider whose platform parks the caller, the host whose microphone it is — by restating the entry
2786
+ (`task.history.held.open`, `.muted.open`). Whoever performs the leg closes it — the
2787
+ provider whose platform parks the caller, the agent application whose microphone it is — by restating the entry
2780
2788
  with its duration, and **an entry that cannot be closed is not written**: open for ever is a
2781
2789
  plausible nought one level down from a total. **A leg still open when the media ends is closed by
2782
2790
  the provider**, at that instant, in the same publication that says the media ended: the provider
2783
- is the one that knows the instant, and the host can only learn of it afterwards. Agents end calls
2784
- muted, so the host's leg is routinely open at media end; the provider closes it with the duration
2785
- from the leg's `at` to the media's end, and the host's own closing report for that leg, which
2791
+ is the one that knows the instant, and the agent application can only learn of it afterwards. Agents end calls
2792
+ muted, so the agent application's leg is routinely open at media end; the provider closes it with the duration
2793
+ from the leg's `at` to the media's end, and the agent application's own closing report for that leg, which
2786
2794
  follows what it hears, is answered `recorded` and changes nothing, the entry standing as the
2787
2795
  provider closed it. One publisher of the closed leg, and no order between them to get right. There is no resumed step; a resume is the end of a
2788
2796
  hold, at the entry's `at` plus its `seconds`, and nothing is lost by not naming it twice. The same goes for every step: two mutes are two
2789
2797
  `muted` entries, and a call that joined two queues -- a menu's, then this one -- has two `queued`
2790
2798
  entries, one per join. Order is enforced: an entry earlier than the one before it is refused
2791
- (`task.interactionHistory.order`). **Intervals between steps are the host's to subtract**, never a
2799
+ (`task.history.order`). **Intervals between steps are the agent application's to subtract**, never a
2792
2800
  total the provider adds: *time to offer*, from the call's arrival to the agent's screen lighting
2793
2801
  up, is the `offered` entry's `at` minus the last `queued` entry's, and the ring is outside it.
2794
2802
  `queueSeconds` keeps the industry's meaning -- the whole wait until somebody answered -- and is not
@@ -2798,32 +2806,32 @@ grain: rounded to the nearest second, and a leg that rounds to nought is stated
2798
2806
  being under the contract's resolution, where dropping the entry would say the leg never happened.
2799
2807
 
2800
2808
  **A record once read is not unread.** Every restatement of a task's record -- on `task-updated`,
2801
- on a resync snapshot -- carries every entry the host has already read, by step and instant, and
2809
+ on a resync snapshot -- carries every entry the agent application has already read, by step and instant, and
2802
2810
  may add to them; it never has fewer, and never drops the record while the task is open. A fact
2803
- stated to the host and then withdrawn without an event is a record contradicting itself, exactly
2811
+ stated to the agent application and then withdrawn without an event is a record contradicting itself, exactly
2804
2812
  as a task that lost the terms it had read would be, and the stream refuses it the same way
2805
- (`stream.taskUpdated.interactionHistory`, `stream.snapshot.interactionHistory`). A provider whose
2806
- platform cannot hold a leg the host reported keeps it in the login's `store` for the life of the
2807
- task, so a reload of the host restates the same record; the entry is keyed by `step` and `at`, so
2813
+ (`stream.taskUpdated.history`, `stream.snapshot.history`). A provider whose
2814
+ platform cannot hold a leg the agent application reported keeps it in the login's `store` for the life of the
2815
+ task, so a reload of the agent application restates the same record; the entry is keyed by `step` and `at`, so
2808
2816
  a running hold restated with its final `seconds` is the same entry.
2809
2817
 
2810
- **The provider owns the timestamps in its record.** Host timestamps are advisory. The provider
2811
- may retain a host instant it accepts or assign its own observation/receipt instant; it need not
2812
- copy the host clock. A provider declaring `timestampAuthority: "provider"` uses its own timestamps
2818
+ **The provider owns the timestamps in its record.** Agent application timestamps are advisory. The provider
2819
+ may retain an agent application instant it accepts or assign its own observation/receipt instant; it need not
2820
+ copy the agent application clock. A provider declaring `timestampAuthority: "provider"` uses its own timestamps
2813
2821
  for final records. Receipt time is an observation boundary, not a claim about when the physical
2814
- host action happened. Records are ordered by their published provider-selected instants, with no
2815
- rewriting of an already-published entry when a later host report arrives.
2822
+ agent application action happened. Records are ordered by their published provider-selected instants, with no
2823
+ rewriting of an already-published entry when a later agent application report arrives.
2816
2824
 
2817
- The incoming host `step` and `at`, scoped to the task and its current life, identify one reported
2825
+ The incoming agent application `step` and `at`, scoped to the task and its current life, identify one reported
2818
2826
  leg for correlation only. The provider retains a binding from that key to its chosen history
2819
2827
  `at`. Every successful `recordStep` returns `{ status: "recorded", at }` with that same canonical
2820
- history instant, even for subsequent duration/end reports. The host keeps sending the original
2821
- report key, never the returned history timestamp. A changed host timestamp is not a correction
2828
+ history instant, even for subsequent duration/end reports. The agent application keeps sending the original
2829
+ report key, never the returned history timestamp. A changed agent application timestamp is not a correction
2822
2830
  to the same report: it names a different leg. Bindings survive reconnect/reload for the retained
2823
- task lifetime. The host renders provider-published history unchanged. It never compares the
2831
+ task lifetime. The agent application renders provider-published history unchanged. It never compares the
2824
2832
  provider instant back to its own clock, substitutes its own timestamp, or adjusts later messages
2825
- to match an earlier host estimate. The acknowledgment identifies the provider record for
2826
- correlation/conformance only; it is not a host-side timestamp reconciliation instruction. Conflicting reuse is refused visibly, not paired by arrival time or nearest instant.
2833
+ to match an earlier agent application estimate. The acknowledgment identifies the provider record for
2834
+ correlation/conformance only; it is not an application-side timestamp reconciliation instruction. Conflicting reuse is refused visibly, not paired by arrival time or nearest instant.
2827
2835
  If two distinct entries would collide under the history's `(step, at)` key, do not invent a time
2828
2836
  or combine them: report the representation conflict. No ambiguous event is silently accepted.
2829
2837
 
@@ -2833,17 +2841,17 @@ history — until the task's media ends, and a hold neither pauses nor resets it
2833
2841
  duration is the `held` entry's `seconds`, and a desk that restarts its counter on resume is
2834
2842
  counting the wrong thing.
2835
2843
 
2836
- `muted` is there because the mute is the host's and never the provider's — see **The station is
2837
- the host's** — so without a step the provider, which alone keeps the task's record, would have no
2838
- account of a period the agent could not be heard. Each `muted` entry carries `mutedBy`, as the host
2839
- reported it: `host` for the agent's own Mute, `station` for a headset or system mute the host
2840
- observed. No other step has it (`task.interactionHistory.mutedBy`, `.mutedBy.unexpected`).
2844
+ `muted` is there because the mute is the agent application's and never the provider's — see **The station is
2845
+ the agent application's** — so without a step the provider, which alone keeps the task's record, would have no
2846
+ account of a period the agent could not be heard. Each `muted` entry carries `mutedBy`, as the agent application
2847
+ reported it: `host` for the agent's own Mute, `station` for a headset or system mute the agent application
2848
+ observed. No other step has it (`task.history.mutedBy`, `.mutedBy.unexpected`).
2841
2849
 
2842
2850
  **A step that dialled says which dial and where.** `transferred`, `conferenced` and `unanswered`
2843
- each end a dial, so the entry carries the `destinationId` it went to and, where a host placed it, the
2844
- `dialId` the host minted; no other step dialled, and either field on one is refused
2845
- (`task.interactionHistory.dialId.unexpected`). This is how a dial made before a transfer is placeable
2846
- by whoever holds the task now: a `dial-outcome` naming a `dialId` the host never minted is looked
2851
+ each end a dial, so the entry carries the `destinationId` it went to and, where an agent application placed it, the
2852
+ `dialId` the agent application minted; no other step dialled, and either field on one is refused
2853
+ (`task.history.dialId.unexpected`). This is how a dial made before a transfer is placeable
2854
+ by whoever holds the task now: a `dial-outcome` naming a `dialId` the agent application never minted is looked
2847
2855
  up in the record, not discarded.
2848
2856
 
2849
2857
  Four rules a provider has to keep:
@@ -2859,16 +2867,16 @@ Four rules a provider has to keep:
2859
2867
  the same way `ForcedBreak.by` does. It comes from this provider's own directory, the same
2860
2868
  namespace as `AuthenticationState.identity.id` and the team member list, so entries pair
2861
2869
  within a provider and never across one.
2862
- - **A task carries no names.** Omni resolves what to display with `describeUsers()`. Two people
2870
+ - **A task carries no names.** Omni resolves what to display with `getUserDetails()`. Two people
2863
2871
  called Arun on one site is ordinary, and anything pairing entries on a display name pairs them
2864
2872
  wrongly; carrying the name here would also copy it into every task and leave it to go stale.
2865
2873
 
2866
2874
  **An absent `by` means different things on different steps, and both are legitimate.** On
2867
2875
  `queued` nobody takes part, so there is nothing to name. On every other step somebody did — see
2868
- `INTERACTION_STEPS_WITH_A_PERSON` and `interactionStepExpectsAPerson()` — so an absent `by` there says
2876
+ `HISTORY_STEPS_WITH_A_PERSON` and `historyStepExpectsAPerson()` — so an absent `by` there says
2869
2877
  *this was handled and the provider cannot say by whom*. The one step that is never unattributed is
2870
- `muted`: the host has exactly one agent and the provider knows who, so `by` is required there
2871
- (`task.interactionHistory.muted.by`).
2878
+ `muted`: the agent application has exactly one agent and the provider knows who, so `by` is required there
2879
+ (`task.history.muted.by`).
2872
2880
 
2873
2881
  That case is ordinary rather than theoretical: a leg answered on a shared phone, a manager's
2874
2882
  handset, or a device the provider cannot resolve to a person. **Report the step without `by`
@@ -2876,11 +2884,11 @@ rather than dropping it.** A list missing a real handler looks complete and is w
2876
2884
  worse than one saying plainly it could not attribute a leg — and far better than publishing
2877
2885
  nothing because a single leg could not be named.
2878
2886
 
2879
- A host must render the two differently. Showing an unattributed `answered` the same way as
2887
+ An agent application must render the two differently. Showing an unattributed `answered` the same way as
2880
2888
  `queued` tells the agent nobody was involved, which is not what was said. Omni renders it as
2881
2889
  *"not recorded"* in the place the name would go.
2882
2890
 
2883
- Omit `interactionHistory` entirely when the provider cannot observe the steps. Empty `steps` is a
2891
+ Omit `history` entirely when the provider cannot observe the steps. Empty `steps` is a
2884
2892
  different claim — it says the task has had none.
2885
2893
 
2886
2894
  **What the record adds up to is stated, not summed.** A call that has changed hands arrives
@@ -2893,45 +2901,44 @@ zeros. The record is restated with the task on every `task-updated` and snapshot
2893
2901
  that arrives late corrects the sums. These four are what every platform reports; more will be
2894
2902
  added here as a need is shown, not invented ahead of one.
2895
2903
 
2896
- #### The host records what it performs
2904
+ #### The agent application records what it performs
2897
2905
 
2898
- `muted` is the one leg the host performs rather than the provider, and a record kept by the
2899
- provider would have a hole exactly there. So the host reports it, through `recordStep`, and the provider
2906
+ `muted` is the one leg the agent application performs rather than the provider, and a record kept by the
2907
+ provider would have a hole exactly there. So the agent application reports it, through `recordStep`, and the provider
2900
2908
  writes it into its record as it writes every other leg:
2901
2909
 
2902
2910
  ```ts
2903
2911
  declare const connection: Connection<"voice">;
2904
- declare const taskId: TaskId;
2905
- declare const allocationId: AllocationId;
2912
+ declare const assignmentId: AssignmentId;
2906
2913
  declare const at: IsoTimestamp;
2907
2914
 
2908
- void connection.recordStep?.({ taskId, allocationId, step: "muted", at, mutedBy: "host" }); // the moment the agent mutes
2909
- void connection.recordStep?.({ taskId, allocationId, step: "muted", at, mutedBy: "host", seconds: 15 }); // still running, if the host chooses to say
2910
- void connection.recordStep?.({ taskId, allocationId, step: "muted", at, mutedBy: "host", seconds: 42, ended: true }); // the moment they unmute
2915
+ void connection.recordStep?.({ assignmentId, step: "muted", at, mutedBy: "host" }); // the moment the agent mutes
2916
+ void connection.recordStep?.({ assignmentId, step: "muted", at, mutedBy: "host", seconds: 15 }); // still running, if the agent application chooses to say
2917
+ void connection.recordStep?.({ assignmentId, step: "muted", at, mutedBy: "host", seconds: 42, ended: true }); // the moment they unmute
2911
2918
  ```
2912
2919
 
2913
- Every report about one leg repeats its original `step` and host `at` as a correlation key;
2914
- the published history uses the provider-selected `at` returned by `recordStep`. The host reports
2920
+ Every report about one leg repeats its original `step` and agent application `at` as a correlation key;
2921
+ the published history uses the provider-selected `at` returned by `recordStep`. The agent application reports
2915
2922
  the action it performed and its measured duration, not an authoritative provider timestamp. It may say how long so far — `seconds` is
2916
2923
  elapsed while the leg runs and final once it has ended — and **the end is stated, never
2917
2924
  inferred**: `ended: true` marks the last report, and it carries the final duration. **What a
2918
2925
  provider never asked for never crosses.** The running report is sent only to a provider whose
2919
2926
  manifest declares `runningStepReports`; every other provider receives exactly two reports per
2920
- leg, when it began and when it ended, and `validateInteractionReport(report, path, manifest)` refuses
2921
- a running one it was never asked for (`interactionReport.running.unexpected`). What a provider that
2927
+ leg, when it began and when it ended, and `validateHistoryReport(report, path, manifest)` refuses
2928
+ a running one it was never asked for (`historyReport.running.unexpected`). What a provider that
2922
2929
  did ask for them forwards upstream, and how often, is its own business. The step appears in
2923
- `interactionHistory` when the *provider* publishes it: Omni never writes the record itself.
2930
+ `history` when the *provider* publishes it: Omni never writes the record itself.
2924
2931
  `recordStep` is required of every softphone login's connection, since every call on a softphone
2925
- can be muted by the host, and answers `recorded` with the canonical history `at`. A `muted` report says whose the silence was,
2926
- `mutedBy: "host"` or `"station"`, and no other report has the word (`interactionReport.mutedBy`,
2932
+ can be muted by the agent application, and answers `recorded` with the canonical history `at`. A `muted` report says whose the silence was,
2933
+ `mutedBy: "host"` or `"station"`, and no other report has the word (`historyReport.mutedBy`,
2927
2934
  `.mutedBy.unexpected`). On a desk phone the microphone is the phone's:
2928
- the host mutes nothing and records nothing.
2935
+ the agent application mutes nothing and records nothing.
2929
2936
 
2930
- **The provider's confirmed end is decisive.** The host keeps local state for interaction and
2937
+ **The provider's confirmed end is decisive.** The agent application keeps local state for interaction and
2931
2938
  reporting, but follows the provider's authoritative state. When the provider publishes the end
2932
- of the current mute leg, the host ends that local mute and releases its host-controlled mute
2939
+ of the current mute leg, the agent application ends that local mute and releases its agent application-controlled mute
2933
2940
  on the matching task's media. It does not wait for its own timer, reopen the leg, replace the
2934
- provider timestamp, or overwrite the provider's final duration with a later host report.
2941
+ provider timestamp, or overwrite the provider's final duration with a later agent application report.
2935
2942
  A later agent mute is a new leg, never a reopening of the ended one.
2936
2943
 
2937
2944
  Correlate the provider-published `muted` entry using the provider-selected `at` acknowledged
@@ -2939,15 +2946,15 @@ for the current report key; a final `seconds` closes that leg under the history
2939
2946
  This is identity matching, not reconciliation between clocks. An old closed entry, an unrelated
2940
2947
  task, or a stale connection cannot end a newer local mute. If publication precedes the acknowledgment,
2941
2948
  retain the current provider view and apply the matching closure once correlation is available;
2942
- never guess a match from arrival order or nearest timestamp. Failure to release a host-controlled
2949
+ never guess a match from arrival order or nearest timestamp. Failure to release an agent application-controlled
2943
2950
  mute is reported visibly; local device reports still describe the actual device state.
2944
2951
 
2945
- At a provider-confirmed task/media end, the host also stops the associated local mute and reports
2946
- its observed ending where the report is still accepted. A host closing report repeats its original
2952
+ At a provider-confirmed task/media end, the agent application also stops the associated local mute and reports
2953
+ its observed ending where the report is still accepted. An agent application closing report repeats its original
2947
2954
  key and may include its measured duration, but cannot reverse an already confirmed provider end.
2948
2955
  The provider acknowledges a known closed leg without rewriting its final record; after the task
2949
- has been completed, it may refuse the report as task-not-found. The host reads that response rather
2950
- than retrying or recreating the task. An observed host end before a provider closure is still
2956
+ has been completed, it may refuse the report as task-not-found. The agent application reads that response rather
2957
+ than retrying or recreating the task. An observed agent application end before a provider closure is still
2951
2958
  reported normally; the provider decides the final timestamp and publishes the record.
2952
2959
 
2953
2960
  ### Browser capability
@@ -2981,7 +2988,7 @@ Each `TaskBrowser` defines one named browser in the task workspace.
2981
2988
  | `url` | Initial URL. Must use `http:` or `https:`; see below. Later navigation comes from Chromium. |
2982
2989
  | `sharedSession` | Required. `false` creates a task-specific browser session. |
2983
2990
  | `isolationScheme` | **Required when `sharedSession` is `true`**, and rejected when it is `false`. There is no default: see below. |
2984
- | `urlVisibility` | What the agent sees of this tab's URL in Omni's chrome: `hidden`, `domain`, or `full`. Omitted, the URL shows as any browser's does; a provider says `hidden` where the URL carries what the agent may not read — a caller's number, a CRM token. Per browser, on the provider's word; a host that declares `guarantees.browserUrlVisibility` honours it tab by tab, and a provider checks that guarantee before it sends such a URL at all. |
2991
+ | `urlVisibility` | What the agent sees of this tab's URL in Omni's chrome: `hidden`, `domain`, or `full`. Omitted, the URL shows as any browser's does; a provider says `hidden` where the URL carries what the agent may not read — a caller's number, a CRM token. Per browser, on the provider's word; an agent application that declares `guarantees.browserUrlVisibility` honours it tab by tab, and a provider checks that guarantee before it sends such a URL at all. |
2985
2992
 
2986
2993
  ##### Choosing an isolation scheme
2987
2994
 
@@ -3042,7 +3049,7 @@ The supported `BrowserIsolationScheme` values, declared under **Shapes**, key as
3042
3049
 
3043
3050
  | Enum member | Example session key |
3044
3051
  | --- | --- |
3045
- | `PROVIDER_NAME__TASK_ID__TAB_NAME` | `mailflow.EMAIL-829102%2Ea1.CRM` -- the task's allocation, so one life of the id, never the next customer's cookies |
3052
+ | `PROVIDER_NAME__TASK_ID__TAB_NAME` | `mailflow.EMAIL-829102%2Ea1.CRM` -- the task's assignment id, so one assignment, never the next customer's cookies; the scheme's name is a stable wire value and keeps its spelling |
3046
3053
  | `TAB_NAME` | `CRM` |
3047
3054
  | `PROVIDER_NAME__TASK_TYPE_NAME__TAB_NAME` | `mailflow.Support.CRM` |
3048
3055
  | `PROVIDER_NAME__TAB_NAME` | `mailflow.CRM` |
@@ -3072,8 +3079,8 @@ that produces two consumers disagreeing about one fact. The task is the one sour
3072
3079
  provider puts on the task what the platform permits for it -- and says, in `capabilitySource`, who
3073
3080
  chose those terms. `queue` says somebody configured them. `ungoverned` says nothing handed the work
3074
3081
  over: an agent's own outbound call has no queue behind it, and the provider states what it permits
3075
- for such a call. Neither changes where a host reads the capabilities from, which is the task; the
3076
- source is one more published fact about them, and the one that lets a host tell a fact from a fault
3082
+ for such a call. Neither changes where an agent application reads the capabilities from, which is the task; the
3083
+ source is one more published fact about them, and the one that lets an agent application tell a fact from a fault
3077
3084
  (see below).
3078
3085
 
3079
3086
  **Completing the task is not a capability, and no capability set withholds it.** `complete` is
@@ -3092,14 +3099,14 @@ task said so both times, at the moment it became true. A call moves queues the s
3092
3099
  identified as a priority customer is transferred to the priority queue, and the task arrives under
3093
3100
  that queue's terms -- a longer wrap allowance, a discount control the general queue never offered --
3094
3101
  restated on the task at the hand-over, not inferred from the queue it left. A capability stated
3095
- once at offer or answer and never corrected is a fact with a shelf life and no expiry, and a host
3102
+ once at offer or answer and never corrected is a fact with a shelf life and no expiry, and an agent application
3096
3103
  draws a control the provider will now refuse -- or withholds one the agent now has. So the provider republishes
3097
- the task, with its capabilities as they now stand, and a host treats the last statement as current
3104
+ the task, with its capabilities as they now stand, and an agent application treats the last statement as current
3098
3105
  rather than re-deriving anything. This is the same shape as a room left full after the call ends
3099
3106
  -- a field describing the present, carried past the moment it stopped being true -- carried past
3100
3107
  this time not by a spread but by nobody sending the correction. A provider whose platform can
3101
3108
  change a permission mid-task and does not republish is in breach, however conformant its offer was.
3102
- A capability set can shrink as well as grow, and a host that has only ever seen it grow meets a
3109
+ A capability set can shrink as well as grow, and an agent application that has only ever seen it grow meets a
3103
3110
  control that was there a moment ago and is gone; a command that arrives after its capability was
3104
3111
  withdrawn is refused with a reason, never acted on. The asymmetry decides which direction a
3105
3112
  provider gets right first: a control gained late is a nicety, a control withdrawn and not
@@ -3108,12 +3115,12 @@ direction: the task as offered and as republished, and one command that was issu
3108
3115
  first and is refused under the last for want of the capability withdrawn -- and nothing else.
3109
3116
 
3110
3117
  **An empty capability set is a statement, not a shrug.** `capabilities: {}` under `queue` or
3111
- `ungoverned` says the platform permits nothing capability-gated on this task, and a host draws
3118
+ `ungoverned` says the platform permits nothing capability-gated on this task, and an agent application draws
3112
3119
  nothing beyond what the phase and `completionMode` require. A provider that has not yet learned
3113
3120
  what the platform permits -- a queue's configuration that has not reached it -- knows nothing of
3114
3121
  the kind, and must not publish the task as if it did, neither as `{}` nor as every control it has.
3115
3122
  It publishes the task under `capabilitySource: "undetermined"`, with the capabilities it will
3116
- honour until it knows, and a host shows that where the agent works, beside the controls it draws
3123
+ honour until it knows, and an agent application shows that where the agent works, beside the controls it draws
3117
3124
  from them: "no queue governs this call" is a fact, "the configuration has not arrived" is a fault,
3118
3125
  and the set alone cannot tell them apart, so the provider says which. What a provider honours
3119
3126
  under undetermined terms is its own call -- a floor that would rather an agent briefly hold a
@@ -3126,7 +3133,7 @@ Terms once read stay read: a re-read that fails mid-task is not a new fact about
3126
3133
  last statement stands and the failure is a `diagnostic`, and a task that was published under
3127
3134
  `queue` or `ungoverned` never returns to `undetermined`, on an update (`stream.taskUpdated.capabilitySource`)
3128
3135
  or on a resync snapshot (`stream.snapshot.capabilitySource`); a record once read never loses an
3129
- entry the same two ways (`stream.taskUpdated.interactionHistory`, `stream.snapshot.interactionHistory`);
3136
+ entry the same two ways (`stream.taskUpdated.history`, `stream.snapshot.history`);
3130
3137
  a snapshot carrying a task still at work does not forget the audio the stream held up, since media
3131
3138
  ends on `task-media-ended` and the call moves on (`stream.snapshot.media`); a voice task ends after
3132
3139
  its audio ends, never around it, whatever the outcome (`stream.taskEnded.mediaOpen`); and a task does not go
@@ -3158,9 +3165,9 @@ a message that shows and clears has said nothing about the buttons still on the
3158
3165
  words are close in English and far apart on the desk: `ungoverned` is silence, `undetermined` is a
3159
3166
  standing notice.
3160
3167
 
3161
- One consequence for whoever builds the host: because a conformance run fails on `undetermined`, a
3162
- conformant adapter never shows a host `undetermined` under test, and a clean `exerciseAdapter`
3163
- result says nothing about how the host renders it. That rendering is tested against a fixture --
3168
+ One consequence for whoever builds the agent application: because a conformance run fails on `undetermined`, a
3169
+ conformant adapter never shows an agent application `undetermined` under test, and a clean `exerciseAdapter`
3170
+ result says nothing about how the agent application renders it. That rendering is tested against a fixture --
3164
3171
  a task published under `undetermined` shows the notice, the same task under `queue` shows none --
3165
3172
  and never against an adapter, even in principle. `exerciseAdapter` treats a
3166
3173
  task published under `undetermined` as a violation (`capabilitySource.undetermined`), as it treats
@@ -3187,7 +3194,7 @@ See **Which commands need a capability**.
3187
3194
 
3188
3195
  | Capability | Omni UI | Contract |
3189
3196
  | --- | --- | --- |
3190
- | `decline` | Pending-task button: Decline | The provider can decline a pending voice offer. Omni shows it only when provisioning also permits declining. |
3197
+ | `decline` | Pending-task button: Decline | The provider can decline a pending voice offer. Omni shows it only when local policy also permits declining. |
3191
3198
  | `hold` | Primary toggle: Hold | Omni may issue voice-task `hold` and `resume` commands. |
3192
3199
  | `endCall` | Primary button: End call | The provider ends the caller connection and all owned/inherited agent-added channels; wrap/completion remain separate. See **Ending a call, and removing one person from it**. |
3193
3200
  | `connectBack` | Completing-task button: Connect back | Omni may have the provider connect the agent back to the task's party while the task is `completing`, returning it to `in-progress` on the same task. Not offered where there is no `completing` window: `provider-automatic` with a zero allowance completes the task at provider end. See **Connecting back during completion**. |
@@ -3195,7 +3202,7 @@ See **Which commands need a capability**.
3195
3202
  | `warmTransfer` | Secondary menu item: Warm transfer | Omni may park the customer and call a destination first, then hand the customer over or cancel back. See **Warm transfer**. |
3196
3203
  | `leadAssist` | Secondary menu item: Lead assist | Omni may ask a lead to join this call, with a note. The lead's decision reaches the agent on `Task.leadAssist`. See **Lead assist**. |
3197
3204
  | `conference` | Secondary button: Conference | Omni may dial a destination into the active call, and remove one person from it -- a conferenced entry, one still ringing included, which calls the dial off, or the party, leaving the agent with the colleague. See **Ending a call, and removing one person from it**. |
3198
- | `recording` | Overflow menu item: Recording | Per-task provider and host policies expose only their permitted recording actions; each has independent state and routing. |
3205
+ | `recording` | Overflow menu item: Recording | Per-task provider and agent application policies expose only their permitted recording actions; each has independent state and routing. |
3199
3206
  | `outcomes` | Primary button: Complete | Omni may request task completion with a provider outcome and notes. |
3200
3207
 
3201
3208
  ### Publishing codes and destinations
@@ -3277,7 +3284,7 @@ reason (`task.destinations.shape`): once nothing is typed, the directory is the
3277
3284
 
3278
3285
  **The provider chooses the supported destinations.** A published item may route to an IVR,
3279
3286
  queue, named agent or another configured destination. No destination kind is inferred from its
3280
- label. The host offers only the directory attached to this task's specific transfer capability,
3287
+ label. The agent application offers only the directory attached to this task's specific transfer capability,
3281
3288
  and sends the exact destination ID; it does not invent an agent picker or arbitrary dial target.
3282
3289
  The provider rechecks eligibility and executes the routing. Returning to an IVR or queue does not
3283
3290
  end the caller journey; a later assignment to the same agent is a new interaction.
@@ -3293,19 +3300,19 @@ provider.
3293
3300
  { type: "conference", action: "remove", destinationId: "tier2" } // the conferenced person leaves; ringing, this calls the dial off
3294
3301
  ```
3295
3302
 
3296
- The host sends the ordinary task-scoped `execute` request with `command: { type: "end-call" }`.
3303
+ The agent application sends the ordinary task-scoped `execute` request with `command: { type: "end-call" }`.
3297
3304
  The provider knows the caller and agent-added channel bindings; no channel list or owner details
3298
- are sent by the host. The task's `endCall` capability is permission, not an executor selection.
3299
- `validateTaskCommandRequest` checks the exact interaction/allocation and delegates the command's
3305
+ are sent by the agent application. The task's `endCall` capability is permission, not an executor selection.
3306
+ `validateTaskCommandRequest` checks the exact interaction/assignment and delegates the command's
3300
3307
  policy/phase checks. The provider rechecks current ownership atomically; no client validator can
3301
- prove that its view is fresh. The host does not implement agent end-call; low-level removal of individual channels is not
3302
- this agent action. There is no host end-call execution API or fallback route.
3308
+ prove that its view is fresh. The agent application does not implement agent end-call; low-level removal of individual channels is not
3309
+ this agent action. There is no agent application end-call execution API or fallback route.
3303
3310
 
3304
3311
  `end-call` is gated by `endCall` on the current interaction. It ends the caller connection and
3305
3312
  all agent-added channels owned by that interaction, including channels originally added by previous
3306
3313
  agents and inherited through transfer or takeover. Ownership is not inferred from who originally
3307
3314
  dialed, the current UI selection, or a person's label. The provider maintains that authority
3308
- and checks the exact interaction/allocation when acting. Agent-added channels are not left behind
3315
+ and checks the exact interaction/assignment when acting. Agent-added channels are not left behind
3309
3316
  merely because another agent added them.
3310
3317
 
3311
3318
  On a successful transfer or takeover, ownership of those channels passes to the receiving
@@ -3351,7 +3358,7 @@ offer any of the three without the others, and each is declared on its own.
3351
3358
  ```
3352
3359
 
3353
3360
  `warm` is gated by the `warmTransfer` capability and names a directory item exactly as a cold
3354
- transfer does, from the same kind of directory. It is a dial, so it carries the host's `dialId`
3361
+ transfer does, from the same kind of directory. It is a dial, so it carries the agent application's `dialId`
3355
3362
  and is answered `dialling`, and its `dial-outcome` says whether the destination was reached. While
3356
3363
  the destination is on the line the task carries a `consulted` entry on `onCall`, and that presence
3357
3364
  is what makes `complete` and `cancel` issuable -- they name no destination because there is exactly
@@ -3377,7 +3384,7 @@ customer.
3377
3384
 
3378
3385
  | Capability | Omni UI | Contract |
3379
3386
  | --- | --- | --- |
3380
- | `decline` | Pending-task button: Decline | The provider can decline a pending chat offer. Omni shows it only when provisioning also permits declining. |
3387
+ | `decline` | Pending-task button: Decline | The provider can decline a pending chat offer. Omni shows it only when local policy also permits declining. |
3381
3388
  | `hold` | Primary toggle: Hold | Omni may pause and resume the agent’s interaction in the chat. |
3382
3389
  | `outcomes` | Primary button: Complete | Omni may request task completion with a provider outcome and notes. |
3383
3390
 
@@ -3385,7 +3392,7 @@ customer.
3385
3392
 
3386
3393
  | Capability | Omni UI | Contract |
3387
3394
  | --- | --- | --- |
3388
- | `decline` | Pending-task button: Decline | The provider can decline a pending email offer. Omni shows it only when provisioning also permits declining. |
3395
+ | `decline` | Pending-task button: Decline | The provider can decline a pending email offer. Omni shows it only when local policy also permits declining. |
3389
3396
  | `outcomes` | Primary button: Complete | Omni may request task completion with a provider outcome and notes. |
3390
3397
 
3391
3398
  ### Custom capabilities
@@ -3420,7 +3427,7 @@ control and invokes it with the shared custom task command:
3420
3427
  }
3421
3428
  ```
3422
3429
 
3423
- `name` is the `id` of the custom capability the agent used. There is no `taskId` here: like every
3430
+ `name` is the `id` of the custom capability the agent used. There is no `assignmentId` here: like every
3424
3431
  other command it travels on the `TaskCommandRequest` around it. A `toggle` carries the state it
3425
3432
  wants — `{ type: "custom", name: "mark-vip", on: true }` — never a flip, for the reason under
3426
3433
  **Task commands**.
@@ -3434,7 +3441,7 @@ Custom capabilities must not redefine the meaning of a standard channel capabili
3434
3441
  Starts one outbound call from the idle dialpad. It is present only when the voice provider
3435
3442
  declares `dial`.
3436
3443
 
3437
- - `dialId` is the host's identity for this dial, minted before the request leaves.
3444
+ - `dialId` is the agent application's identity for this dial, minted before the request leaves.
3438
3445
  - `destination` is the original number selected or entered by the agent.
3439
3446
  - The provider holds `destination` to its declared `destinations`: under `contacts-only`, a
3440
3447
  number that is not one of its contacts answers `failed` with `omni.destination-not-permitted`.
@@ -3454,43 +3461,42 @@ and apart from its answer -- the destination picks up, is busy, or never does --
3454
3461
  late in a call routinely outlives the call. Nothing in between is reported: the wire says
3455
3462
  `dialling`, then says how it ended, once.
3456
3463
 
3457
- **The host mints the identity.** Every command that dials carries a `dialId` the host made, unique
3464
+ **The agent application mints the identity.** Every command that dials carries a `dialId` the agent application made, unique
3458
3465
  across the installation, and it travels four ways so no leg is a lookup:
3459
3466
 
3460
3467
  ```ts
3461
3468
  declare const connection: Connection<"voice">;
3462
- declare const taskId: TaskId;
3463
- declare const allocationId: AllocationId;
3469
+ declare const assignmentId: AssignmentId;
3464
3470
 
3465
- // 1. Out, minted by the host.
3466
- const result = await connection.execute({ taskId, allocationId, command: { type: "conference", action: "add", dialId: "dial-7f2", destinationId: "tier2" } });
3471
+ // 1. Out, minted by the agent application.
3472
+ const result = await connection.execute({ assignmentId, command: { type: "conference", action: "add", dialId: "dial-7f2", destinationId: "tier2" } });
3467
3473
 
3468
- // 2. Back on the result, restated, so the host compares and confirms.
3474
+ // 2. Back on the result, restated, so the agent application compares and confirms.
3469
3475
  expect(result).toEqual({ status: "dialling", dialId: "dial-7f2" });
3470
3476
 
3471
3477
  // 3. On the outcome, however late, against the task it belonged to.
3472
- const outcome: ProviderEvent<"voice"> = { type: "dial-outcome", dialId: "dial-7f2", taskId, allocationId, destinationId: "tier2", outcome: "no-answer", reason: "No route to destination" };
3478
+ const outcome: ProviderEvent<"voice"> = { type: "dial-outcome", dialId: "dial-7f2", assignmentId, destinationId: "tier2", outcome: "no-answer", reason: "No route to destination" };
3473
3479
 
3474
3480
  // 4. In the record, so a dial made before a transfer is placeable by whoever holds the task now.
3475
- const step: TaskInteractionStep = { step: "unanswered", at: "2026-08-21T09:15:30Z", by: "A-12", dialId: "dial-7f2", destinationId: "tier2" };
3481
+ const step: TaskHistoryStep = { step: "unanswered", at: "2026-08-21T09:15:30Z", by: "A-12", dialId: "dial-7f2", destinationId: "tier2" };
3476
3482
  ```
3477
3483
 
3478
- The identity is a correlation handle between host and provider and **is never shown to the
3479
- agent**. A host holding several tasks places an outcome by the `dialId` it minted; one it did not
3484
+ The identity is a correlation handle between agent application and provider and **is never shown to the
3485
+ agent**. An agent application holding several tasks places an outcome by the `dialId` it minted; one it did not
3480
3486
  mint -- a dial made by the previous agent before a transfer -- it finds on the task's `onCall` or in
3481
- its `interactionHistory`, which is why the steps that dial carry it. The `dialId` is not a retry key:
3487
+ its `history`, which is why the steps that dial carry it. The `dialId` is not a retry key:
3482
3488
  Omni never repeats a dial, and a command still carries no key for that purpose.
3483
3489
 
3484
3490
  **`dialling` is the answer to a dial, and `applied` is not.** A command that dials answers
3485
- `{ status: "dialling", dialId }`, restating the host's identity (`result.dialId`,
3491
+ `{ status: "dialling", dialId }`, restating the agent application's identity (`result.dialId`,
3486
3492
  `result.dialId.mismatch`); `applied` from such a command, or `dialling` from one that dialled
3487
3493
  nothing, is refused (`result.status`). `validateResult(result, method, path, dialId)` takes the
3488
- `dialId` the host sent for that reason.
3494
+ `dialId` the agent application sent for that reason.
3489
3495
 
3490
3496
  **The outcome is stated, once, either way.** A `dial-outcome` names the `dialId`, the task where
3491
3497
  there was one, the directory item it went to where there was one, and how the dial ended -- from a closed
3492
3498
  set: `answered`, `busy`, `no-answer`, `unreachable`, `rejected`, `cancelled`, `unexplained`.
3493
- `answered` is stated rather than read off somebody appearing on the call, because a host that infers
3499
+ `answered` is stated rather than read off somebody appearing on the call, because an agent application that infers
3494
3500
  success cannot tell "reached" from "still ringing". `cancelled` is the dialler calling the dial off
3495
3501
  before anyone answered -- the agent hanging up while a consult still rings -- which is not a
3496
3502
  `no-answer` the destination never gave. `unexplained` is the switch dropping the call with no cause among
@@ -3501,14 +3507,14 @@ create dialog" in words and still name no cause a code would carry, so `unexplai
3501
3507
  `reason` is a dial the switch described but did not classify, and a desk renders the words without
3502
3508
  inventing the class.
3503
3509
 
3504
- **`taskId` is the task the dial was placed on**, resolved from the dial's own identity and never from
3510
+ **`assignmentId` is the task the dial was placed on**, resolved from the dial's own identity and never from
3505
3511
  whatever task the agent is looking at when the outcome arrives. That task may already have ended,
3506
3512
  and the harness places the outcome all the same (`TaskStream`, `stream.dialOutcome.unknown`,
3507
3513
  `stream.dialOutcome.duplicate`); an agent who moved on still learns nobody was reached, against the
3508
3514
  call it belonged to and never against the next one.
3509
3515
 
3510
- The stream knows a dial from three places: `TaskStream.dialled(dialId)`, which a host calls when it
3511
- places one; an entry on a task's `onCall`; and a step in its `interactionHistory`. Since a dialled entry
3516
+ The stream knows a dial from three places: `TaskStream.dialled(dialId)`, which an agent application calls when it
3517
+ places one; an entry on a task's `onCall`; and a step in its `history`. Since a dialled entry
3512
3518
  is listed from placement, `dialled()` is load-bearing only for a dial that never has an entry -- a
3513
3519
  cold transfer, a connect-back, an idle dialpad call -- or whose entry has already left the room; an
3514
3520
  outcome for a dial nobody placed and no task mentions is what `stream.dialOutcome.unknown` refuses.
@@ -3548,8 +3554,8 @@ const onCall: OnCall[] = [
3548
3554
 
3549
3555
  `party` is the customer and `agent` a person by user id; neither was dialled from anywhere, so
3550
3556
  neither carries a destination. `consulted` and `conferenced` were, so both carry the
3551
- `destinationId` of the directory item and, where a host's dial brought them, its `dialId`; a person
3552
- the platform added itself carries none. `held: true` is presence as claim. A snapshot establishes state, so a host that attaches
3557
+ `destinationId` of the directory item and, where an agent application's dial brought them, its `dialId`; a person
3558
+ the platform added itself carries none. `held: true` is presence as claim. A snapshot establishes state, so an agent application that attaches
3553
3559
  after a transfer reads the room from here rather than inferring it from a sequence of outcomes it
3554
3560
  never saw.
3555
3561
 
@@ -3564,7 +3570,7 @@ task may remain open for wrap. Completion is a separate task action, not the cal
3564
3570
  `previewEndsAt` and `atDeadline` are three instances of one shape, and there will be more: each
3565
3571
  describes a state that is true now, and each is carried past the moment it stops being true by the
3566
3572
  most natural implementation there is, building the next task by spreading the last one. The
3567
- provider's own state looks right, the claim on the wire is stale, and only the host sees it. An
3573
+ provider's own state looks right, the claim on the wire is stale, and only the agent application sees it. An
3568
3574
  adapter that builds each transition from what is true after it, rather than from what was true
3569
3575
  before, needs none of these rules named. Two agents were
3570
3576
  once shown on calls for the better part of an hour while callers queued, because the last message
@@ -3707,11 +3713,11 @@ thing as a break the platform forced on its own. Where a platform applies one au
3707
3713
  executing a preference somebody configured, and that person is the owner of the action — `by` names
3708
3714
  them, not the machinery that carried it out.
3709
3715
 
3710
- Omni resolves the name to show with `describeUsers()`, so a provider sends the identifier and never
3716
+ Omni resolves the name to show with `getUserDetails()`, so a provider sends the identifier and never
3711
3717
  a display name.
3712
3718
 
3713
3719
  **A forced break travels with `on-break` or `starting-after-task`, and nothing else.** It is a
3714
- break in progress or about to be; beside `granted` or `awaiting-approval` the host would read a
3720
+ break in progress or about to be; beside `granted` or `awaiting-approval` the agent application would read a
3715
3721
  request the agent never made and commit it (`break.forced.status`). Where the provider publishes
3716
3722
  `reasons`, the lead's `force-break` named one, and the member's state carries it as `activeReasonId`.
3717
3723
 
@@ -3724,18 +3730,18 @@ forced: {
3724
3730
  }
3725
3731
  ```
3726
3732
 
3727
- The host keeps **Resume** available for an agent on a forced break. The agent explicitly chooses
3728
- Resume; the host sends `endBreak()` and follows the provider-confirmed state before resuming
3733
+ The agent application keeps **Resume** available for an agent on a forced break. The agent explicitly chooses
3734
+ Resume; the agent application sends `endBreak()` and follows the provider-confirmed state before resuming
3729
3735
  work. An expected duration is a positive finite number of milliseconds, measured from actual
3730
3736
  entry into `on-break`, excluding any `starting-after-task` wait. Omission means no expected
3731
- duration was supplied. Neither duration expiry nor an overdue indication authorizes the host
3737
+ duration was supplied. Neither duration expiry nor an overdue indication authorizes the agent application
3732
3738
  or provider to end the break, restore availability, or route work to the agent.
3733
3739
 
3734
3740
  **A lead lifting the restriction does not resume the agent.** On an applied
3735
3741
  `end-forced-break`, the provider clears `BreakState.forced` while preserving the current
3736
3742
  `on-break` or `starting-after-task` status and `activeReasonId`. This command cannot publish
3737
3743
  `not-requested`, restore readiness, or start routing work. Ordinary progress from
3738
- `starting-after-task` to `on-break` still happens when work finishes. The host follows the
3744
+ `starting-after-task` to `on-break` still happens when work finishes. The agent application follows the
3739
3745
  published state and waits for the agent's explicit Resume, even after reconnect. Historical
3740
3746
  attribution is not rewritten by clearing the current forced marker.
3741
3747
 
@@ -3745,7 +3751,7 @@ must correlate resumption to the authenticated agent's action; a state-only orde
3745
3751
  cannot establish the cause of a transition. The usual multi-provider end/reconciliation flow
3746
3752
  still applies, and work resumes only on confirmed provider state.
3747
3753
 
3748
- A host may display the expected duration. A countdown requires an evidenced actual start;
3754
+ An agent application may display the expected duration. A countdown requires an evidenced actual start;
3749
3755
  a received snapshot, replay or reconnect is not a new start and cannot restart the duration.
3750
3756
  Without that evidence, show the duration without inventing a start or return time.
3751
3757
 
@@ -3784,43 +3790,43 @@ hold applied. A `held` result would repeat the discriminant that travelled with
3784
3790
 
3785
3791
  ### `setCapacity(capacity)`
3786
3792
 
3787
- States how many tasks this provider may have allocated to the agent **at once**.
3793
+ States how many tasks this provider may have assigned to the agent **at once**.
3788
3794
 
3789
3795
  `count` is an absolute ceiling, not an increment, a whole number of zero or more
3790
3796
  (`capacity.count`). An agent's capacity is a property of the agent, not of the moment: it is
3791
3797
  stated when the agent is set up and restated only when it genuinely changes, which is a
3792
- provisioning change rather than a task starting or ending -- with one exception below.
3798
+ local policy change rather than a task starting or ending -- with one exception below.
3793
3799
 
3794
- **The provider counts its own outstanding tasks against it.** Allocate while you hold fewer than
3800
+ **The provider counts its own outstanding tasks against it.** Assign while you hold fewer than
3795
3801
  `count` tasks for this agent, and stop when you hold that many; when one of yours ends you have
3796
3802
  room again and need no new signal to know it. Omni does not re-state capacity as tasks come and
3797
3803
  go, and a provider that waits for it will stall.
3798
3804
 
3799
3805
  Your own tasks are the only ones you count. What the agent holds at other providers is not your
3800
3806
  concern — Omni set `count` knowing it, and this is how: the agent is one person on several
3801
- providers, and the host divides their capacity among them rather than telling each the whole. A
3802
- provider that has none of it for now is told **`count: 0`, host-stopped**: allocate nothing, show
3803
- the member as `reserved` on the team member list -- signed in here, capacity held by the host for elsewhere,
3807
+ providers, and the agent application divides their capacity among them rather than telling each the whole. A
3808
+ provider that has none of it for now is told **`count: 0`, agent application-stopped**: assign nothing, show
3809
+ the member as `reserved` on the team member list -- signed in here, capacity held by the agent application for elsewhere,
3804
3810
  a fact this provider holds, where `on-task` would assert work it cannot see -- and take the next
3805
- count as any other when the host has capacity for this provider again. Zero is the one restatement
3806
- that follows work rather than provisioning.
3811
+ count as any other when the agent application has capacity for this provider again. Zero is the one restatement
3812
+ that follows work rather than local policy.
3807
3813
 
3808
3814
  **A capacity is taken, never refused.** `setCapacity` answers `applied` and nothing else: a
3809
- statement has no failure to report, and a `failed` arm gave four host-provider pairings four
3810
- readings of which ceiling stood after it. A provider that cannot carry the count allocates within
3815
+ statement has no failure to report, and a `failed` arm gave four agent application-provider pairings four
3816
+ readings of which ceiling stood after it. A provider that cannot carry the count assigns within
3811
3817
  what it can and says so on a `diagnostic`, so the gap is visible and nothing is inferred from a
3812
3818
  refusal.
3813
3819
 
3814
3820
  Capacity supersedes rather than accumulates: the latest value is the ceiling, and a decrease is as
3815
3821
  ordinary as an increase. A provider whose ceiling can only rise -- one that keeps the highest count
3816
- it was ever told, or returns early on a small one -- cannot be told to take less work, and a host
3822
+ it was ever told, or returns early on a small one -- cannot be told to take less work, and an agent application
3817
3823
  taking capacity away is answered `applied` while the work keeps coming. The harness moves the axis
3818
3824
  both ways after the drive, two then one then nought, and an offer after a lower count is caught
3819
3825
  against it (`stream.taskOffered.overCapacity`).
3820
3826
 
3821
- **Capacity gates what the provider allocates, not what the agent starts.** A call placed from the
3827
+ **Capacity gates what the provider assigns, not what the agent starts.** A call placed from the
3822
3828
  idle dialpad arrives through `task-offered` like any other task, and a full agent does not forbid
3823
- it: the ceiling binds allocation, not the agent's own hand.
3829
+ it: the ceiling binds assignment, not the agent's own hand.
3824
3830
 
3825
3831
  ### Runtime break prerequisite checks
3826
3832
 
@@ -3852,7 +3858,7 @@ These validators report violations without dispatching, rewriting state or provi
3852
3858
  Recheck prerequisites atomically at the provider; client validation cannot prevent a race.
3853
3859
  Continue to use `validateResult` for each method's response vocabulary. A request acknowledgment
3854
3860
  is not a grant, and no method response overwrites a newer state emission. Rejected promises
3855
- remain unknown and recover by snapshot, not automatic retry. The host's frozen provider set,
3861
+ remain unknown and recover by snapshot, not automatic retry. The agent application's frozen provider set,
3856
3862
  durable mutually exclusive commit/cancel decision and reconciliation obligations above remain
3857
3863
  required; per-provider validation does not implement the multi-provider coordinator.
3858
3864
 
@@ -3979,7 +3985,7 @@ request and is ready to stop the agent when Omni asks. It does not reveal that o
3979
3985
  or why Omni has not committed yet. While reporting `granted`, the provider remains available,
3980
3986
  continues to honour Omni's current capacity, and continues offering work normally.
3981
3987
 
3982
- Omni separately tracks the aggregate host states `working`, `requesting-break`, `committing-break`,
3988
+ Omni separately tracks the aggregate agent application states `working`, `requesting-break`, `committing-break`,
3983
3989
  `cancelling-break`, and `on-break`. While `requesting-break`, Omni shows which providers remain
3984
3990
  outstanding and offers **Cancel break request**, but does not tell the agent that their break has
3985
3991
  begun.
@@ -3996,7 +4002,7 @@ Omni coordinates one break attempt as follows:
3996
4002
  from and is not asked: nothing is asked of it, the break proceeds without it, and when the
3997
4003
  login is restored it is reconciled from its snapshot as a set-aside provider is, with no
3998
4004
  capacity until then. `refreshing` keeps a provider in — its identity and capabilities remain
3999
- available and work continues. `assertBreakAttemptProviders` holds a host to this set.
4005
+ available and work continues. `assertBreakAttemptProviders` holds an agent application to this set.
4000
4006
  2. Enter `requesting-break`. Keep the agent's normal capacity in place throughout this phase.
4001
4007
  3. Send one `requestBreak` to every asked provider. A provider reports `awaiting-approval` or
4002
4008
  `granted`; neither state stops work. A denial transitions directly to `not-requested` and
@@ -4128,7 +4134,7 @@ an absent `team` still means the login is not entitled to that contribution.
4128
4134
 
4129
4135
  | `TeamMember` field | Contract |
4130
4136
  | --- | --- |
4131
- | `id` | Required `UserId`. A task carries no names and neither does a team member list: Omni resolves what to display with `describeUsers()`. |
4137
+ | `id` | Required `UserId`. A task carries no names and neither does a team member list: Omni resolves what to display with `getUserDetails()`. |
4132
4138
  | `availability` | Required. What the member is doing now. |
4133
4139
  | `since` | Optional. When the current `availability` began — not when they signed in, and not when the team member list was read. |
4134
4140
  | `break` | Present only while the member has an outstanding break request. See **A member waiting for a break**. |
@@ -4140,7 +4146,7 @@ Each availability value means one thing:
4140
4146
  | `ready` | Signed in, able to take work, none assigned. |
4141
4147
  | `on-task` | Working on at least one task. It says nothing about how many, and nothing about whether more will fit. |
4142
4148
  | `on-break` | Stopped and not taking work, whether they asked or somebody stopped them. The reason lives on their own `BreakState`, not here. |
4143
- | `reserved` | Signed in here, and the host holds this agent's capacity for another provider (`count: 0`, host-stopped): not receiving this provider's work, and not on a break. See **Capacity**. |
4149
+ | `reserved` | Signed in here, and the agent application holds this agent's capacity for another provider (`count: 0`, agent application-stopped): not receiving this provider's work, and not on a break. See **Capacity**. |
4144
4150
  | `signed-out` | Known to this team but not signed in to this provider. |
4145
4151
 
4146
4152
  **Always publish the complete team member list, never a change to it.** Team presence typically reaches an
@@ -4183,7 +4189,7 @@ One method, `executeTeamBreak`, taking a discriminated command exactly as `execu
4183
4189
 
4184
4190
  `memberId` is this provider's own identifier for the member, as published on its team member list. It is
4185
4191
  never an identifier from another provider, and Omni does not translate between them; names come
4186
- from `describeUsers()`.
4192
+ from `getUserDetails()`.
4187
4193
 
4188
4194
  `requests-suspended` means requests are **rejected outright** rather than left pending — nobody is coming to
4189
4195
  approve them. A provider that suspends break requests must also publish `canRequestBreak: false` to the team's
@@ -4209,23 +4215,24 @@ Required when the login declares `capabilities.team.leadAssistControl`, and gate
4209
4215
 
4210
4216
  ```ts
4211
4217
  // 1. The agent asks, with a small note. Their task carries `leadAssist` from here on.
4212
- execute({ taskId: "call-42", command: { type: "lead-assist", action: "request", note: "Refund dispute, needs approval" } })
4218
+ execute({ assignmentId: "alloc-42", command: { type: "lead-assist", action: "request", note: "Refund dispute, needs approval" } })
4213
4219
  // task.leadAssist = { stage: "requested", note: "Refund dispute, needs approval", since }
4214
4220
 
4215
4221
  // 2. Every lead entitled to it sees the request on their team member list.
4216
- // team-updated: requests: [{ id: "req-7", memberId: "A-1", taskId: "call-42", allocationId: "alloc-42", note, since }]
4222
+ // team-updated: requests: [{ id: "req-7", memberId: "A-1", assignmentId: "alloc-42", note, since }]
4217
4223
 
4218
4224
  // 3. A lead joins, or declines.
4219
4225
  executeTeamLeadAssist({ command: { type: "join", requestId: "req-7" } })
4220
4226
  executeTeamLeadAssist({ command: { type: "decline", requestId: "req-7", reason: "In a call" } })
4221
4227
  ```
4222
4228
 
4223
- **On `join` the provider bridges three parties and the lead is on a task of their own**, on the
4224
- same task id, arriving on the lead's connection as `task-offered` with `automatic`
4225
- -- the way a call an agent placed themselves arrives -- and carrying `assisting`. The agent's task
4229
+ **On `join` the provider bridges three parties and the lead is on a task of their own**, an
4230
+ assignment of its own, arriving on the lead's connection as `task-offered` with `automatic`
4231
+ -- the way a call an agent placed themselves arrives -- and carrying `assisting`, which names the
4232
+ member and the member's assignment. The agent's task
4226
4233
  moves to `leadAssist: { stage: "joined", leadId }`. A join is the lead's own act, so capacity does not
4227
4234
  trigger it; but from then on it is an outstanding task the provider counts against the lead's
4228
- stated ceiling like any other, nothing more is allocated to the lead while it stands, and a
4235
+ stated ceiling like any other, nothing more is assigned to the lead while it stands, and a
4229
4236
  provider whose lead is already at the ceiling answers the join `failed`.
4230
4237
 
4231
4238
  **A lead assists one call at a time.** A `join` from a lead already on a call -- their own or one
@@ -4272,7 +4279,7 @@ const leadAssistCapable = {
4272
4279
  ```
4273
4280
 
4274
4281
  Lead and member alike are `UserId`s of this provider, so an adapter publishing them implements
4275
- `describeUsers()`; names never travel on a task or a team member list.
4282
+ `getUserDetails()`; names never travel on a task or a team member list.
4276
4283
 
4277
4284
  ### Listening to a call
4278
4285
 
@@ -4333,8 +4340,8 @@ declaration requires `executeTeamListen`, gated exactly as `executeTeamLeadAssis
4333
4340
  executeTeamListen({ command: { type: "listen", memberId: "A-1" } })
4334
4341
 
4335
4342
  // 2. The lead's own task arrives -- task-offered with `automatic`, as a joined call does -- and
4336
- // carries `listening`; the task id is the lead's, the member's call is named inside it.
4337
- // listening: { memberId: "A-1", taskId: "call-42", allocationId: "alloc-42", mode: "listen", since }
4343
+ // carries `listening`; the assignment is the lead's own, the member's is named inside it.
4344
+ // listening: { memberId: "A-1", assignmentId: "alloc-42", mode: "listen", since }
4338
4345
 
4339
4346
  // 3. The lead changes how they are heard; the provider restates the task with the new mode.
4340
4347
  executeTeamListen({ command: { type: "coach" } })
@@ -4372,7 +4379,7 @@ const listeningLead = {
4372
4379
  channel: "voice",
4373
4380
  capabilities: {},
4374
4381
  phase: "in-progress",
4375
- listening: { memberId: "A-1", taskId: "call-42", allocationId: "alloc-42", mode: "coach", since: "2026-08-21T09:04:00Z" },
4382
+ listening: { memberId: "A-1", assignmentId: "alloc-42", mode: "coach", since: "2026-08-21T09:04:00Z" },
4376
4383
  } satisfies Pick<Task<"voice">, "channel" | "capabilities" | "phase" | "listening">;
4377
4384
  ```
4378
4385
 
@@ -4413,25 +4420,25 @@ decision or it is not.
4413
4420
  ## Real-time media
4414
4421
 
4415
4422
  Every voice provider has media: `channel: "voice"` says audio exists. Where the agent hears it
4416
- depends on the `phone` the host selected at authentication and connect from the manifest's
4423
+ depends on the `phone` the agent application selected at authentication and connect from the manifest's
4417
4424
  `phones`. On a softphone, audio lands in Omni; on a desk phone, it lands on the handset and Omni
4418
4425
  opens no audio. See **How the agent hears the call**. Media transitions are voice-only;
4419
4426
  chat and email publish none (`event.media.channel`, `stream.taskMedia.channel`).
4420
4427
 
4421
- The provider owns signalling and the platform's endpoint configuration. The host selects the
4428
+ The provider owns signalling and the platform's endpoint configuration. The agent application selects the
4422
4429
  declared phone mode; it does not enumerate or reconfigure the platform's devices. The selected
4423
4430
  mode stays with the login rather than being inferred from a snapshot or a device failure.
4424
4431
 
4425
4432
  Nor does the audio ever stand in for the task: a task's presence and
4426
4433
  phase follow the provider's reports about the work, and the media — attaching, moving through a
4427
4434
  hold, a consult, a conference or a transfer, and ending — is transient beside it. See **A task is
4428
- never its audio** under **Task allocation lifecycle**.
4435
+ never its audio** under **Task assignment lifecycle**.
4429
4436
 
4430
- ### The host reports, the adapter decides
4437
+ ### The agent application reports, the adapter decides
4431
4438
 
4432
4439
  The adapter runs inside Omni and sees nothing of the station for itself: the devices, the
4433
- permissions, the audio element and the network are the host's, and only the host can tell. So
4434
- the host reports, and the adapter asks. **An adapter consults `ConnectContext.host` before it
4440
+ permissions, the audio element and the network are the agent application's, and only the agent application can tell. So
4441
+ the agent application reports, and the adapter asks. **An adapter consults `ConnectContext.host` before it
4435
4442
  declares the agent ready to its platform, and again whenever the report changes**, and it decides
4436
4443
  what any of it means and what to relay upstream — go not-ready, refuse calls, carry on because the
4437
4444
  platform's audio lands elsewhere. Omni facilitates and does not take responsibility: it captures
@@ -4439,29 +4446,29 @@ the microphone once as the voice connection opens, so the permission prompt land
4439
4446
  is signing in rather than over a contact, prompts, retries on the agent's request, tells the agent
4440
4447
  what failed, and reports. It never decides for the adapter what a missing microphone means.
4441
4448
 
4442
- **The host also guarantees, and a promise the provider cannot see is not one it can rely on.**
4443
- Two of this contract's obligations fall on the host rather than the provider — honouring a task
4449
+ **The agent application also guarantees, and a promise the provider cannot see is not one it can rely on.**
4450
+ Two of this contract's obligations fall on the agent application rather than the provider — honouring a task
4444
4451
  browser's `urlVisibility`, and taking a `consent` offer only on the person's own press — and more
4445
4452
  than one desk speaks this contract: a browser and a native application differ in what they can
4446
4453
  reach, and a provider never branches on which it is talking to, only on what it has declared —
4447
- here, and in `host.mute` (see **The station is the host's**). So `ConnectContext.host.guarantees` says which promises the
4448
- connected host makes, declared once per connection, presence being the guarantee exactly as it is
4454
+ here, and in `host.mute` (see **The station is the agent application's**). So `ConnectContext.host.guarantees` says which promises the
4455
+ connected agent application makes, declared once per connection, presence being the guarantee exactly as it is
4449
4456
  the permission everywhere else:
4450
4457
 
4451
4458
  | Guarantee | Contract |
4452
4459
  | --- | --- |
4453
- | `browserUrlVisibility` | Every task browser's `urlVisibility` is honoured in this host's chrome, tab by tab. A provider that would send a caller's number in a URL checks this first and tokenises where the promise is absent. |
4460
+ | `browserUrlVisibility` | Every task browser's `urlVisibility` is honoured in this agent application's chrome, tab by tab. A provider that would send a caller's number in a URL checks this first and tokenises where the promise is absent. |
4454
4461
  | `personConsent` | A `consent` offer is accepted only by the person's own explicit act, never on their behalf. A provider whose work may only be taken by a human checks this first and does not offer it where the promise is absent. |
4455
4462
 
4456
- A guarantee the host does not make is an absent key, never `false` — `validateHostGuarantees`
4463
+ A guarantee the agent application does not make is an absent key, never `false` — `validateHostGuarantees`
4457
4464
  refuses a false one, as it refuses a name this contract does not list.
4458
4465
 
4459
4466
  | Field | Contract |
4460
4467
  | --- | --- |
4461
- | `online` | Whether the host has a network interface up. Not a claim that anything is reachable — the adapter knows whether it can reach its own platform far better than the host does — so `false` is a reason not to go ready and `true` is not a reason to. |
4468
+ | `online` | Whether the agent application has a network interface up. Not a claim that anything is reachable — the adapter knows whether it can reach its own platform far better than the agent application does — so `false` is a reason not to go ready and `true` is not a reason to. |
4462
4469
  | `audio` | Present on a voice connection, absent where there is no audio. |
4463
- | `audio.input` | `available` with `localAudio` — the microphone as captured, the same stream `openMedia` receives — and `flowing`, false while no audio moves through it, when `mutedBy` says who stopped it: `host`, the host's own Mute on a host that mutes the station, or `station`, a slider on the headset or the operating system, which the host observed and did not do. An adapter treats `host` as the agent's act on a call and `station` as a condition of the station. `unavailable` with `reason`, since each wants a different fix from the agent: `no-device`; `denied`; `not-asked`, which a host that asks at connect never publishes; `in-use`, a device present and permitted that another application holds — on an agent desktop the commonest of all; `lost`, a capture that ended. A host decides the reason from the devices before the error name: a browser can report a permission error on a machine with no microphone at all, and "grant permission" is the wrong instruction for an agent who needs to plug one in. `failure` carries the words Omni showed them. |
4464
- | `audio.output` | `available`, with `flowing` where the host can know whether audio reaches the speaker — a browser mostly cannot, and omits it; a native host reads the endpoint — false while it is silenced, when `mutedBy` says who did it, as on input. Or `unavailable` with `reason` — `no-device`, or `lost` for one removed — and `failure`: an agent who cannot hear is as unable to take a call as one who cannot speak. |
4470
+ | `audio.input` | `available` with `localAudio` — the microphone as captured, the same stream `openMedia` receives — and `flowing`, false while no audio moves through it, when `mutedBy` says who stopped it: `host`, the agent application's own Mute on an agent application that mutes the station, or `station`, a slider on the headset or the operating system, which the agent application observed and did not do. An adapter treats `host` as the agent's act on a call and `station` as a condition of the station. `unavailable` with `reason`, since each wants a different fix from the agent: `no-device`; `denied`; `not-asked`, which an agent application that asks at connect never publishes; `in-use`, a device present and permitted that another application holds — on an agent desktop the commonest of all; `lost`, a capture that ended. An agent application decides the reason from the devices before the error name: a browser can report a permission error on a machine with no microphone at all, and "grant permission" is the wrong instruction for an agent who needs to plug one in. `failure` carries the words Omni showed them. |
4471
+ | `audio.output` | `available`, with `flowing` where the agent application can know whether audio reaches the speaker — a browser mostly cannot, and omits it; a native agent application reads the endpoint — false while it is silenced, when `mutedBy` says who did it, as on input. Or `unavailable` with `reason` — `no-device`, or `lost` for one removed — and `failure`: an agent who cannot hear is as unable to take a call as one who cannot speak. |
4465
4472
 
4466
4473
  Omni republishes the report whenever it changes — a permission granted late, a headset unplugged,
4467
4474
  a network gone — and it publishes a state, not a flicker: a change that resolves within moments is
@@ -4469,13 +4476,13 @@ not reported, so an adapter may act on what it reads without debouncing it again
4469
4476
  report is a task fact or a capacity fact; it is what the station can do, and the adapter's platform
4470
4477
  is the one that knows whether an agent without a microphone, or without a speaker, can work.
4471
4478
 
4472
- The host's own obligations here — asking at connect, never publishing `not-asked` when it does,
4479
+ The agent application's own obligations here — asking at connect, never publishing `not-asked` when it does,
4473
4480
  publishing a state and not a flicker — are Omni's tests' to hold. `exerciseAdapter` holds the
4474
- other side: it validates the shape of whatever host a test hands the adapter, requires `audio` on
4481
+ other side: it validates the shape of whatever agent application a test hands the adapter, requires `audio` on
4475
4482
  a softphone login and none elsewhere -- not on a desk phone, not off voice
4476
4483
  (`context.host.audio.required` / `.unexpected`), holds `host.mute` to the same line (`host.mute.required`
4477
4484
  / `.unexpected`, `host.mute` for a third word) -- and refuses a voice adapter that never asked the
4478
- host anything (`connection.host.consulted`), and one that subscribed to nothing will never hear of a
4485
+ agent application anything (`connection.host.consulted`), and one that subscribed to nothing will never hear of a
4479
4486
  change (`connection.host.subscribed`): the obligation has two halves, and each is held.
4480
4487
 
4481
4488
  ### Capacity around setup
@@ -4485,9 +4492,9 @@ as reachability opens a window where it believes the agent is available and the
4485
4492
  set up — the adapter's own registration incomplete, its credentials not yet renewed.
4486
4493
 
4487
4494
  Nothing closes that window, because nothing opens it: **Omni states no capacity until the
4488
- connection is established**, and **Work is pulled, never pushed** makes an allocation with none
4489
- stated a violation. Capacity does not wait on the microphone: whether an agent without host audio
4490
- can take calls is the platform's question, answered by the adapter from the host's report, not by
4495
+ connection is established**, and **Work is pulled, never pushed** makes an assignment with none
4496
+ stated a violation. Capacity does not wait on the microphone: whether an agent without agent application audio
4497
+ can take calls is the platform's question, answered by the adapter from the agent application's report, not by
4491
4498
  Omni withholding capacity for every platform alike.
4492
4499
 
4493
4500
  Capacity follows **automatically** once the connection is established; the agent does not press
@@ -4495,12 +4502,12 @@ anything to become available.
4495
4502
 
4496
4503
  | Situation | What Omni sends |
4497
4504
  | --- | --- |
4498
- | Connecting | Nothing. No capacity has been stated, so nothing may be allocated. |
4499
- | Connected and idle | `setCapacity({ count: n })`, with the host's report already available to consult. |
4505
+ | Connecting | Nothing. No capacity has been stated, so nothing may be assigned. |
4506
+ | Connected and idle | `setCapacity({ count: n })`, with the agent application's report already available to consult. |
4500
4507
  | A task starts or ends | Nothing. The provider counts its own against the ceiling. |
4501
4508
  | The agent's provisioned capacity changes | `setCapacity({ count: n })` |
4502
4509
  | Agent asks for a break | `requestBreak`. Capacity is unchanged and work continues. |
4503
- | Omni commits a break | `commitBreak`. The break stops allocation, not the ceiling. |
4510
+ | Omni commits a break | `commitBreak`. The break stops assignment, not the ceiling. |
4504
4511
  | Agent returns from break | `endBreak` |
4505
4512
 
4506
4513
  **A break is not a capacity of zero, and neither is the reverse.** Capacity says how much of this
@@ -4512,57 +4519,57 @@ a return.
4512
4519
 
4513
4520
  ### How the agent hears the call
4514
4521
 
4515
- A voice platform can put an agent on a **softphone**, where the call's audio lands in the host
4522
+ A voice platform can put an agent on a **softphone**, where the call's audio lands in the agent application
4516
4523
  and Omni owns the microphone and the playback, or on a **desk phone**, a handset on the platform's
4517
- switch that the platform rings, where the host owns no audio and only shows the call. Which of
4524
+ switch that the platform rings, where the agent application owns no audio and only shows the call. Which of
4518
4525
  these a platform can do is a fact about the platform, and which one a login is on is a choice the
4519
- host makes for that agent -- so the manifest declares and the host chooses.
4526
+ agent application makes for that agent -- so the manifest declares and the agent application chooses.
4520
4527
 
4521
4528
  ```ts
4522
4529
  // Manifest: what the platform can do
4523
4530
  phones: ["softphone", "deskPhone"]
4524
- // The host, at authentication and again at connect: which one this login is on
4531
+ // The agent application, at authentication and again at connect: which one this login is on
4525
4532
  { phone: "softphone" }
4526
4533
  ```
4527
4534
 
4528
4535
  A voice manifest lists its `phones` and any other channel lists none (`manifest.phones.required`,
4529
- `manifest.phones.channel`). The host's `phone` is required on a voice login, absent on any other,
4536
+ `manifest.phones.channel`). The agent application's `phone` is required on a voice login, absent on any other,
4530
4537
  and one the manifest listed (`context.phone.required`, `.unexpected`, `.unsupported`). Everything
4531
- about audio then follows the phone rather than the channel: on a softphone the host reports its
4538
+ about audio then follows the phone rather than the channel: on a softphone the agent application reports its
4532
4539
  audio, the adapter implements `openMedia`, and `task-media-started` is the word to open it; on a
4533
- desk phone the host reports no audio, opens nothing, and `task-media-started` still marks the
4540
+ desk phone the agent application reports no audio, opens nothing, and `task-media-started` still marks the
4534
4541
  moment the call is live so the desk shows it, with the sound on the handset. A platform that lists
4535
4542
  `deskPhone` alone never implements `openMedia`; one that lists `softphone` always does.
4536
4543
 
4537
- **The mode comes from the host; the status comes from the provider.** The host knows which kind
4544
+ **The mode comes from the agent application; the status comes from the provider.** The agent application knows which kind
4538
4545
  of station the agent signed in at, because the person chose it, and nothing else can know that.
4539
4546
  The provider knows whether that station can carry a call right now -- whether a handset is
4540
- registered -- which a host in a browser cannot see. So the host's `phone` selects the branch, and
4547
+ registered -- which an agent application in a browser cannot see. So the agent application's `phone` selects the branch, and
4541
4548
  the provider's own knowledge of the device decides readiness within it. A provider never overrides
4542
- the host's declaration from its device record: treating a desk-phone login as a softphone because
4549
+ the agent application's declaration from its device record: treating a desk-phone login as a softphone because
4543
4550
  the handset is momentarily unregistered, and demanding a microphone of it, is the reading this
4544
4551
  sentence exists to refuse. What the provider does when the handset is not registered is what it
4545
4552
  does for any station that cannot take a call -- hold the agent not-ready and say why.
4546
4553
 
4547
- **On a desk-phone login the host never calls `openMedia`.** There is no stream to hand over and
4548
- no audio to attach; a host that calls it anyway is in error, and an adapter that receives the call
4554
+ **On a desk-phone login the agent application never calls `openMedia`.** There is no stream to hand over and
4555
+ no audio to attach; an agent application that calls it anyway is in error, and an adapter that receives the call
4549
4556
  answers `unavailable` with a non-retryable failure, since waiting changes nothing about a station
4550
4557
  that is a telephone. The harness requires no `openMedia` of such an adapter and never calls it.
4551
4558
 
4552
4559
  **Which handset a desk-phone login rings is the platform's configuration for that agent**, and
4553
- this wire never asks the agent for it: a host declares `phone` and nothing more. What a platform
4560
+ this wire never asks the agent for it: an agent application declares `phone` and nothing more. What a platform
4554
4561
  asks on surfaces of its own is its own decision.
4555
4562
 
4556
4563
  **A declared phone the platform does not permit for this agent is a login that cannot be
4557
4564
  established.** The manifest says what the platform can do; the agent's record, kept by an
4558
- administrator, says what this agent is configured for, and the two can disagree with the host's
4565
+ administrator, says what this agent is configured for, and the two can disagree with the agent application's
4559
4566
  declaration -- a softphone declared for an agent whose record says desk phone. Honouring that
4560
4567
  declaration on a switch that allows one registration per endpoint would evict the handset: the
4561
4568
  agent's phone stops ringing and their calls land in a tab, and nobody is told. So the provider
4562
- refuses the login at authentication, with `omni.phone-not-permitted` and a message the host shows
4569
+ refuses the login at authentication, with `omni.phone-not-permitted` and a message the agent application shows
4563
4570
  -- "this agent is configured for a desk phone" -- and refusing is correct, not an override of the
4564
- host. It is a refusal, never a negotiation afterwards and never a quiet substitution, and it is
4565
- never retryable: trying again does not reconfigure the agent, and a host validating the answer
4571
+ agent application. It is a refusal, never a negotiation afterwards and never a quiet substitution, and it is
4572
+ never retryable: trying again does not reconfigure the agent, and an agent application validating the answer
4566
4573
  (`validateAuthenticationResult`) refuses a phone refusal marked otherwise
4567
4574
  (`authentication.failure.phone.retryable`). And **a
4568
4575
  provider never makes a declared phone true by changing the platform's configuration**: the record
@@ -4574,16 +4581,16 @@ is the administrator's, and a login is not a request to reconfigure an agent.
4574
4581
  `softphone` implements it, because on a softphone the call's audio lands in Omni:
4575
4582
 
4576
4583
  ```ts
4577
- openMedia({ taskId, localAudio }): Promise<OpenMediaResult>
4584
+ openMedia({ assignmentId, localAudio }): Promise<OpenMediaResult>
4578
4585
  // { status: "opened", session } | { status: "unavailable", failure }
4579
4586
  ```
4580
4587
 
4581
4588
  The adapter speaks whatever its platform speaks — SIP over WebSocket, a vendor SDK, plain
4582
4589
  WebRTC — and **none of that appears in this contract**. Registration, signalling, credential
4583
4590
  renewal and reconnect are the adapter's, exactly as its authentication and transport already
4584
- are. Omni owns what belongs to the host: the microphone, the output element, mute, and when a
4591
+ are. Omni owns what belongs to the agent application: the microphone, the output element, mute, and when a
4585
4592
  session ends — owning the microphone meaning capturing it, prompting, retrying and reporting how
4586
- it stands, never deciding for the adapter what a missing one means (see **The host reports, the
4593
+ it stands, never deciding for the adapter what a missing one means (see **The agent application reports, the
4587
4594
  adapter decides**).
4588
4595
 
4589
4596
  | Member | Contract |
@@ -4592,9 +4599,9 @@ adapter decides**).
4592
4599
  | `setMuted(muted)` | Mutes the agent's microphone on this session. |
4593
4600
  | `close()` | Releases the session. Omni calls it when the task ends. |
4594
4601
 
4595
- `localAudio` is the agent's microphone as Omni captured it, the same stream the host's report
4602
+ `localAudio` is the agent's microphone as Omni captured it, the same stream the agent application's report
4596
4603
  carries as `audio.input.localAudio`, and absent while that input is `unavailable`. A provider that
4597
- bridges audio without a host-side input may ignore it; one that needs it and finds it absent
4604
+ bridges audio without an application-side input may ignore it; one that needs it and finds it absent
4598
4605
  answers `unavailable` with a failure Omni shows the agent.
4599
4606
 
4600
4607
  **When to ask is the provider's word, not Omni's guess.** On a softphone login, Omni opens media on `task-media-started`,
@@ -4614,7 +4621,7 @@ Command names follow the channel's operational vocabulary, and each channel's co
4614
4621
  discriminated by `type` — the same discriminant `executeTeamBreak` and `custom` already use. The
4615
4622
  unions are declared under **Shapes**.
4616
4623
 
4617
- `taskId` is not repeated on the command. It travels on the `TaskCommandRequest` around it.
4624
+ `assignmentId` is not repeated on the command. It travels on the `TaskCommandRequest` around it.
4618
4625
 
4619
4626
  **A toggle carries the state it wants, not a flip.** Inverting whatever is found cannot converge
4620
4627
  with a stale view: a flip against a state the provider has already changed turns something on and
@@ -4632,87 +4639,87 @@ command asks the provider to **perform** something: `hold`, `transfer`, `confere
4632
4639
  Provider-targeted `recording` commands and the rest act on the platform's own call leg, its bridge, or its record of the
4633
4640
  task. Nothing has happened until the provider applies them, and `failed` means nothing happened.
4634
4641
 
4635
- **The provider performs every action; the host only offers it.** A control drawn on the host is
4636
- an affordance, never the enforcement: the host asks, and the provider does or declines. A provider
4642
+ **The provider performs every action; the agent application only offers it.** A control drawn on the agent application is
4643
+ an affordance, never the enforcement: the agent application asks, and the provider does or declines. A provider
4637
4644
  answers `failed` for a command whose capability it did not publish, and that is the provider
4638
- honouring its own declaration, not the host deciding policy -- a host that refuses a command on
4645
+ honouring its own declaration, not the agent application deciding policy -- an agent application that refuses a command on
4639
4646
  its own reading of a queue's flag has decided something that was never its to decide. What a
4640
4647
  command means on the platform is the provider's to work out: `end-call` disconnects the caller channel, and
4641
- which legs on which bridge that touches is a fact about the switch, never a choice the host makes.
4642
- The one thing the host performs physically is the microphone, and that is not a command at all.
4648
+ which legs on which bridge that touches is a fact about the switch, never a choice the agent application makes.
4649
+ The one thing the agent application performs physically is the microphone, and that is not a command at all.
4643
4650
 
4644
- ### The station is the host's
4651
+ ### The station is the agent application's
4645
4652
 
4646
4653
  The microphone, the speaker, the headset and its buttons are the station's, and the station is the
4647
- host's. So mute is not a capability a provider declares, not a control a queue allows or a team
4654
+ agent application's. So mute is not a capability a provider declares, not a control a queue allows or a team
4648
4655
  locks, not a preference the person keeps with the provider, and not a command: nothing about the
4649
- station crosses to the provider except two things -- the station's condition, in the host report,
4650
- and the record of when the agent could not be heard, through `recordStep`. A host offers Mute on
4651
- every voice task with media open, under its own provisioning, in `in-progress` and `paused`
4656
+ station crosses to the provider except two things -- the station's condition, in the agent application report,
4657
+ and the record of when the agent could not be heard, through `recordStep`. An agent application offers Mute on
4658
+ every voice task with media open, under its own local policy, in `in-progress` and `paused`
4652
4659
  alone, and performs it through `VoiceMediaSession.setMuted()`. A task carrying
4653
4660
  `capabilities.mute` is refused (`task.capability.unknown`), and so is a `mute` command
4654
4661
  (`command.type`), a `mute` preference (`preference.id`) and a `mute` policy (`team.policy.key`).
4655
4662
 
4656
- **Two mutes, and the host states which its Mute performs.** A *stream* mute stops the audio the
4657
- host sends: the microphone keeps capturing, the party hears silence, nothing else on the machine
4658
- changes, and every softphone host can do it. A *station* mute silences the microphone itself at
4663
+ **Two mutes, and the agent application states which its Mute performs.** A *stream* mute stops the audio the
4664
+ agent application sends: the microphone keeps capturing, the party hears silence, nothing else on the machine
4665
+ changes, and every softphone agent application can do it. A *station* mute silences the microphone itself at
4659
4666
  the operating system: every application on the machine goes quiet, the system shows it, and a
4660
- headset that follows the system follows it. Only a native host can do it. `Host.mute` says which
4661
- this host does -- `stream` or `station` -- stated on a softphone login, where the host holds the
4667
+ headset that follows the system follows it. Only a native agent application can do it. `Host.mute` says which
4668
+ this agent application does -- `stream` or `station` -- stated on a softphone login, where the agent application holds the
4662
4669
  microphone, and absent on a desk phone and off voice (`host.mute.required` / `.unexpected`). A
4663
- browser says `stream`. A native host says whichever it does. Nothing on the wire says what kind of
4664
- application the host is; a provider reads only what the host declared.
4670
+ browser says `stream`. A native agent application says whichever it does. Nothing on the wire says what kind of
4671
+ application the agent application is; a provider reads only what the agent application declared.
4665
4672
 
4666
4673
  **A silenced device says who silenced it.** `audio.input.flowing: false` and
4667
- `audio.output.flowing: false` carry `mutedBy`: `host` when the host's own Mute did it -- which is
4668
- only ever true of a host whose mute is `station`, since a stream mute leaves the microphone
4669
- flowing -- and `station` when a slider on the headset or the operating system did, which the host
4670
- observed and did not do. Without the word, a station-muting host's own Mute would read as a fault
4674
+ `audio.output.flowing: false` carry `mutedBy`: `host` when the agent application's own Mute did it -- which is
4675
+ only ever true of an agent application whose mute is `station`, since a stream mute leaves the microphone
4676
+ flowing -- and `station` when a slider on the headset or the operating system did, which the agent application
4677
+ observed and did not do. Without the word, a station-muting agent application's own Mute would read as a fault
4671
4678
  and an adapter would take the agent out of ready in the middle of a call. A browser reads a station
4672
- mute through the capture track's muted state, read-only, and cannot lift it; a native host reads
4679
+ mute through the capture track's muted state, read-only, and cannot lift it; a native agent application reads
4673
4680
  the endpoint and can clear an operating-system mute. A hardware slider is nobody's to clear.
4674
4681
 
4675
4682
  **The record carries the same word.** A `muted` interaction leg is a period the agent could not be
4676
- heard, and the record exists so that period is not a hole. The host reports every such period
4683
+ heard, and the record exists so that period is not a hole. The agent application reports every such period
4677
4684
  through `recordStep` -- its own Mute, and a station mute it observed during a call -- with
4678
4685
  `mutedBy` saying whose the silence was, and the provider writes the word into the entry
4679
- (`task.interactionHistory.mutedBy`). The report names no agent because the host has exactly one, and
4686
+ (`task.history.mutedBy`). The report names no agent because the agent application has exactly one, and
4680
4687
  the provider knows who that is: it attributes the leg to the login's agent in `by`, a fact it
4681
- holds and not an inference, for a station mute as much as for the host's own. An unattributed
4682
- `muted` entry is refused (`task.interactionHistory.muted.by`); a shared handset's unattributed hold
4688
+ holds and not an inference, for a station mute as much as for the agent application's own. An unattributed
4689
+ `muted` entry is refused (`task.history.muted.by`); a shared handset's unattributed hold
4683
4690
  is a different claim, and stands. A supervisor reading the record then sees "the agent muted for
4684
4691
  forty seconds" and "the agent's headset was muted for forty seconds" as the different things they
4685
- are. See **The host records what it performs**.
4692
+ are. See **The agent application records what it performs**.
4686
4693
 
4687
4694
  **Mute has a lifecycle, and none of it is inferred.** A call that starts while the station is
4688
4695
  already muted begins a `muted` leg the moment its media starts, `mutedBy: "station"`. Media that
4689
- ends while any leg is open ends the leg at that instant, as every host-performed leg ends. And the
4690
- host's own Mute starts off on every call, which is every `task-media-started` -- a connect-back
4696
+ ends while any leg is open ends the leg at that instant, as every agent application-performed leg ends. And the
4697
+ agent application's own Mute starts off on every call, which is every `task-media-started` -- a connect-back
4691
4698
  opens a second call on the same task with no offer -- so an agent is never muted by the call before.
4692
4699
 
4693
- **Every press on a headset is the agent's own press**, performed the host's way, and the lights
4694
- follow the host's state. The `personConsent` guarantee is honoured by a hook-switch press exactly
4700
+ **Every press on a headset is the agent's own press**, performed the agent application's way, and the lights
4701
+ follow the agent application's state. The `personConsent` guarantee is honoured by a hook-switch press exactly
4695
4702
  as by a click. What a call-control headset sends, and what becomes of it:
4696
4703
 
4697
- | Input | Where it comes from | What the host does | What crosses to the provider |
4704
+ | Input | Where it comes from | What the agent application does | What crosses to the provider |
4698
4705
  | --- | --- | --- | --- |
4699
- | Mute button | The headset, on the HID Telephony usage page: a Phone Mute report on the press, a Mute LED the host writes back | A press of the host's Mute, performed the host's way; the LED follows the host's state, so button, light and control are one state with one owner | The `muted` leg, `mutedBy: "host"` |
4700
- | Hook switch | The headset, HID Telephony | A press of the host's Answer or End call, only where the task is in a phase that has one; the off-hook and ring lights follow the task | The existing `answer` and `end-call` commands |
4706
+ | Mute button | The headset, on the HID Telephony usage page: a Phone Mute report on the press, a Mute LED the agent application writes back | A press of the agent application's Mute, performed the agent application's way; the LED follows the agent application's state, so button, light and control are one state with one owner | The `muted` leg, `mutedBy: "host"` |
4707
+ | Hook switch | The headset, HID Telephony | A press of the agent application's Answer or End call, only where the task is in a phase that has one; the off-hook and ring lights follow the task | The existing `answer` and `end-call` commands |
4701
4708
  | Flash, redial, speed dial | Older headsets and desk-phone style devices | Flash is Hold and Resume where the task offers `hold`; redial and speed dial map to nothing on a desk with no dial pad on a transfer, and are ignored | Nothing new |
4702
- | Volume up and down | The headset's own amplifier, or the operating system through the consumer-control keys | Nothing: the device and the system handle it | Nothing, except that a speaker at nought is `audio.output.flowing: false` where the host can know it |
4709
+ | Volume up and down | The headset's own amplifier, or the operating system through the consumer-control keys | Nothing: the device and the system handle it | Nothing, except that a speaker at nought is `audio.output.flowing: false` where the agent application can know it |
4703
4710
  | Microphone gain and level | The operating system, the headset's own boost | A level meter, so the agent can see they are heard | Nothing: a level is a flicker, not a state |
4704
- | Hardware or operating-system mute | A slider on the headset, the system's input mute | Observes it, publishes `flowing: false, mutedBy: "station"`, records the leg during a call, and tells the agent which it is where it knows -- headset or system -- and what to do; a host whose mute is `station` clears a system mute itself, a browser can only say so | The report and the leg |
4711
+ | Hardware or operating-system mute | A slider on the headset, the system's input mute | Observes it, publishes `flowing: false, mutedBy: "station"`, records the leg during a call, and tells the agent which it is where it knows -- headset or system -- and what to do; an agent application whose mute is `station` clears a system mute itself, a browser can only say so | The report and the leg |
4705
4712
  | Device changed, unplugged, permission revoked | The operating system | Re-capture, prompt, report | Already `audio.input` and `audio.output` with `lost`, `denied`, `no-device` |
4706
4713
 
4707
- **What the host shows.** Beside Mute, a standing line while the station is muted, saying which and
4708
- what to do, with a button that clears a system mute only on a host whose mute is `station`. The
4714
+ **What the agent application shows.** Beside Mute, a standing line while the station is muted, saying which and
4715
+ what to do, with a button that clears a system mute only on an agent application whose mute is `station`. The
4709
4716
  Mute control does not pretend: while the station is muted it shows the agent cannot be heard and
4710
- that pressing it will not change that, and a press still toggles the host's own mute, so the two
4717
+ that pressing it will not change that, and a press still toggles the agent application's own mute, so the two
4711
4718
  states stay separate and the agent is not unmuted by surprise when the slider moves back. Before a
4712
4719
  call, the same line in the ready state, so an agent does not learn of it from a silent customer;
4713
4720
  whether work is held back is the adapter's decision from the report, as it is for every station
4714
4721
  fact. Where a provider's own platform holds a mute of its own -- a bridge that silences a leg --
4715
- that is a fact about the switch, reported as the provider sees fit, and never the host's Mute.
4722
+ that is a fact about the switch, reported as the provider sees fit, and never the agent application's Mute.
4716
4723
 
4717
4724
  ### Which commands need a capability
4718
4725
 
@@ -4725,7 +4732,7 @@ declared:
4725
4732
  | `answer`, `accept` | Nothing. A task that was offered can be accepted, or offering it meant nothing. |
4726
4733
  | `end-call` | The `endCall` capability. |
4727
4734
  | `conference` with `action: "remove"` | The `conference` capability, and somebody else on the call: a remove that would leave the agent alone is `end-call`, and a provider answers it `failed`. |
4728
- | `decline` | The `decline` capability on any channel, **and** Omni provisioning permitting it. One word for refusing an offer, whatever the channel. |
4735
+ | `decline` | The `decline` capability on any channel, **and** Omni local policy permitting it. One word for refusing an offer, whatever the channel. |
4729
4736
  | `call` | The `preview` phase. A record put in front of an agent is there to be called, so the phase is the gate and there is no capability. It is a dial, with a `dialId` and a `dial-outcome`. |
4730
4737
  | `complete` | `completionMode: "agent-command"`. The `outcomes` capability decides whether a code travels with the command, never whether the command exists — a task Omni cannot complete never ends. What travels is what the capability published: a code from its list where it has one (`command.complete.outcome.unknown`), a code at all where it requires one (`.outcome.required`), notes as it said (`.notes.required`, `.notes.unexpected`), and neither where the task declares no outcomes (`.outcome.unexpected`). |
4731
4738
  | `connect-back` | The `connectBack` capability **and** the `completing` phase. It exists to reach the party again after the call, so it has no meaning while the call is up. |
@@ -4751,10 +4758,10 @@ The commands with a phase of their own -- `answer`, `accept` and `decline` in `p
4751
4758
 
4752
4759
  `validateTaskCommand(command, task)` holds a command to this table at runtime, both ways: the
4753
4760
  capability it needs, the phase it belongs to, and the state that has to stand. The task it wants
4754
- is the one the provider published, not a host's own mapping of it: a host that keeps only its
4761
+ is the one the provider published, not an agent application's own mapping of it: an agent application that keeps only its
4755
4762
  mapped shape has nothing honest to pass, and then checks shape alone, which is still worth doing
4756
4763
  -- it names a command the wire never had -- but is not the table. Keeping the published task
4757
- beside the mapped one is what the full check costs a host; an adapter has it for free. The
4764
+ beside the mapped one is what the full check costs an agent application; an adapter has it for free. The
4758
4765
  validator holds a command only to a task that stands: a task handed in that is not one the wire
4759
4766
  published is named (`command.task`) rather than checked against.
4760
4767
 
@@ -4805,8 +4812,8 @@ react rather than only display the message:
4805
4812
  | --- | --- |
4806
4813
  | `omni.not-authenticated` | The provider session is no longer usable. The adapter has published `expired` at or before this answer — the state is what Omni surfaces reauthentication from; the code says why this action failed, and is never the only signal. |
4807
4814
  | `omni.capability-not-enabled` | The action targets a capability this task, manifest, or login did not declare — including a lead command from a login whose `capabilities` no longer carry it. |
4808
- | `omni.task-not-found` | The provider-local task id is unknown, typically after the task already ended. |
4809
- | `omni.phone-not-permitted` | The host declared a `phone` the platform does not permit for this agent -- a softphone for an agent configured for a desk phone, or the reverse. The login is refused at authentication, and the provider never reconfigures the agent to make the declaration true. See **How the agent hears the call**. |
4815
+ | `omni.task-not-found` | The assignment named is not one the provider holds, typically after the task already ended. |
4816
+ | `omni.phone-not-permitted` | The agent application declared a `phone` the platform does not permit for this agent -- a softphone for an agent configured for a desk phone, or the reverse. The login is refused at authentication, and the provider never reconfigures the agent to make the declaration true. See **How the agent hears the call**. |
4810
4817
  | `omni.destination-not-permitted` | The dialled number, or the `destinationId` named, is not one the provider offers this agent. |
4811
4818
  | `omni.rate-limited` | The action was throttled. Pair with `retryAfterMs`. |
4812
4819
  | `omni.unavailable` | The provider is temporarily unable to serve the action, including any command sent while `transport-status` is not `active`. |
@@ -4820,7 +4827,7 @@ They are published as `OMNI_FAILURE_CODES`.
4820
4827
 
4821
4828
  | Field | Contract |
4822
4829
  | --- | --- |
4823
- | `id` | Required identifier for this event, unique within the login. Omni does not act on it; it exists so a host log line and an adapter log line can be matched when something has to be traced. |
4830
+ | `id` | Required identifier for this event, unique within the login. Omni does not act on it; it exists so an agent application log line and an adapter log line can be matched when something has to be traced. |
4824
4831
  | `loginId` | Login session that produced the event. Omni rejects any other value, which only reaches it if an adapter kept an old connection emitting after a re-login. |
4825
4832
  | `occurredAt` | Valid RFC-3339 timestamp with an explicit timezone, representing provider observation time. |
4826
4833
  | `event` | Typed `ProviderEvent` payload. |
@@ -4835,7 +4842,7 @@ instant that the source cannot establish makes that evidence unavailable, not pe
4835
4842
  invent a timestamp or silently omit a required field.
4836
4843
 
4837
4844
  Clock estimation is an exception, not the standard interpretation of events. An ISO timestamp
4838
- identifies an instant; it does not prove that the host and provider clocks are synchronized.
4845
+ identifies an instant; it does not prove that the agent application and provider clocks are synchronized.
4839
4846
  Use an explicitly trusted clock in the relevant domain. Do not infer a general clock offset
4840
4847
  from event arrivals, shift source timestamps, or use an estimate to order events or create history.
4841
4848
 
@@ -4843,29 +4850,29 @@ The current exceptions and their reasons are:
4843
4850
 
4844
4851
  | Case | Exception and reason |
4845
4852
  | --- | --- |
4846
- | Host display of provider deadlines (`allocationExpiresAt`, `previewEndsAt`, wrap deadline) | A countdown may use an explicitly bounded provider-clock estimate when a trusted direct clock is unavailable, because the deadline belongs to another clock domain. This estimates the display only; it does not establish that the provider acted. Without usable time, show timing uncertainty. |
4847
- | Host-triggered preview deadline | A bounded clock estimate with monotonic aging may schedule the host's Call command because the provider owns the deadline but the host owns the trigger. Do not trigger before the deadline is known to have passed; invalidate on clock discontinuity and reconcile when uncertain. |
4853
+ | Agent application display of provider deadlines (`assignmentExpiresAt`, `previewEndsAt`, wrap deadline) | A countdown may use an explicitly bounded provider-clock estimate when a trusted direct clock is unavailable, because the deadline belongs to another clock domain. This estimates the display only; it does not establish that the provider acted. Without usable time, show timing uncertainty. |
4854
+ | Agent application-triggered preview deadline | A bounded clock estimate with monotonic aging may schedule the agent application's Call command because the provider owns the deadline but the agent application owns the trigger. Do not trigger before the deadline is known to have passed; invalidate on clock discontinuity and reconcile when uncertain. |
4848
4855
  | Recording evidence expiry | A bounded observer-domain clock estimate with monotonic aging may assess freshness because observation and expiry belong to the recorder's clock. If time cannot be trusted, recording state is unknown; never renew evidence from receipt or replay. |
4849
4856
  | Unknown recording state | `observedAt` and `validUntil` are absent because there is no confirmed observation. The containing provider event still has its own `occurredAt`; that publication is not a recorder observation. |
4850
4857
  | Direct snapshot reads and method requests/results | These are reads/operations, not event envelopes, and their current types have no general event timestamp. A snapshot event still carries `occurredAt`; embedded source instants remain unchanged. Do not treat a method result or read completion time as an occurrence boundary. |
4851
- | Host-provided provider-clock estimate | Best-effort ISO time may be supplied by the host for optional comparisons; it is not a source observation or accuracy guarantee. The reason is that the host does not own the provider clock. |
4852
- | Provider receipt timestamps | The provider may use its own receipt instant for final records of receipt/processing because host timestamps are untrusted advisory input. Receipt must not be presented as an earlier action or capture boundary. |
4853
- | Optional source instants and deadlines | Omit only where the declared type permits absence and the source has no evidence or the policy has no deadline (for example unlimited preview). Do not replace absence with host time. |
4858
+ | Agent application-provided provider-clock estimate | Best-effort ISO time may be supplied by the agent application for optional comparisons; it is not a source observation or accuracy guarantee. The reason is that the agent application does not own the provider clock. |
4859
+ | Provider receipt timestamps | The provider may use its own receipt instant for final records of receipt/processing because agent application timestamps are untrusted advisory input. Receipt must not be presented as an earlier action or capture boundary. |
4860
+ | Optional source instants and deadlines | Omit only where the declared type permits absence and the source has no evidence or the policy has no deadline (for example unlimited preview). Do not replace absence with agent application time. |
4854
4861
 
4855
4862
  Every additional exception must be listed with its scope and reason before adoption. Estimates
4856
4863
  must specify their uncertainty and validity; elapsed time should use monotonic aging, and a clock
4857
4864
  jump invalidates the estimate. The optional check below samples provider time without changing event timestamps. Report
4858
4865
  source-measured durations where required; timestamp subtraction is not a substitute.
4859
4866
 
4860
- #### Optional periodic provider time checks and host estimates
4867
+ #### Optional periodic provider time checks and agent application estimates
4861
4868
 
4862
4869
  A provider may declare `Manifest.timeCheck: true` and implement `Connection.checkTime(request)`.
4863
- Omission means unsupported. The host separately opts in with `ProviderTimeCheckPolicy`; these
4864
- host-local settings are not task policy or a guarantee. All four durations are explicit positive
4870
+ Omission means unsupported. The agent application separately opts in with `ProviderTimeCheckPolicy`; these
4871
+ agent application-local settings are not task policy or a guarantee. All four durations are explicit positive
4865
4872
  safe integer milliseconds, with `maxRoundTripMs <= timeoutMs <= intervalMs`. No default interval
4866
4873
  is assumed. Validate settings with `validateProviderTimeCheckPolicy`.
4867
4874
 
4868
- While the connection is active, the host checks immediately on opt-in and then at `intervalMs`
4875
+ While the connection is active, the agent application checks immediately on opt-in and then at `intervalMs`
4869
4876
  using a monotonic scheduler. Only one check may be outstanding. Missed ticks are skipped, never
4870
4877
  replayed in a burst. Each request has a fresh ID. The provider samples its own event/deadline
4871
4878
  clock after receiving the request and before returning `providerTime` as an ISO/RFC3339 instant,
@@ -4874,25 +4881,25 @@ may masquerade as provider time. A provider unable to sample that domain must no
4874
4881
  Clock authority replacement or a discontinuity changes `clockId`.
4875
4882
 
4876
4883
  Validate requests and responses with `validateProviderTimeCheckRequest` and
4877
- `validateProviderTimeCheckResult`. The host also checks the outstanding request, provider/connection
4884
+ `validateProviderTimeCheckResult`. The agent application also checks the outstanding request, provider/connection
4878
4885
  and login, monotonic elapsed time and cancellation after the await: a late successful response is
4879
4886
  still rejected. Reject samples at or beyond `timeoutMs`, or above `maxRoundTripMs`. Cancel local
4880
4887
  tracking and invalidate estimates on disconnect, logout, policy disable, clock change or clock
4881
4888
  jump; late results cannot restore them. Resume with a fresh check after reconnection. Expire a
4882
- sample at `maxSampleAgeMs` using monotonic elapsed time. Failure is visible through the host's
4889
+ sample at `maxSampleAgeMs` using monotonic elapsed time. Failure is visible through the agent application's
4883
4890
  existing diagnostic path, with the estimate unavailable; the next scheduled check can recover.
4884
4891
  Checking failure alone does not assert call/recording state or require a healthy connection to close.
4885
4892
  This read-only check is not a task command. Protocol supplies declarations and validators; the
4886
- host implements the scheduler and the provider implements the clock read.
4893
+ agent application implements the scheduler and the provider implements the clock read.
4887
4894
 
4888
- The host may also expose `Host.estimateProviderTime({ providerId, loginId })`. It returns an ISO
4895
+ The agent application may also expose `Host.estimateProviderTime({ providerId, loginId })`. It returns an ISO
4889
4896
  `at` in that provider's clock domain, the same explicit scope and `clockId`, or `undefined` when
4890
4897
  unavailable. Optional `uncertaintyMs` is an estimate, not a guaranteed bound. The method is optional
4891
- at the host level and is deliberately absent from `HostGuarantees`. A provider declaring time
4892
- checks does not require the host to expose estimates, and an estimate need not originate from
4893
- this check if the host has another explicitly configured source for that provider clock.
4898
+ at the agent application level and is deliberately absent from `HostGuarantees`. A provider declaring time
4899
+ checks does not require the agent application to expose estimates, and an estimate need not originate from
4900
+ this check if the agent application has another explicitly configured source for that provider clock.
4894
4901
 
4895
- To estimate the difference, the host brackets the request with local send/receive instants and
4902
+ To estimate the difference, the agent application brackets the request with local send/receive instants and
4896
4903
  measures elapsed time monotonically. For provider sample P and local bracketing instants H0/H1,
4897
4904
  the offset under stable clocks lies between P-H1 and P-H0, before clock error and timestamp
4898
4905
  precision are considered. A midpoint is only an estimate; one-way delays need not be symmetric.
@@ -4901,22 +4908,22 @@ sample with monotonic elapsed time, and return unavailable after its configured
4901
4908
  `validateProviderTimeEstimate` checks shape and scope, not actual accuracy or freshness.
4902
4909
 
4903
4910
  A provider may declare `Manifest.timestampAuthority: "provider"`: its own timestamps are
4904
- used for final records, and host-supplied timestamps are advisory. This declaration is independent
4905
- of time-check support and the optional host estimate; neither changes who owns the final record.
4906
- Omission makes no promise that host timestamps will be trusted. No host-authoritative default
4911
+ used for final records, and agent application-supplied timestamps are advisory. This declaration is independent
4912
+ of time-check support and the optional agent application estimate; neither changes who owns the final record.
4913
+ Omission makes no promise that agent application timestamps will be trusted. No agent application-authoritative default
4907
4914
  is inferred. Successful `recordStep` responses identify the provider-selected history instant;
4908
- see **The host records what it performs** for correlation and retained bindings.
4915
+ see **The agent application records what it performs** for correlation and retained bindings.
4909
4916
 
4910
- A provider need not trust or adopt any host-supplied timestamp. It may timestamp an incoming
4917
+ A provider need not trust or adopt any agent application-supplied timestamp. It may timestamp an incoming
4911
4918
  message using its own clock at receipt and use that for its own processing/accounting. The reason
4912
- for this exception is that host clocks and host estimates are not authoritative at the provider.
4913
- Receipt time must be described as receipt/observation time, not relabeled as the original host
4919
+ for this exception is that agent application clocks and agent application estimates are not authoritative at the provider.
4920
+ Receipt time must be described as receipt/observation time, not relabeled as the original agent application
4914
4921
  action, recorder capture boundary, or proof an operation applied. An existing field with a
4915
4922
  specific occurrence meaning still requires that evidence; this option does not silently redefine
4916
- it. Host-only instants remain advisory input; the provider owns its authoritative publication.
4923
+ it. Agent application-only instants remain advisory input; the provider owns its authoritative publication.
4917
4924
 
4918
- This host estimate is another explicit timestamp exception: it helps optional displays and
4919
- provider-clock comparisons when the host lacks that clock directly. It is not a source occurrence,
4925
+ This agent application estimate is another explicit timestamp exception: it helps optional displays and
4926
+ provider-clock comparisons when the agent application lacks that clock directly. It is not a source occurrence,
4920
4927
  may not replace event/history timestamps, and alone cannot authorize deadline actions or prove
4921
4928
  recording freshness. Uses requiring a trustworthy bound still need independently established
4922
4929
  clock accuracy/drift assumptions. It neither synchronizes the operating-system clock nor changes
@@ -4979,8 +4986,8 @@ safe for the agent to see.
4979
4986
  | `active` | The transport is up and the provider is serving this session. It is the only value under which work arrives. |
4980
4987
  | `error` | The adapter cannot serve the session and is not simply mid-reconnect. Say why in `message`, and say what revives it in `recovery` — required here, forbidden on any other status. It is not terminal: an adapter that recovers on its own still reports `connecting` and then `active`, and one that cannot is revived as `recovery` says. |
4981
4988
 
4982
- **An error names its recovery, and the host acts on that word.** The adapter knows why its session
4983
- died; the host knows how to run a login. `recovery` joins the two:
4989
+ **An error names its recovery, and the agent application acts on that word.** The adapter knows why its session
4990
+ died; the agent application knows how to run a login. `recovery` joins the two:
4984
4991
 
4985
4992
  - **`reconnect`** — the login is good and this connection is not: a backend restart, a session the
4986
4993
  platform no longer recognises. Omni calls `disconnect()` on the dead connection and then
@@ -4995,7 +5002,7 @@ died; the host knows how to run a login. `recovery` joins the two:
4995
5002
  `reconnect`, and the fresh snapshot re-establishes state. The adapter tears nothing down itself
4996
5003
  and expects nothing to carry on: the connection that reported `error` is finished.
4997
5004
 
4998
- **Patience is the host's.** An adapter in `connecting` retries for as long as it takes and never
5005
+ **Patience is the agent application's.** An adapter in `connecting` retries for as long as it takes and never
4999
5006
  has to decide when to stop. Omni owns giving up: after however long it chooses to wait, it may
5000
5007
  call `disconnect()` and either `connect()` afresh or surface the failure — so neither side waits
5001
5008
  for the other to blink.
@@ -5007,11 +5014,11 @@ availability on `BreakState`. Nor does it carry authentication — a session tha
5007
5014
  the transport underneath may be perfectly `active`. Provider login identity likewise belongs to
5008
5015
  authentication state, not here.
5009
5016
 
5010
- **Only `active` means work can arrive.** Omni stops expecting allocations in any other value, so an
5017
+ **Only `active` means work can arrive.** Omni stops expecting assignments in any other value, so an
5011
5018
  adapter that leaves a stale `active` in place is telling Omni to keep waiting for work that cannot
5012
5019
  come — see **Liveness**.
5013
5020
 
5014
- **The status is seen, not merely known.** A host renders the transport's status where the agent
5021
+ **The status is seen, not merely known.** An agent application renders the transport's status where the agent
5015
5022
  works — `connecting` from the moment it is reported, `error` with what revives it — and never a
5016
5023
  healthy workspace over a transport that cannot serve it: an agent talking on a desk whose transport
5017
5024
  died was an incident, and it happened because the desk knew and did not say. The same obligation
@@ -5046,9 +5053,9 @@ snapshot. `seed(snapshot)` returns violations, which callers must check. This is
5046
5053
  tracker, not a complete production reducer: snapshot freshness, login/connection fencing and
5047
5054
  full task consistency remain separately required.
5048
5055
 
5049
- **Both sides must enforce the order.** The host validates immediately before dispatch; the
5056
+ **Both sides must enforce the order.** The agent application validates immediately before dispatch; the
5050
5057
  provider rechecks current permission and state atomically before acting. The provider validates
5051
- the resulting break/task state before publication and serializes those publications. The host
5058
+ the resulting break/task state before publication and serializes those publications. The agent application
5052
5059
  validates the envelope, transition and full task consistency before replacing local state. A
5053
5060
  request result does not optimistically advance break state, and a delayed command cannot apply
5054
5061
  to a later attempt merely because its status happens to look compatible. Keep at most one
@@ -5061,7 +5068,7 @@ Normal order is `not-requested` → `awaiting-approval` → `granted` →
5061
5068
  returns a precommit request to `not-requested`; an explicit agent end returns a committed
5062
5069
  break there. Same-state restatements are allowed. An evidenced forced break is the explicit
5063
5070
  exception to requesting/granting, and must carry its forced actor/state. Neither skipped
5064
- publication nor a host-local guess creates another exception. A later normal attempt starts
5071
+ publication nor an agent application-local guess creates another exception. A later normal attempt starts
5065
5072
  from `not-requested`, never by regressing an active break into a request.
5066
5073
 
5067
5074
  A fresh authoritative snapshot establishes a new baseline; do not run this event-transition
@@ -5102,8 +5109,8 @@ The provider's word that the task's audio should now attach. Omni calls `openMed
5102
5109
  a task carried with `media: "started"`, which is how a reconnect snapshot reattaches audio an
5103
5110
  earlier event brought — and renders the call as live from that word, never from its own senses. It
5104
5111
  precedes `openMedia` and is never a reply to it: a provider whose media state comes from the
5105
- platform, a station going in use the moment a call is answered, sends it then, before any host has
5106
- opened anything, and `openMedia` has its own answer for what the host did. It
5112
+ platform, a station going in use the moment a call is answered, sends it then, before any agent application has
5113
+ opened anything, and `openMedia` has its own answer for what the agent application did. It
5107
5114
  names a task whose work has begun, and it alternates with `task-media-ended`: media that never
5108
5115
  started cannot end, so a live call whose provider says nothing about its audio is a provider in
5109
5116
  breach, not a state a desk fills in from its own devices.
@@ -5138,21 +5145,21 @@ A successful `complete` or `transfer` command does not clear the task. Omni wait
5138
5145
  and not for ever: `applied` to a completion -- `complete`, or a lead's `take-over-call` -- says the
5139
5146
  provider has completed the task, and its `task-ended` follows within the
5140
5147
  manifest's `completionSettleMs`. A provider never answers `applied` for a completion it has not yet
5141
- performed. Past the bound the host calls `snapshot()`: a snapshot still carrying the task is a task
5148
+ performed. Past the bound the agent application calls `snapshot()`: a snapshot still carrying the task is a task
5142
5149
  held open by a provider that said it was done, and the desk shows it as unsettled -- "Completing...
5143
5150
  the provider has not confirmed" -- naming the command; a snapshot no longer carrying it clears the
5144
5151
  task, since the ending was owed and lost. The drive holds a provider to the same bound
5145
5152
  (`drive.completion.unsettled`). The `task-media-ended` event and the `completing` phase are likewise
5146
5153
  non-terminal. A replacement
5147
5154
  snapshot that no longer contains the task also clears it. Repeated `task-ended` delivery with the
5148
- same envelope ID is harmless, and a `task-ended` naming an allocation that has already ended is
5149
- recognised as the late event it is, never applied to the life now open under the same id.
5155
+ same envelope ID is harmless, and a `task-ended` naming an assignment that has already ended is
5156
+ recognised as the late event it is, never applied to whatever assignment is open now.
5150
5157
 
5151
5158
  ### `dial-outcome`
5152
5159
 
5153
- How a dial the host placed ended, once, either way, named by the `dialId` the host sent: `answered`,
5160
+ How a dial the agent application placed ended, once, either way, named by the `dialId` the agent application sent: `answered`,
5154
5161
  or one of the declared ways of not reaching the destination, with the switch's `reason` where it
5155
- gave one. `taskId` names the task the dial was on, where there was one, and that task may already
5162
+ gave one. `assignmentId` names the task the dial was on, where there was one, and that task may already
5156
5163
  have ended. Omni shows it to the agent against the call it belonged to and does nothing else: no
5157
5164
  audio moves, since the provider bridges the leg on its side, and no dial is repeated. See **Every
5158
5165
  dial has an outcome**.
@@ -5168,11 +5175,11 @@ explicit timezones.
5168
5175
  The provider's report that something its platform answered broke a rule the adapter relies on — a
5169
5176
  state read that contradicted itself, a `task-ended` naming a task nobody held, a party arriving
5170
5177
  without a name. `expected` is the rule as a sentence, `observed` is what came instead, and
5171
- `taskId` names the task where there is one. **Informational, never behavioural**: the provider has
5178
+ `assignmentId` names the task where there is one. **Informational, never behavioural**: the provider has
5172
5179
  already done the safe thing before it speaks, and nothing in the task or break machinery reacts to
5173
- a diagnostic. It exists so that the loudness reaches a person — a host renders each one where the
5180
+ a diagnostic. It exists so that the loudness reaches a person — an agent application renders each one where the
5174
5181
  agent works and keeps a count an operator can read, because a healthy workspace over a shouting
5175
- console is the silence problem one layer up. One event per occurrence; the host counts, the
5182
+ console is the silence problem one layer up. One event per occurrence; the agent application counts, the
5176
5183
  provider does not batch. `exerciseAdapter` treats a diagnostic delivered during a run as a
5177
5184
  violation (`diagnostic.raised`): a conformance run against a platform that is breaking its rules
5178
5185
  fails loudly rather than passing with a note. A task published under `capabilitySource:
@@ -5183,7 +5190,7 @@ fails loudly rather than passing with a note. A task published under `capability
5183
5190
  | --- | --- |
5184
5191
  | `expected` | Required. The rule that was broken, as a sentence a person can read. |
5185
5192
  | `observed` | Required. What the platform answered instead. |
5186
- | `taskId` | Optional. The task concerned, where there is one, with its `allocationId` beside it: a task is named with its life, and an allocation never alone. |
5193
+ | `assignmentId` | Optional. The task concerned, where there is one, named by its assignment. |
5187
5194
 
5188
5195
  ### `queue-summary`
5189
5196
 
@@ -5217,10 +5224,11 @@ declares the `calendar` idle capability.
5217
5224
 
5218
5225
  ## Utilities
5219
5226
 
5220
- ### `taskKey(providerId, taskId)`
5227
+ ### `taskKey(providerId, assignmentId)`
5221
5228
 
5222
- Returns a collision-safe global task key by encoding and joining the provider-local identifiers.
5223
- Use this key in Omni state; never assume task IDs are unique across providers.
5229
+ Returns a collision-safe global task key by encoding and joining the provider id and the
5230
+ assignment id. Use this key in Omni state; an assignment id is unique within its provider and
5231
+ never across providers.
5224
5232
 
5225
5233
  ### `userKey(providerId, userId)`
5226
5234
 
@@ -5228,7 +5236,7 @@ The same treatment for a `UserId`, and needed for the same reason: user identifi
5228
5236
  issued by each provider independently, so two providers will eventually issue the same string for
5229
5237
  different people. Encode and join before storing or comparing.
5230
5238
 
5231
- Use it for every `UserId` — `interactionHistory[].by`, team members, `memberId` on a
5239
+ Use it for every `UserId` — `history[].by`, team members, `memberId` on a
5232
5240
  lead command, `ForcedBreak.by`. A bare one is only ever compared against another from the **same** provider; anything
5233
5241
  wider goes through this key.
5234
5242
 
@@ -5252,18 +5260,18 @@ same exported checks are used by Omni and adapter tests so their interpretations
5252
5260
  | `validateEventEnvelope(envelope, manifest)` | Envelope identity, timestamp, and the payload for each event type. |
5253
5261
  | `validateContact(contact)` | Contact field shapes and attribute keys. Every field is optional, so this checks what is present rather than what is missing. |
5254
5262
  | `validateScheduledActivity(activity)` | Required activity fields and start/end ordering. |
5255
- | `validateHostGuarantees(guarantees)` | What a host promises: only the guarantees this contract names, each declared by presence and never `false`. The harness validates the guarantees of whatever host a test hands the adapter. |
5263
+ | `validateHostGuarantees(guarantees)` | What an agent application promises: only the guarantees this contract names, each declared by presence and never `false`. The harness validates the guarantees of whatever agent application a test hands the adapter. |
5256
5264
  | `validateProviderTimeCheckPolicy(policy)` | Explicit optional polling settings, positive safe-integer durations and round-trip/timeout/interval ordering. |
5257
- | `validateProviderTimeCheckRequest(request)` | Fresh-request shape; the host enforces actual uniqueness and outstanding-request lifetime. |
5265
+ | `validateProviderTimeCheckRequest(request)` | Fresh-request shape; the agent application enforces actual uniqueness and outstanding-request lifetime. |
5258
5266
  | `validateProviderTimeCheckResult(result, request, loginId)` | ISO timestamp, clock identity, exact request/login correlation; timing and source accuracy remain runtime checks. |
5259
- | `validateProviderTimeEstimate(estimate, scope)` | Optional host estimate shape and provider/login scope; no accuracy guarantee. |
5260
- | `validateInteractionReport(report, path?, manifest?)` | What the host reports of a leg it performed, for an adapter to check before forwarding: a task, a step, when it began, a positive `seconds` where stated, and an explicit `ended` that carries the final duration. Given the manifest, a running report is refused unless it declares `runningStepReports`. |
5261
- | `validateHostReport(report)` | The host's own report as published to an adapter: `online`, and where there is audio, an input that is `available` with the microphone and `flowing`, or `unavailable` with a reason and the failure that says why, and an output that is `available` or `unavailable` with its failure. The harness validates whatever host a test hands the adapter; `stillHost(report)` builds one that never changes. |
5262
- | `validateHostMute(mute, softphone)` | What the host's Mute does, stated on a softphone login and nowhere else: `stream` or `station` (`host.mute`), required where the host holds a microphone (`host.mute.required`) and refused where it does not (`host.mute.unexpected`). The harness holds `ConnectContext.host.mute` to it. |
5263
- | `validateLoginStore(store)` | The login's store the host hands every connection: an object with `get`, `set` and `delete` (`store.shape`, `store.get`, `.set`, `.delete`). The harness holds `ConnectContext.store` to it. |
5264
- | `validateCapacity(capacity)` | What the host states as capacity: a whole number of zero or more (`capacity.count`), zero being host-stopped. The harness states one on connect and two, one and zero after the drive, each answered `applied`, and holds any offer to the count in force (`stream.taskOffered.overCapacity`). |
5267
+ | `validateProviderTimeEstimate(estimate, scope)` | Optional agent application estimate shape and provider/login scope; no accuracy guarantee. |
5268
+ | `validateHistoryReport(report, path?, manifest?)` | What the agent application reports of a leg it performed, for an adapter to check before forwarding: a task, a step, when it began, a positive `seconds` where stated, and an explicit `ended` that carries the final duration. Given the manifest, a running report is refused unless it declares `runningStepReports`. |
5269
+ | `validateHostReport(report)` | The agent application's own report as published to an adapter: `online`, and where there is audio, an input that is `available` with the microphone and `flowing`, or `unavailable` with a reason and the failure that says why, and an output that is `available` or `unavailable` with its failure. The harness validates whatever agent application a test hands the adapter; `stillHost(report)` builds one that never changes. |
5270
+ | `validateHostMute(mute, softphone)` | What the agent application's Mute does, stated on a softphone login and nowhere else: `stream` or `station` (`host.mute`), required where the agent application holds a microphone (`host.mute.required`) and refused where it does not (`host.mute.unexpected`). The harness holds `ConnectContext.host.mute` to it. |
5271
+ | `validateLoginStore(store)` | The login's store the agent application hands every connection: an object with `get`, `set` and `delete` (`store.shape`, `store.get`, `.set`, `.delete`). The harness holds `ConnectContext.store` to it. |
5272
+ | `validateCapacity(capacity)` | What the agent application states as capacity: a whole number of zero or more (`capacity.count`), zero being agent application-stopped. The harness states one on connect and two, one and zero after the drive, each answered `applied`, and holds any offer to the count in force (`stream.taskOffered.overCapacity`). |
5265
5273
  | `validateAuthenticationResult(result, method)` | What `start()` or `complete()` answered: a challenge or a rejection, a login or a rejection. A rejection's failure is held to its rules -- an `omni.` code the contract lists, and `omni.phone-not-permitted` never retryable, since the agent's station is configuration. `validateAuthenticationFailure(failure)` is the same check on a failure alone. |
5266
- | `validateTaskCommand(command, task?)` | What a command needs to be issuable, against the task it names: its own shape -- a dial's `dialId`, a transfer's item, a remove naming exactly one person -- and, with the task, the capability the table above gates it on (`command.capability.<name>`, `.locked`), the phase it belongs to (`command.phase.*`, `command.phase.interaction` for every control on the call or the conversation), and the state that has to stand: a consulted entry, a lead requested, somebody else still on the call (`command.conference.remove.alone`). A host validates before sending and an adapter before acting. |
5274
+ | `validateTaskCommand(command, task?)` | What a command needs to be issuable, against the task it names: its own shape -- a dial's `dialId`, a transfer's item, a remove naming exactly one person -- and, with the task, the capability the table above gates it on (`command.capability.<name>`, `.locked`), the phase it belongs to (`command.phase.*`, `command.phase.interaction` for every control on the call or the conversation), and the state that has to stand: a consulted entry, a lead requested, somebody else still on the call (`command.conference.remove.alone`). An agent application validates before sending and an adapter before acting. |
5267
5275
  | `validateResult(result, method)` | What a connection method answered: the status it gives, a failure where the status says so and nowhere else, the failure's shape, and that an `omni.` code is one this contract names. |
5268
5276
  | `validateAuthenticationState(state)` | The identity each state must carry, the capabilities a usable login declares, and the expiry that only `authenticated` may. Omni applies it to every state a session publishes — the republished as much as the first. |
5269
5277
 
@@ -5289,25 +5297,25 @@ and may be compiled against a different protocol version, so its output is untru
5289
5297
  Validating a snapshot before it replaces provider state is what stops a malformed task from
5290
5298
  reaching the workspace.
5291
5299
 
5292
- ### What the host does with what it refuses
5300
+ ### What the agent application does with what it refuses
5293
5301
 
5294
5302
  A refusal has an aftermath on the desk and a report to the provider, and both are stated.
5295
5303
 
5296
- - **A refused snapshot replaces nothing.** The host keeps the last state it took from this
5304
+ - **A refused snapshot replaces nothing.** The agent application keeps the last state it took from this
5297
5305
  provider whole, and shows the provider as faulted -- the transport as it stands, and the words
5298
5306
  "last update refused" with the rule -- so the agent knows the view is standing still rather than
5299
5307
  believing it current. It does not adopt the good half of a snapshot: a task the agent is on would
5300
5308
  vanish from the desk while the call is up.
5301
- - **A refused event is dropped and counted.** The state the host holds does not move for it. The
5302
- provider is told, and may republish a corrected state or raise a `diagnostic`; the host retries
5309
+ - **A refused event is dropped and counted.** The state the agent application holds does not move for it. The
5310
+ provider is told, and may republish a corrected state or raise a `diagnostic`; the agent application retries
5303
5311
  nothing. The desk shows nothing for it: the view kept moving for every other event, so "last
5304
5312
  update refused" would be false of it, and a chip that said nothing would be right about the
5305
- transport. Counted, and the provider told, is all a host can truthfully do for one event.
5313
+ transport. Counted, and the provider told, is all an agent application can truthfully do for one event.
5306
5314
  - **The provider is told, every time.** `refused(report)` carries the artefact, the envelope id for
5307
5315
  an event, and every violation with its rule and path. An adapter logs it at error and treats it as
5308
- its own defect until shown otherwise: what the host refused never reached the agent, and a
5316
+ its own defect until shown otherwise: what the agent application refused never reached the agent, and a
5309
5317
  provider that hears nothing runs a whole shift beside a frozen desk with nothing wrong on its
5310
- side. The harness tells an adapter under test exactly as a host does
5318
+ side. The harness tells an adapter under test exactly as an agent application does
5311
5319
  (`connection.refused.required`, `connection.refused.rejected`).
5312
5320
 
5313
5321
  ## Conformance helpers
@@ -5339,7 +5347,7 @@ latest the session published during the run, which differs only when the adapter
5339
5347
  A capability granted by a later login requires its methods just as one declared at sign-in does.
5340
5348
 
5341
5349
  `result.notExercised` lists what the run never reached — one subject per family of rules: each
5342
- optional part of a task (`task.browsers`, `task.interactionHistory`, `task.leadAssist`, …), the break's
5350
+ optional part of a task (`task.browsers`, `task.history`, `task.leadAssist`, …), the break's
5343
5351
  `reasons` and `forced`, the team member list's `members` and `requests`, each declared contribution, and
5344
5352
  each event type (`event.task-ended`, …) — and so what a clean `violations` says nothing about.
5345
5353
  Nothing there is a violation: an adapter with no team has nothing to exercise. But a fixture with
@@ -5352,18 +5360,18 @@ in each adopter's own tests. `{ drive: true }` closes that: the exercise takes t
5352
5360
  provider offers through one ordinary lifecycle -- accept it, wait for its media and open it on a
5353
5361
  softphone, hold and resume where the task offers `hold`, end the call where it offers `endCall`,
5354
5362
  complete it with an outcome where the agent completes -- and holds every step to the rules a
5355
- host holds a provider to. Each command is validated against the task as published
5363
+ agent application holds a provider to. Each command is validated against the task as published
5356
5364
  (`drive.command.*`), each answer for its method, a refusal of a control the task offered is a
5357
5365
  violation (`drive.command.failed`), and an event the provider owes and never sends is one too
5358
5366
  (`drive.timeout`, after `driveTimeoutMs`, 5000 by default). Around the drive the exercise holds
5359
- the run to what a host holds a provider to between commands: an offer before the host stated
5367
+ the run to what an agent application holds a provider to between commands: an offer before the agent application stated
5360
5368
  capacity, or beyond the count with nothing dialled on it, is named
5361
5369
  (`stream.taskOffered.beforeCapacity`, `.overCapacity`); every user the snapshot names is looked up
5362
- through `describeUsers` and the answer held to the shape, nobody unasked, nobody described as
5363
- nothing (`describeUsers.user.*`, `describeUsers.unasked`, `connection.describeUsers.empty`); and
5370
+ through `getUserDetails` and the answer held to the shape, nobody unasked, nobody described as
5371
+ nothing (`getUserDetails.user.*`, `getUserDetails.unasked`, `connection.getUserDetails.empty`); and
5364
5372
  the second adapter a `rebuild` gives comes up signed in as the same login from the secrets alone
5365
5373
  before it reads anything (`drive.reload.login`), and is then held to everything the first was on
5366
- connect: the methods its declarations call for, the host's report, a capacity stated to it, its
5374
+ connect: the methods its declarations call for, the agent application's report, a capacity stated to it, its
5367
5375
  snapshot read as the connect snapshot was, and its media opened afresh on a task carried with
5368
5376
  `media: "started"`, since the first client's session died with it. The result also says which rules the
5369
5377
  run evaluated, pass or fail, in `rulesEvaluated`: the validators' as each was applied, the stream's
@@ -5373,12 +5381,12 @@ gap and not a pass. With the audio open on a softphone,
5373
5381
  the drive mutes it for one second and reports the leg through `recordStep`, begun and then ended,
5374
5382
  expecting each report `recorded` with the provider-selected history `at` (`drive.recordStep.failed`, `.rejected`, `result.recordStep.at`); then it mutes again and
5375
5383
  ends the call muted, as agents do, so the leg is open when the media ends, the provider closes it
5376
- in the completing publication or the open entry is refused (`task.interactionHistory.muted.open`),
5384
+ in the completing publication or the open entry is refused (`task.history.muted.open`),
5377
5385
  and the drive's closing report after the media ended is expected `recorded` and to change nothing:
5378
5386
  a record restated afterwards with that leg's duration altered is named (`drive.recordStep.overwritten`).
5379
5387
  Where the provider restates the task's record afterwards, each leg is in it or the hole is named
5380
- (`drive.recordStep.history`). Given `rebuild`, a way to build the adapter again as a host reload
5381
- does, the drive reloads the host as a reload happens: the first client is unsubscribed,
5388
+ (`drive.recordStep.history`). Given `rebuild`, a way to build the adapter again as an agent application reload
5389
+ does, the drive reloads the agent application as a reload happens: the first client is unsubscribed,
5382
5390
  disconnected and its session closed (`drive.reload.handover`), and only then is a second adapter
5383
5391
  built and connected for the same login with the same context and the same `store`; its snapshot
5384
5392
  must carry the task with that leg at its acknowledged provider timestamp and the reported actor, and the run goes on with the second as its
@@ -5386,7 +5394,7 @@ connection to the end. A platform that holds the record hands it back, and an ad
5386
5394
  the record in memory has nothing and is named (`drive.reload.snapshot`, `drive.reload.history`,
5387
5395
  `.rejected`). The second adapter's snapshot is taken as any resync is: held to what the stream knew
5388
5396
  before it replaces it, so a phase gone backwards, a record that shrank or audio forgotten on a task
5389
- still at work is named by the stream's own rules (`stream.snapshot.phase`, `.interactionHistory`,
5397
+ still at work is named by the stream's own rules (`stream.snapshot.phase`, `.history`,
5390
5398
  `.media`) and a reload is a place those rules keep working, not one where they stop. The second
5391
5399
  adapter is held to what the first was: the same provider
5392
5400
  (`drive.reload.manifest`), a snapshot that stands as any snapshot must, and a record that lost none
@@ -5397,12 +5405,12 @@ first client is gone before the second connects, there is no client for the plat
5397
5405
  open task back to, and nothing about the reload is exempt from any rule. The second adapter opens its session from the same
5398
5406
  `secrets`, so the reload is a restore before it is anything else: an adapter that holds a session
5399
5407
  has already put what would rebuild it into the secrets store, from the moment it was handed one,
5400
- not only when a flow completes -- the session is the adapter's, the store is the host's, and a
5401
- host reload is exactly when no flow will run. And once the task has ended, the store the drive
5402
- handed the adapter holds no key naming the task's id, delimited, never as a run of characters inside
5408
+ not only when a flow completes -- the session is the adapter's, the store is the agent application's, and a
5409
+ agent application reload is exactly when no flow will run. And once the task has ended, the store the drive
5410
+ handed the adapter holds no key naming the task's assignment id, delimited, never as a run of characters inside
5403
5411
  another id (`drive.store.retained`); an adapter whose keys never named the task leaves the rule
5404
5412
  unevaluated, and the result says so rather than passing it: a task's keys go
5405
- with the task, or the next offer of the same id inherits them. Outside the
5413
+ with the task, or whatever comes next inherits them. Outside the
5406
5414
  interaction phases with `hold` still declared -- in
5407
5415
  `confirmed`, where the provider publishes it, and in `completing` once this agent's interaction has ended -- the
5408
5416
  drive sends `hold` past the validator that would hold it back, and expects `failed`: the adapter
@@ -5456,8 +5464,8 @@ cannot be established from TypeScript structure alone.
5456
5464
  | `assertReached(result, subjects)` | The exercise met every subject named; throws listing those it did not. Pair it with a clean `exerciseAdapter` result. |
5457
5465
  | `assertAuthenticationRestoreAndExpiry(states)` | A restored authenticated session can refresh and ends in expiry. Every state is validated. |
5458
5466
  | `assertReconnectWithMissedAssignments(before, reconnect, ids)` | A reconnect snapshot restores assignments received while offline. |
5459
- | `stillHost(report?, guarantees?, mute?)` | A host that reports one thing and never changes, for a test context: `{ online: true }` by default, a report with audio for a softphone voice adapter, and never for a desk phone. |
5460
- | `TaskStream`, `BreakStream` | The cross-event models the harness applies after the connect snapshot, exported for a host that wants the same rules at its boundary: `seed(snapshot)`, then `apply(envelope)` returns the violations. |
5467
+ | `stillHost(report?, guarantees?, mute?)` | An agent application that reports one thing and never changes, for a test context: `{ online: true }` by default, a report with audio for a softphone voice adapter, and never for a desk phone. |
5468
+ | `TaskStream`, `BreakStream` | The cross-event models the harness applies after the connect snapshot, exported for an agent application that wants the same rules at its boundary: `seed(snapshot)`, then `apply(envelope)` returns the violations. |
5461
5469
  | `assertBreakFollowsItsRequests(envelopes, snapshot?)` | A break follows its requests: a commit's states only after a grant, never backwards, and a forced break arriving in effect with `forced`. The harness applies the same rules after the connect snapshot. |
5462
5470
  | `assertMediaFollowsTheTask(envelopes, snapshot?)` | The media follows the task and never decides it: every task is introduced once, `task-media-started` and `task-media-ended` alternate on work that has begun, media ends only where it arrived, and what follows the media ending is `completing` or `task-ended`. The harness applies the same rules to every event after the connect snapshot (`stream.*`). A sequence with no media satisfies it by never testing it — pair it with the assertion that the media end is present. |
5463
5471
  | `assertBreakAttemptProviders(candidates, asked)` | A break attempt asks every usable provider holding capacity, `refreshing` included, and nothing of a provider whose login is `expired`. |
@@ -5475,7 +5483,7 @@ Adapters should run the relevant scenarios against deterministic test state befo
5475
5483
 
5476
5484
  ## A provider does not style the workspace
5477
5485
 
5478
- How a deployment themes Omni is the host's concern and is specified with the host, not here. What
5486
+ How a deployment themes Omni is the agent application's concern and is specified with the agent application, not here. What
5479
5487
  belongs in this contract is the boundary. A provider says what a control **is** through its
5480
5488
  capabilities and what its work is **called** through `phaseLabels` and `taskTypePresentation`; how
5481
5489
  any of it is drawn is Omni's. A task cannot select a design language, inject a component, or
@@ -5485,21 +5493,21 @@ override the agent's theme and font preferences.
5485
5493
 
5486
5494
  Recording is voice-only. A task can arrive already recording, including while pending, and offer
5487
5495
  no recording controls. The provider publishes only its own current state on
5488
- the provider field of the task’s `recording` state. The host publishes its own full scoped view in `HostReport.recordings`.
5489
- A provider task update cannot replace host state. Neither a capability nor an accepted command
5496
+ the provider field of the task’s `recording` state. The agent application publishes its own full scoped view in `HostReport.recordings`.
5497
+ A provider task update cannot replace agent application state. Neither a capability nor an accepted command
5490
5498
  establishes recording. Missing state, lost recorder observation, transport loss and expired
5491
5499
  observation mean unknown; they never mean stopped. Paused means a recording remains open without
5492
5500
  capturing. Task hold, task pause and recording pause are independent.
5493
5501
 
5494
- The per-task policy is `Task.capabilities.recording`, with independently optional provider and host
5502
+ The per-task policy is `Task.capabilities.recording`, with independently optional provider and agent application
5495
5503
  action sets. The outer capability may be locked. Absence grants no permission, and a state may
5496
5504
  exist without any permission. A provider may offer only stop for a recording started automatically,
5497
5505
  or withdraw a control on a later task update. There is no global recording mode and no automatic
5498
- start from a capability declaration. Host support is declared on `ConnectContext.host.recording`,
5499
- not the provider-owned manifest. The task chooses an explicitly provisioned host destination;
5506
+ start from a capability declaration. Agent application support is declared on `ConnectContext.host.recording`,
5507
+ not the provider-owned manifest. The task chooses an explicitly provisioned agent application destination;
5500
5508
  unknown destinations or unsupported actions are refused visibly, never redirected to provider
5501
- recording or a default upload location. Initial host support requires voice softphone media and
5502
- capture of both local and remote audio; a host unable to capture either must refuse start/resume.
5509
+ recording or a default upload location. Initial agent application support requires voice softphone media and
5510
+ capture of both local and remote audio; an agent application unable to capture either must refuse start/resume.
5503
5511
  This package declares that contract; it supplies no recorder, media mixing, storage or upload.
5504
5512
 
5505
5513
  | Action | Required current recording state | Confirmed outcome |
@@ -5520,16 +5528,16 @@ Partial success (capture stopped but storage outcome unknown) cannot return fail
5520
5528
  of no effect. It rejects with unknown outcome, reports the failure visibly and publishes whatever
5521
5529
  current capture state is actually known. Retention is not a promise of sample-perfect audio.
5522
5530
 
5523
- Provider commands go exclusively to `Connection.execute`; host commands go exclusively to
5524
- `HostRecording.execute`. Both include task, allocation, request and observation identities; all
5531
+ Provider commands go exclusively to `Connection.execute`; agent application commands go exclusively to
5532
+ `HostRecording.execute`. Both include the assignment, request and observation identities; all
5525
5533
  non-start commands identify the particular recording. IDs are opaque and scoped by provider login,
5526
5534
  task and recorder owner. They are never inferred from filenames or current agent identity. A
5527
- recording ID survives pause/resume and reallocation only where the same recorder confirms continuity;
5528
- commands always name the current allocation. A later start gets a different ID. Reconnect does not
5535
+ recording ID survives pause/resume and reassignment only where the same recorder confirms continuity;
5536
+ commands always name the current assignment. A later start gets a different ID. Reconnect does not
5529
5537
  create a new recording or fresh evidence. After lost continuity, use unknown until reconciled.
5530
5538
  There is no automatic restart, transfer to another recorder, or stop on task hold/disconnect.
5531
- Task removal does not prove recording stopped: outstanding host recorders remain tracked by the
5532
- host until its executor reconciles/finishes them, with visible unresolved cleanup failures.
5539
+ Task removal does not prove recording stopped: outstanding agent application recorders remain tracked by the
5540
+ agent application until its executor reconciles/finishes them, with visible unresolved cleanup failures.
5533
5541
 
5534
5542
  Only start/resume require an in-progress or paused task with started media. Pause/stop/cancel may
5535
5543
  also finish an independently observed recorder while the task is completing. A pending task may
@@ -5544,40 +5552,40 @@ Receipt, replay and task publication never extend freshness. Clock discontinuity
5544
5552
  consumers using the explicit recording-expiry clock-estimation exception must invalidate that
5545
5553
  estimate and use monotonic aging so clock rollback cannot
5546
5554
  revive expired evidence. The executor compares observation identity and recording identity against
5547
- its latest state atomically before I/O. An intervening observation or allocation change refuses the
5555
+ its latest state atomically before I/O. An intervening observation or assignment change refuses the
5548
5556
  stale command; it never acts on a replacement recorder. Providers lacking trustworthy current-state
5549
5557
  identity or observation time publish unknown and offer no issuable controls.
5550
5558
 
5551
5559
  Use `validateTask` and `validateTaskCommand` for published shape and static permissions.
5552
5560
  Immediately before dispatch, additionally use `validateRecordingRequest` against the full current
5553
- task and explicit observer-domain time. For host commands also supply the current host declaration,
5554
- full host report and softphone context. The same checks must run at the executing boundary;
5561
+ task and explicit observer-domain time. For agent application commands also supply the current agent application declaration,
5562
+ full agent application report and softphone context. The same checks must run at the executing boundary;
5555
5563
  client validation alone is not authorization. The executor serializes operations on each recorder
5556
5564
  and durably correlates request identity with scope, action and outcome: an exact retry refers to the
5557
5565
  same operation; reuse with different contents is refused. It never silently retries an ambiguous
5558
5566
  operation. Implementations without reliable request correlation must refuse controls.
5559
5567
 
5560
- Keep command progress in host UI separately from authoritative state. Applied means the requested
5561
- recording transition and any retain/discard effect actually completed; publish the confirming task or host report before
5568
+ Keep command progress in agent application UI separately from authoritative state. Applied means the requested
5569
+ recording transition and any retain/discard effect actually completed; publish the confirming task or agent application report before
5562
5570
  resolving applied. Failed means confirmed no effect. Rejected promise means outcome unknown:
5563
5571
  show the failure, reconcile that path and do not automatically retry or pretend inactive. Authoritative
5564
- updates remain full current task/host views, not replayed provider events. These current-state fields
5572
+ updates remain full current task/agent application views, not replayed provider events. These current-state fields
5565
5573
  create no interaction-history entries and infer no actors, durations or historical capture boundaries.
5566
5574
 
5567
5575
  Migration is explicit: replace the old true recording capability with per-path action policies,
5568
5576
  replace untargeted commands with scoped commands, and retain protocol version 1. During pre-release
5569
5577
  development, hosts and adapters must align their recording contracts; negotiation does not detect
5570
5578
  differences between package revisions that share that protocol number. No legacy-shape fallback is provided.
5571
- This change does not publish a package or enable recording in any existing host/provider by itself.
5579
+ This change does not publish a package or enable recording in any existing agent application/provider by itself.
5572
5580
 
5573
5581
  `validateRecordingOutcome` checks confirming observations against recording-specific applied/failed
5574
5582
  semantics, including pause/resume identity and rejection of a dialling result. It cannot prove audio
5575
5583
  retention/completion or source truth from a status flag; those remain executor obligations.
5576
5584
 
5577
- Host destination selection binds storage when start actually creates a recording. Existing recordings
5585
+ Agent application destination selection binds storage when start actually creates a recording. Existing recordings
5578
5586
  keep that binding through pause/resume/stop/cancel; a later policy cannot redirect their stored audio.
5579
5587
  The executor rejects a mismatched destination rather than moving or discarding another binding.
5580
- Action permission does not authorize unattended invocation: host controls require the agent's explicit
5588
+ Action permission does not authorize unattended invocation: agent application controls require the agent's explicit
5581
5589
  act, and provider authorization remains enforced at its authenticated command boundary.
5582
5590
 
5583
5591
 
@@ -5589,31 +5597,31 @@ capability restrictions from disappearing at dispatch. The standalone `validateR
5589
5597
  requires an affirmative permission; false, malformed permission declarations and unknown actions grant nothing.
5590
5598
 
5591
5599
 
5592
- ### Host recording announcements to the caller
5600
+ ### Agent application recording announcements to the caller
5593
5601
 
5594
- `HostRecording.announcesToCaller`, when true, is a guarantee that the host delivers audible recording
5602
+ `HostRecording.announcesToCaller`, when true, is a guarantee that the agent application delivers audible recording
5595
5603
  status messages to the remote party over the call's outgoing audio. It belongs inside the optional
5596
- host recording capability: without that capability there is no such guarantee. Omission makes no
5604
+ agent application recording capability: without that capability there is no such guarantee. Omission makes no
5597
5605
  promise; false is invalid. It does not belong in the provider manifest, the task's recording policy
5598
- or the general `HostGuarantees` object. A provider can inspect this host guarantee when deciding
5599
- whether to permit host recording on a task.
5606
+ or the general `HostGuarantees` object. A provider can inspect this agent application guarantee when deciding
5607
+ whether to permit agent application recording on a task.
5600
5608
 
5601
- The guarantee applies only to host-owned recordings. Providers implement announcements for their
5602
- own recordings at their end; provider state updates must not cause the host to announce those
5609
+ The guarantee applies only to agent application-owned recordings. Providers implement announcements for their
5610
+ own recordings at their end; provider state updates must not cause the agent application to announce those
5603
5611
  recordings. Both recorders can operate independently on the same call.
5604
5612
 
5605
- On a confirmed host start, the remote party hears that recording started. On a confirmed stop or
5613
+ On a confirmed agent application start, the remote party hears that recording started. On a confirmed stop or
5606
5614
  cancel, they hear that recording stopped. If pause/resume is supported, say paused/resumed so a
5607
5615
  pause is not presented as a finished recording. Announcements follow actual capture transitions,
5608
5616
  not button clicks, accepted requests or task-policy changes. When attaching to an already-active
5609
- host recording, announce that recording is active, without inventing its original start time.
5617
+ agent application recording, announce that recording is active, without inventing its original start time.
5610
5618
  Repeated observations of the same state do not repeat announcements. Unknown or expired evidence
5611
5619
  must never produce a stopped announcement.
5612
5620
 
5613
5621
  A local sound, UI indicator, screen-reader message to the agent, or sound leaking through the
5614
- microphone does not fulfil this guarantee. The host must deliver the message directly in the audio
5622
+ microphone does not fulfil this guarantee. The agent application must deliver the message directly in the audio
5615
5623
  sent to the remote party, even when the agent microphone is muted. It may also notify the agent.
5616
- Only declare the guarantee when the host can provide that outgoing audio path. An announcement
5624
+ Only declare the guarantee when the agent application can provide that outgoing audio path. An announcement
5617
5625
  that cannot be delivered, including after the remote party has disconnected, is a visible failure;
5618
5626
  never claim delivery or replay the notice into a different call.
5619
5627
 
@@ -5623,4 +5631,4 @@ report the announcement failure visibly and reject with unknown command outcome.
5623
5631
  effect, automatically repeat the recording action or silently switch to an agent-only notice.
5624
5632
 
5625
5633
  `validateHostRecording` checks the declaration, including its true-or-absent guarantee. Actual audio
5626
- delivery remains the host implementation's responsibility and must be exercised in its own tests.
5634
+ delivery remains the agent application implementation's responsibility and must be exercised in its own tests.