Skip to content

adopt(memos): ready to send: stale pin, tasks and reactions after two quick changes to a memo - #161

Open
MeharPro wants to merge 12 commits into
mainfrom
claude/relaxed-babbage-w6cey1
Open

MeharPro wants to merge 12 commits into
mainfrom
claude/relaxed-babbage-w6cey1

Conversation

@MeharPro

@MeharPro MeharPro commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Status: ready to send (after the by-hand items in docs/adoption/hunts/memos-issue.md, "Before sending").

What was found

genclass_explore found two races of one kind in Memos' web app (usememos/memos main@b40d8a7b5). In each, an older reply is written over newer client state and stays there.

  1. useUpdateMemo: Pin then Unpin, or "Check all tasks" then "Uncheck all tasks", on the memo's detail page. The page can end showing the first change while the server holds the second.
  2. useReactionActions: 👍 then ❤️. The 👍 click's raw getMemo reply can land last and remove ❤️.

Both reproduce without GenClass (plain Playwright, one reply held 1.5 s): 10 of 10 trials each, still stale 30 s later, 0 of 3 without the hold. A two-commit patch (13 source lines plus 3 Vitest tests that fail on main and pass fixed) brings that to 0 of 10 each. On the fixed build, explore's oracle shows 0 of 54 stale reordered loads, against 7 of 54 unfixed.

Files

  • docs/adoption/hunts/memos.md: the report (setup, every scenario with its verdict, the findings in causal order, root cause with lines, fix, tests, fixed variant, problems with GenClass, duplicates and policy, time).
  • docs/adoption/hunts/memos.patch: git format-patch of the two commits against b40d8a7b5. Checked with git am on a fresh clone; it applies cleanly.
  • docs/adoption/hunts/memos-issue.md: the issue in Memos' bug_report.yml fields, the PR body (Memos has no template), the AI-assistance paragraph, and the "before sending" checklist.
  • docs/adoption/hunts/memos/:
    • setup.mjs: seeds the local instance.
    • explore.mjs: the harness, GenClass injected from outside, with a DOM-vs-server oracle; GENCLASS=0 runs it without GenClass.
    • repro.mjs: reproduces both races without GenClass.
    • summarise.mjs: builds the results tables.
    • results/: the explore summaries (unfixed, fixed), three full explore reports, and the reproduction JSONs.
  • docs/adoption/hunts/README.md: the new row.

To send (a person, from a personal account)

  1. Search usememos/memos issues and PRs again for duplicates since 2026-11-03 (words in the checklist; none found today).
  2. Run Memos locally (Node 24, pnpm 11.0.1, go run ./cmd/memos --port 8081, pnpm dev). Reproduce pin and reactions by hand or with repro.mjs, and put the commit you used in the issue's version field.
  3. Open the issue with the text in memos-issue.md (bug template; the duplicate-search checkbox is ticked).
  4. Fork, git am memos.patch, re-author the commits, run cd web && pnpm lint && pnpm test, and see the three new tests fail with the source files stashed. Push and open the PR with the drafted body, filling in Fixes #<issue>.
  5. If asked, explain how it was found: GenClass replays the same steps with the server's replies delivered in other orders. Its own role is the last sentence of the disclosure paragraph. Do not argue if the maintainers prefer another fix, for example only skipping superseded replies without the mutation scope.

Measured (M, latencies)

Explore uses 2 request-order baselines plus 6 seeded orders per session, at slow_ms 300, 600 and 900. The oracle compares what the page shows with GetMemo after whenSettled and 2.5 s more.

Unfixed, oracle counts of reordered loads where the page disagreed with the server (0 of 2 baselines in every session):

scenario 300 ms 600 ms 900 ms
pin 0 of 6 (2 of 6 in a first session) 2 of 6 3 of 6
tasks 0 of 6 0 of 6 1 of 6 (GenClass RACE, true)
reaction 1 of 6 (GenClass RACE, true) 0 of 6 0 of 6
comment 0 of 6 0 of 6 0 of 6
archive timing-dependent, not usable 3 of 4 ended on /archived with the memo restored 4 of 6, the same

Fixed:

  • Pin, tasks, reaction: 0 of 6 at every latency.
  • Archive: 0 of 5 at 600 ms. At 900 ms, 1 of 6, a load where the Restore click landed on the Archived page because the first reply arrived before the second click; not a crossing.

Without GenClass, one reply held 1.5 s:

pin reaction
unfixed 10 of 10, 10 of 10 after 30 s 10 of 10, 10 of 10 after 30 s
unfixed, nothing held 0 of 3 0 of 3
fixed 0 of 10 0 of 10

GenClass's false reports (FIR on the correct runs): of the 12 complete unfixed sessions outside archive, 5 ended with a false RACE resting only on request counts (pin 600, reaction 600, comment 300/600/900). On the fixed build, 3 of 12 did (reaction 600, archive 600 and 900). In none of those runs did the page differ from the server.

Problems with GenClass itself (report section 6)

  1. Connect RPC sends reads as POST. Explore counts a different number of GetMemo, ListMemoComments, GetUserStats and ListMemos POSTs as different writes, which caused every false RACE verdict above.
  2. A state shown only as an icon is missed. The pinned mark is role="img" with an aria-label and no text, so the stale pin landed in "internal state only" (the witnesses did name it).
  3. Base UI internals crowd genclass_findings. Its menu and popover state shows up as stale-write findings next to the real ones.
  4. Same steps on another page are grouped together. When the first reply had navigated away, the second click happened on another page, but the run was still compared with the others.
  5. A queued update is labelled as a repeat. The second UpdateMemo, queued by the fix, is labelled UpdateMemo#1~hedge.
  6. Void sessions still get RACE verdicts. Two first sessions errored before any write because of harness locators; one still got "RACE 1 of 6".

Time spent

About 2 hours, 16:33 to about 18:30 UTC.

Not run

  • Memos' Go tests: the patch is web-only.
  • pnpm build: CI runs it, and the change touches no build config.
  • A by-hand check in a headed browser: left to the sender, per the checklist.

Generated by Claude Code

claude added 12 commits November 3, 2026 16:50
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fqwfq2VbjHiLqM5WHy1kJE
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fqwfq2VbjHiLqM5WHy1kJE
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fqwfq2VbjHiLqM5WHy1kJE
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fqwfq2VbjHiLqM5WHy1kJE
…wo upserts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fqwfq2VbjHiLqM5WHy1kJE
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fqwfq2VbjHiLqM5WHy1kJE

This branch has not been deployed

No deployments
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.

2 participants