joule-moq-web: a turn a later schedule replaces ends at that schedule's from #620

Merged
dcharlot merged 1 commit from wai/co-floor-schedule-change into main 2026-11-04 18:26:10 -05:00
Owner

What failed

On #619's browser run, the room e2e's co-performance scenario failed with
the room with the clock's log verifies (co-performance §9): accept — turn_violated at ["object",2380].
The three checks after it failed as a result. #619 changes only a version line in this
workspace's joule-moq-room/Cargo.lock, and the same job passed on main three times that day.

Why

The room page took a turn's end from its own schedule only, so the turn ended at its segment's
boundary. The scenario's refusing schedule takes effect in the middle of the marking schedule's
sixth turn, and the page of the performer holding that turn went on sending up to the new
schedule's from, past the guard of §8.

  • The relay: it judged each of those last objects on arrival, under the marking schedule it
    reached the relay in, and forwarded it.
  • The room's clock: a hop later, it logged the same object after the from, under the
    refusing schedule, which gives that turn to the other holder.
  • The verifier: the clock's log then shows a forwarded object out of turn under refuse,
    turn_violated.

The window is the hop between the relay and the clock. It is small on a quiet host and grows
under load, and the build host was under heavy load during that run.

§6.1 already says a later schedule replaces an earlier one from its from on. The page did not
apply that to the end of a turn.

The change

  • web/room/co.js: a turn ends at its segment's boundary, or at the from of a later
    schedule if that comes first.
    • A performer's guard therefore keeps its media before either.
    • The turns ahead step from the cut turn to the new schedule's first turn. Before, they jumped
      to the old turn's end, skipping the new schedule's turns up to it.
  • web/room/co.test.mjs (new): six cases, run by e2e/run.sh with the page's other module
    tests. Against the old co.js, three of them fail: the turn's end, the guard before the
    from, and the turns ahead.
  • e2e/room.e2e.mjs: a refusal at an object now names the object, its arrival, and how far
    it is from the nearest turn boundary or schedule from, so a future failure says which race it
    was. Nothing else in the scenario changes.

Not changed

  • The spec: its text already gives this.
  • The relay and the room service: they judge each object by its arrival, as the spec says.
  • The schedule lead (lead_ms, 300 ms by default): a page that learns a schedule more than
    150 ms after it is signed still sends past the guard until it learns it. That is the margin the
    spec leaves to the room's configuration, and this change does not alter it.

Checks

  • node --test web/room/co.test.mjs: 6 of 6 pass. Against the old co.js, 3 fail.
  • node --check on both edited scripts.
  • The name checks: the repository script, plus the message and the diff against the denylist.

🤖 Generated with Claude Code

## What failed On #619's browser run, the room e2e's co-performance scenario failed with `the room with the clock's log verifies (co-performance §9): accept — turn_violated at ["object",2380]`. The three checks after it failed as a result. #619 changes only a version line in this workspace's `joule-moq-room/Cargo.lock`, and the same job passed on main three times that day. ## Why The room page took a turn's end from its own schedule only, so the turn ended at its segment's boundary. The scenario's refusing schedule takes effect in the middle of the marking schedule's sixth turn, and the page of the performer holding that turn went on sending up to the new schedule's `from`, past the guard of §8. - **The relay:** it judged each of those last objects on arrival, under the marking schedule it reached the relay in, and forwarded it. - **The room's clock:** a hop later, it logged the same object after the `from`, under the refusing schedule, which gives that turn to the other holder. - **The verifier:** the clock's log then shows a forwarded object out of turn under refuse, `turn_violated`. The window is the hop between the relay and the clock. It is small on a quiet host and grows under load, and the build host was under heavy load during that run. §6.1 already says a later schedule replaces an earlier one from its `from` on. The page did not apply that to the end of a turn. ## The change - **`web/room/co.js`:** a turn ends at its segment's boundary, or at the `from` of a later schedule if that comes first. - A performer's guard therefore keeps its media before either. - The turns ahead step from the cut turn to the new schedule's first turn. Before, they jumped to the old turn's end, skipping the new schedule's turns up to it. - **`web/room/co.test.mjs` (new):** six cases, run by `e2e/run.sh` with the page's other module tests. Against the old `co.js`, three of them fail: the turn's end, the guard before the `from`, and the turns ahead. - **`e2e/room.e2e.mjs`:** a refusal at an object now names the object, its arrival, and how far it is from the nearest turn boundary or schedule `from`, so a future failure says which race it was. Nothing else in the scenario changes. ## Not changed - **The spec:** its text already gives this. - **The relay and the room service:** they judge each object by its arrival, as the spec says. - **The schedule lead (`lead_ms`, 300 ms by default):** a page that learns a schedule more than 150 ms after it is signed still sends past the guard until it learns it. That is the margin the spec leaves to the room's configuration, and this change does not alter it. ## Checks - `node --test web/room/co.test.mjs`: 6 of 6 pass. Against the old `co.js`, 3 fail. - `node --check` on both edited scripts. - The name checks: the repository script, plus the message and the diff against the denylist. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
joule-moq-web: a turn a later schedule replaces ends at that schedule's from, and a performer's page keeps its guard before it
All checks were successful
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (pull_request) Successful in 32s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 5s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 6s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 5s
WAI Studio / does this change touch it (pull_request) Successful in 5s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 31s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Successful in 54s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 2m21s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 8m19s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 9m24s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 8m56s
WAI Studio / Studio in WebKit · linux (pull_request) Successful in 11m5s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 9m35s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m43s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 11m30s
joule-code conformance gate / joule-moq-relay, every target (pull_request) Successful in 3m40s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 19m26s
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 6m1s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 6m30s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 7m27s
29b982fbe2
The room page took a turn's end from its own schedule only. When a lead's new schedule took effect
in the middle of a turn, the page of the performer holding it went on sending up to the new
schedule's `from`, past its guard (co-performance §8). The relay judged its last objects on
arrival, under the schedule they reached it in, and forwarded them. The room's clock, a hop
later, logged them after the `from`, under the new schedule. Where the new schedule refuses and
gives that turn to someone else, the room with the clock's log then refuses as `turn_violated`.

How often depends on that hop: rarely on a quiet host, and once in #619's browser run, on the
shared build host under load (the room e2e's refusing schedule takes effect in the middle of the
marking schedule's sixth turn, which the other holder held).

Now:
- A turn ends at its segment's boundary, or at the `from` of a later schedule, if that comes
  first (§6.1: "A later schedule replaces an earlier one from its `from` on").
- The guard applies before either.
- The turns ahead step from the cut turn to the new schedule's first turn. Before, they jumped
  to the old turn's end and skipped the new schedule's turns up to it.

Tests:
- `web/room/co.test.mjs` (new, run by `e2e/run.sh` with the page's other module tests): six
  cases. Against the old `co.js`, three of them fail: the turn's end, the guard before the
  `from`, and the turns ahead.
- The room e2e names an object it refuses: its arrival, and how far it is from the nearest turn
  boundary or schedule `from`. If the check fails again, it says which race it was.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!620
No description provided.