diff --git a/CHANGELOG.md b/CHANGELOG.md index df7abb6..ee32ca2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ All notable changes to this project are recorded here. The format follows Keep a ### Documentation - README: turning on analytics in every flow a contact can pass through is now a deployment step (section 3, step 2), not just a prerequisite. The stock transfer-to-queue flow has no analytics block, so without it the leg after an agent transfer is never analysed. Added a check that a test transfer produces two analysis files, and a troubleshooting entry for "I can see the bot's turns but not the human agent's". +### Changed +- Spec v0.3: `escalation_to_human` events are now documented as requiring a + valid ISO 8601 `ts`, matching the mock receiver. Unlike the other v0.3 + corrections this is a tightening — a payload omitting that timestamp was + valid before and is not now. The Connect forwarder has always sent it, and + there are no external senders yet, so nothing in flight is affected. +- Mock receiver: `escalation_to_human` events now require a valid ISO `ts`, + which the bot/human turn-split fallback depends on. + ### Fixed - Spec v0.3: removed HTTP Basic auth and the `429` response from the documented contract. Neither is implemented by any ciopulse endpoint; the forwarder has @@ -16,8 +25,6 @@ All notable changes to this project are recorded here. The format follows Keep a "0.2" or later, not exactly "0.2". - Mock receiver: no longer accepts HTTP Basic, so it can no longer certify a payload the real endpoint would reject. -- Mock receiver: `escalation_to_human` events now require a valid ISO `ts`, - which the bot/human turn-split fallback depends on. - README: the contract reference no longer lists a `429` response, matching the spec. ## [0.2.0] - 2026-09-18 diff --git a/docs/send-a-copy-spec-v0.3.md b/docs/send-a-copy-spec-v0.3.md index 2cb170b..d8f8d19 100644 --- a/docs/send-a-copy-spec-v0.3.md +++ b/docs/send-a-copy-spec-v0.3.md @@ -5,6 +5,7 @@ **Status:** Decided · 18 Sep 2026 · Contact: ciopulse **Changes from v0.2:** two optional fields, both decided 18 Sep 2026. `turns[].actor` says whether an `agent` turn came from a bot or a person. `conversation_id` joins the sessions of one conversation that a platform split across a transfer, and is the value the survey `tid` carries. Every valid v0.2 payload is a valid v0.3 payload; receivers accept 0.2 and 0.3 side by side for the life of v0.x. **Corrections, 21 Sep 2026:** removed HTTP Basic and the `429` response, neither of which any ciopulse endpoint implements; clarified that voice requires `"0.2"` or later. Documentation only — no payload valid under v0.3 becomes invalid. +**Correction, 23 Sep 2026:** documented the ISO `ts` requirement on `escalation_to_human`, which the reference implementation enforces. This is a tightening: a payload that omitted that timestamp was accepted before 22 Sep and is rejected now. **Changes from v0.1 (v0.2):** `channel` accepts `"voice"`; optional `platform_signals` block. --- @@ -29,10 +30,10 @@ Content-Type: application/json | `agent.version` | ✔ | Release/version string (scorecards are per-version) | | `started_at`, `ended_at` | ✔ | ISO 8601 with timezone | | `turns[]` | ✔ | Ordered, chronological. Each: `role` (`"user"` \| `"agent"` \| `"system"`), `text`, `ts` (ISO 8601 with timezone), and optionally `actor` (below) | -| `turns[].actor` | – | **New in v0.3.** `"bot"` when the turn was produced by an automated agent, `"human"` when by a person; omit when unknown. Only meaningful when `role` is `"agent"`. Receivers that need the split and find it absent treat turns before the first `escalation_to_human` event as bot and later ones as human | +| `turns[].actor` | – | **New in v0.3.** `"bot"` when the turn was produced by an automated agent, `"human"` when by a person; omit when unknown. Only meaningful when `role` is `"agent"`. Receivers that need the split and find it absent treat turns before the first `escalation_to_human` event as bot and later ones as human. Because that fallback has no other anchor, an `escalation_to_human` event without a valid ISO 8601 `ts` is rejected with a field-level `400`. | | `channel` | – | `"chat"` (default) or **`"voice"`** (new in v0.2). Voice means the turns are text produced by speech-to-text; ciopulse reads them exactly as chat. Voice requires `contract_version` `"0.2"` or later. Audio is never sent | | `outcome` | – | Your call: `"contained"` \| `"escalated"` \| `"abandoned"` \| `"unknown"` | -| `events[]` | – | e.g. `{"type": "escalation_to_human", "ts": "…"}` | +| `events[]` | – | e.g. `{"type": "escalation_to_human", "ts": "…"}`. An `escalation_to_human` event **requires** a valid ISO 8601 `ts` with timezone — the bot/human turn split falls back to it when `turns[].actor` is absent. Other event types need only `type`; any `ts` present must be ISO 8601 with timezone. | | `platform_signals` | – | **New in v0.2.** Measurements your platform already computed about this conversation. See below. Omit the block entirely if you have none | | `metadata` | – | Free-form object, ≤ 2 KB (queue name, deployment context, …) | | `exclude` | – | `true` = ciopulse must not store or analyse this conversation. It is counted and discarded. A sender MAY send a single placeholder turn (`role: "system"`, `text: "excluded by sender"`) instead of the transcript when `exclude` is `true`; receivers never analyse that text |