Skip to content

fix(instrument): a late chain read must not steal the controls - #34

Merged
edycutjong merged 3 commits into
mainfrom
fix/instrument-mode
Sep 9, 2026
Merged

edycutjong merged 3 commits into
mainfrom
fix/instrument-mode

Conversation

@edycutjong

Copy link
Copy Markdown
Owner

What broke

main was green at 16:08Z. The demo subscription was re-termed and restarted at 16:15Z. The next CI run — on fix/reserve-estimate, a branch that touches no UI code — went red at 16:20Z:

[chromium] › e2e/landing.spec.ts:37 › labels the recorded run as recorded…
Error: locator.click: Test timeout of 30000ms exceeded.
  - waiting for getByTestId('instrument').getByRole('button', { name: 'Step' })
  - element is not stable

Reproduced locally against the live deployment, so it is not CI flake.

Why

app/page.tsx reads the demo agent's window once on arrival, unprompted, and Instrument.tsx switched to the live chain whenever that read came back valid. The read lands a few hundred milliseconds after paint, and it won unconditionally — including against a visitor who had already started working the replay. The controls unmount under a click already in flight.

It was invisible for as long as the demo agent was lapsed: the read answered "closed" and changed nothing. Restarting the demo turned it into a broken hero, five days before judging.

The fix

  • The arrival read is distinguished from a request. Anything the visitor asks for — the tab, an address, the demo-agent button, a connected wallet — still switches to live. An unasked-for read stops at the first control they touch.
  • e2e/landing.spec.ts promised in its own docstring that "nothing here depends on the chain answering", and three tests quietly did. The arrival read is stubbed now, both ways round. Two tests added: the instrument opens live when the window is open and nobody has touched it, and a late read never pulls the mode away from a visitor already working the replay.

Also in here: four claims that drifted when the demo was re-termed

  • README / JUDGE / docs/proof.md described 90-second periods in the present tense; the live endpoint the README hands judges answers periodSeconds: 3600. Each now dates the old setting and names the endpoint as the live answer.
  • RUNBOOK.md said to expect 40 contract tests. There are 64.
  • DEMO.md called n=30 "all the renewals this deployment has ever armed" — true of the dated run, not of today.
  • The social card said 39 unattended renewals; the mirror node says 46 across the three deployments and it climbs hourly. Card, alt text and generators now read 46+, a floor that cannot go stale, and ?v= is bumped because platforms cache the card by URL. The og:description drops the count entirely.

Local: 258 unit tests pass, 62 E2E pass (2 skipped), lint clean.

The page reads the demo agent's window once on arrival, unprompted, and switches the
instrument to the live chain if it is open — the real thing beating a replay. That read
lands a few hundred milliseconds after paint, and it used to win unconditionally, so it
also won against a visitor who had already started working the replay: the controls
unmounted under a click already in flight.

It was invisible for as long as the demo agent was lapsed, because the read answered
"closed" and changed nothing. Restarting the demo made it a broken hero, and the E2E suite
found it on a branch that touches no UI code at all — green at 16:08Z, red at 16:20Z, the
restart in between.

So the arrival read is now distinguished from a request. Anything the visitor asks for —
the tab, an address, the demo-agent button, a connected wallet — still switches. An
unasked-for read stops at the first control they touch.
This file's own docstring promised "nothing here depends on the chain answering", and three
tests quietly did: they assumed a cold visitor lands on the recorded run, which is only true
while the demo agent's window is closed. That assumption is what turned green red with no
code change between the runs.

The arrival read is stubbed now, both ways round, so the suite decides what the chain says.
Two tests are added: the instrument opens live when the window is open and nobody has
touched it, and — the regression itself — a late read never pulls the mode away from a
visitor already working the replay.
Re-terming the demo to hourly periods left four claims behind that a judge can falsify with
the one curl the README itself hands them:

- README, JUDGE and docs/proof all described 90-second periods in the present tense. The
  live status endpoint answers `periodSeconds: 3600`. Each now dates the old setting and
  names the endpoint as the live answer, and the README paragraph says the thing that does
  not age: the gas reserve is the clock, and the period length turns it into a duration.
- RUNBOOK told you to expect 40 contract tests. There are 64, as README and JUDGE both
  already said.
- DEMO.md called n=30 "all the renewals this deployment has ever armed". It was, on the run
  it is dated with; the deployment has kept renewing since, so the sentence now says so.

The social card said 39 unattended renewals. The mirror node says 46 executions across the
three deployments, and it climbs every hour — so the card, the og:image alt and the
generators now read 46+, a floor that cannot go stale, and the card's ?v= is bumped because
platforms cache it by URL. The og:description drops the count entirely.
@vercel

vercel Bot commented Sep 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
build Ready Ready Preview Sep 9, 2026 5:07pm UTC

@edycutjong
edycutjong merged commit 000171e into main Sep 9, 2026
9 of 10 checks passed
@edycutjong
edycutjong deleted the fix/instrument-mode branch September 9, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant