Skip to content

fix(web): date a registry slice from when it was asked for - #765

Merged
efiten merged 2 commits into
masterfrom
fix/registry-slice-asked-at
Oct 31, 2026
Merged

efiten merged 2 commits into
masterfrom
fix/registry-slice-asked-at

Conversation

@efiten

@efiten efiten commented Oct 31, 2026 •

Copy link
Copy Markdown
Owner

Closes #764

What changes

createRowAttributor (web/rowattribution.js):

  • A slice gets at: askedAt, the moment it was asked for, instead of now() after the answer. A slow answer then ages from the question.
  • An answer whose askedAt is older than the current slice does not replace it. That call still attributes its own rows with its own answer, since the newer slice need not cover them (second commit, after review).

Why

The flaky CI test relaynames.spec.js:107 (on PR #762) comes down to this:

  • At boot the ticker renders before the role is known.
  • applyRole resets the attributors and refetches (web/map.js:610, :679).
  • If that registry answer only lands after the test jumps the clock 66 s, the empty slice is stamped after the jump and counts as fresh for another minute.

Tests

  • Three unit tests in rowattribution.test.js:
    • a slow answer that lands after the TTL is stale on the next ask;
    • a late older answer does not replace a newer slice;
    • a late older answer still attributes its own rows outside the newer slice.
      All three failed without the fix (called 1 times / rule: estimate).
  • A deterministic e2e probe that holds every empty registry answer until after the clock jump: without the fix 1 of 3 runs failed, with the fix 12 of 12 passed. I did not add the probe as a permanent test; the unit tests cover the rule.
  • vitest 873/873, eslint clean, relaynames.spec.js 7/7.
  • Full Playwright locally: 336 passed, 1 failed (zoomfade.spec.js:90). That test does not touch the registry, and it also failed once in a full run on the branch of fix(web): keep the bar's labels on one line at tablet widths #759 while passing 8 of 8 alone.

Not done

  • Left out of scope (pre-existing, from the review): an answer asked before reset() that lands after it can still fill the slice, and a late failed answer sets failedAt without comparing askedAt.
  • The original flake rate is low: 2 of 40 locally, then 0 of 120. A rate measurement before and after therefore proves little; the probe is the evidence.
  • No changelog entry. The effect for a reader (names up to a minute late after a slow registry answer) occurs rarely and is not a feature.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TDXX3ZV8LEdZgVTNFYFvZi

efiten and others added 2 commits October 31, 2026 11:58
The slice was stamped with now() after the answer landed, so a slow
answer counted as fresh for a minute from then and kept names off the
rows. An older answer that lands after a newer slice no longer replaces
it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TDXX3ZV8LEdZgVTNFYFvZi
When an older answer lost to a newer slice, the call returned the newer
slice's index, which need not cover its rows: a row the registry named
read as unnamed. The call now uses its own answer; only the stored slice
follows the newer question.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TDXX3ZV8LEdZgVTNFYFvZi
@efiten
efiten merged commit 77badec into master Oct 31, 2026
7 checks passed
@github-actions github-actions Bot mentioned this pull request Oct 31, 2026
efiten added a commit that referenced this pull request Oct 31, 2026
…ilure, no longer moves the attributor (#769)

Closes #768

## What changes
`createRowAttributor` (`web/rowattribution.js`):
- `reset()` (a change of role, `web/map.js:610`) bumps a `generation`.
An answer asked for under an earlier generation writes neither the slice
nor `failedAt`, and its own rows read without a registry (`rule:
estimate`). A member's answer that lands after a logout therefore names
nothing for the guest.
- A failed answer only sets `failedAt` when no newer slice exists
(`!slice || slice.at <= askedAt`), the rule #765 applies to a success.

## Tests
- Three unit tests in `rowattribution.test.js`:
- `drops an answer that was asked for before a reset`: the rows read
`estimate` and the next call asks again;
- `does not let an older failure that lands late hold back asks a newer
answer allows`: 3 asks, not 2;
- `does not let a failure asked for before a reset hold back the first
ask after it` (added after review): fails when the generation check is
moved below the failure branch.
The first two fail without the change; the third guards the order of the
two checks.
- vitest 876/876, eslint clean, `relaynames.spec.js` + `auth.spec.js`
26/26.
- Full Playwright locally: 336 passed, 1 failed:
`targetpicker.spec.js:216`. It also fails 1 of 8 runs with master's
`rowattribution.js`, and passes 8 of 8 with this one, so it is not from
this change.

## Not done
- No changelog entry: a reader sees no difference outside these races.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01TDXX3ZV8LEdZgVTNFYFvZi

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
efiten pushed a commit that referenced this pull request Oct 31, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>app: 1.32.1</summary>

##
[1.32.1](app-v1.32.0...app-v1.32.1)
(2026-10-31)


### Bug Fixes

* **web:** a callout with its control in the menu sends the tour copy
into the panel
([#760](#760))
([8592da6](8592da6))
* **web:** keep the bar's labels on one line at tablet widths
([#759](#759))
([f27390c](f27390c))
</details>

<details><summary>server: 1.11.1</summary>

##
[1.11.1](server-v1.11.0...server-v1.11.1)
(2026-10-31)


### Performance Improvements

* **server,web:** one point query per hex refresh for both cell sizes
([#755](#755))
([78868fc](78868fc))
</details>

<details><summary>web: 1.28.1</summary>

##
[1.28.1](web-v1.28.0...web-v1.28.1)
(2026-10-31)


### Bug Fixes

* **web:** a callout with its control in the menu sends the tour copy
into the panel
([#760](#760))
([8592da6](8592da6))
* **web:** a registry answer from before a role change, or an older
failure, no longer moves the attributor
([#769](#769))
([087377d](087377d))
* **web:** date a registry slice from when it was asked for
([#765](#765))
([77badec](77badec))
* **web:** keep the bar's labels on one line at tablet widths
([#759](#759))
([f27390c](f27390c))


### Performance Improvements

* **server,web:** one point query per hex refresh for both cell sizes
([#755](#755))
([78868fc](78868fc))


### Code Refactoring

* **web:** drop the name-redraw hold, MapLibre never closes a popup on
redraw ([#770](#770))
([ba9a9b0](ba9a9b0))


### Tests

* **web:** release the mocked resolver when the popup is open, not after
600 ms ([#762](#762))
([2abc959](2abc959))
* **web:** retry the zoomfade hover until a painted cell answers
([#767](#767))
([9331dfa](9331dfa))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

web: a registry slice is dated from its answer, so a slow answer keeps names off the rows for a minute

1 participant