Task: Give every frame an identity, so a client can resume
Table of Contents
This page documents a task in the Stream the changes as they happen story. It captures the goal, current status, acceptance, and any notes or results.
1. Goal
(Describe what user-visible-or-internal change this task produces.)
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Stream the changes as they happen |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-11-01 |
3. Acceptance
4. Plan
- The hub stamps the id, not the pump: it is the only place that sees every frame in one order, and the only place that can remember what it published.
- The hub keeps the last 64 frames it published with their tenant attached, so a replay cannot cross tenants. A reconnecting client inside that window is given the frames it missed, in order, before it hears anything live.
- Outside the window, or naming an id this process never issued, the client is
sent one
event: resyncframe. Core NATS has no replay, so a silent gap would be indistinguishable from a quiet market, and the client would keep a stale screen forever. - The route reads
Last-Event-ID, and a value that is not a number is logged and treated as a fresh stream rather than refused: a corrupt header must not cost the caller its stream. - The subscribe call takes the resume point under the hub's lock, so no frame is published between replay and live delivery and the client cannot miss one at the seam.
5. Measurements
Every number this task claims about a tree, with the command that produced it
and the commit it was measured at. A number without both is not a measurement,
because a clean-up record describes a tree and trunk moves under a branch: a
consumer count, a gate's component count and a suite's size all change with no
code changing, and the reader of a bare number cannot tell which tree it came
from. Where the raw output matters, put it in an evidence/ file beside the
task and name that file in the Command column.
| What | Value | Command | Commit |
|---|---|---|---|
6. Notes
7. Test Scenarios
Manual QA scenarios (scaffolded via compass add test_scenario)
that verify this task. Link
new ones here as they're created; the scenario doc itself links back
via its "Verifies task" field.
| Scenario | State | Notes |
|---|---|---|
8. PRs
| PR | Title |
|---|---|
| #4460 | [http] Complete the change stream: identity, party, conflation |
9. Review
| Comment summary | File | Decision | Notes |
|---|---|---|---|
10. Measurements
| What | Value | Command | Commit |
|---|---|---|---|
| Core suite cases | 52 | ores.http.core.tests |
this branch |
| Core suite assertions | 206 | ores.http.core.tests |
this branch |
| IAM suite assertions | 290 | ores.http.iam.tests |
this branch |
11. Result
A frame now carries id: <n>, numbered by the hub, so a client can say which
frame it last saw. The hub keeps the last 64 frames with their tenant, and a
reconnecting client that names an id inside that window is given the frames it
missed, in order and filtered by tenancy, before it hears anything live. A
client whose id is outside the window, or names one this process never issued,
is sent one event: resync frame: core NATS has no replay, and a silent gap
would look exactly like a quiet market.
The route honours Last-Event-ID, and a header that is not a number is logged
and treated as a fresh stream rather than refused.
Four cases prove it: ids ascend, a resuming client gets what it missed, a replay cannot cross tenants, and an unknown id is answered with a resync. The two cases that asserted raw frame text now assert the stamped form.