Skip to content

fix(qa): three regressions from yesterday's nine PRs - #611

Merged
mrviduus merged 1 commit into
mainfrom
fix/qa-006-findings
Sep 12, 2026
Merged

fix(qa): three regressions from yesterday's nine PRs#611
mrviduus merged 1 commit into
mainfrom
fix/qa-006-findings

Conversation

@mrviduus

Copy link
Copy Markdown
Owner

An adversarial QA pass over the nine PRs of 2026-09-11 — the ones whose screens no person had opened. Three findings are regressions introduced by those PRs. All three are mine, and all three landed in the half that has no test that could run: apps/mobile has no component test runner, and not one .test.tsx file exists under it.

1 — "Mark as finished" was a silent no-op on a slow clock

markProgressFinished — added in #602 precisely to make web and mobile write the same locator — also sent updatedAt: new Date().toISOString(), a device clock. UserDataEndpoints.UpsertProgress reads that as a last-write-wins guard and, when it is not newer than the stored value, answers 200 with the row untouched. useBookActions has already flipped the shelf optimistically, so the reader sees "finished" and the server has nothing.

Web's markAsRead has never sent one. The guard is right for a queued background sync — an old queued write must not overwrite a fresh one — and wrong for a button the reader just pressed.

Removed, with a payload test that also pins the inverse: the ordinary updateProgress keeps its timestamp, because that caller genuinely is a queue. Mutation-verified.

2 — Apple sign-in never warned about a dropped guest merge

#609 wired warnIfNothingCarried into three of the four merge entry points. An iOS reader whose guest row was not merged was landed in a new account with no indication that their highlights, vocabulary and progress had stayed behind — the exact outcome #609 existed to prevent, on the one path it missed.

A literal-scanning test now covers all four, in the shape capabilityLiterals.test.ts and routeLiterals.test.ts already use. Its KNOWN_GAPS list is empty and the docblock says shrinking it is always the fix.

3 — The Tutor kept ordering a tool that does not exist

#605 removed get_example_sentence from AllowedTools and from SystemPrompt, and missed the copy in BuildGoal — sent on every re-plan turn.

The guard shipped with #605 could not catch it: it reflects over a string array, and the instruction is prose. Its own failure message said "the system prompt may still be telling it to call them"; nothing checked.

So the guard learned to read. It scans what the agent says for anything shaped like a tool name and requires it to be allowed. Two false starts are recorded in its docblock because both are instructive:

  • Matching against registered tools left the mutation green — a deleted tool is registered nowhere, which is exactly the case that hurts.
  • A naive scan then failed on a correct file: these prompts wrap at 110 columns, so a name lands across a concatenation ("…get_weak_" + "vocabulary…") and the scanner reported get_weak_. It now glues adjacent literals.

Both mutations — plain and split across a concatenation — turn it red.

Also in this PR

The QA pass left seven test files behind, several of them characterization tests that assert today's behaviour with names saying what to invert when fixed. The Apple one is inverted here (its assertion was "does not warn"). The rest stand.

Verification

  • unit 1288 · MCP 33 · integration 176 (50 skipped) · mobile 380 · shared 456 — pass
  • dotnet format --verify-no-changes clean
  • Each of the three fixes mutation-tested: put the defect back, watch the new test go red.

What this pass did NOT fix, and is worth a decision

  • set_book_progress derives its percentage as chapters-done/total while the app's canonical formula is word-weighted (computeBookProgress) — measured live, 0.2308 vs 0.0797 on the same book. It declares percentUnit: "book", so the server's guard trusts it.
  • A catalog book the assistant records progress for is not added to the library, so get_my_reading — the tool whose description says "call this FIRST" — does not list it afterwards.
  • An MC card can render with no prompt at all when a word has no sentence, definition or translation; mobile's fourth fallback prints the answer above its own options.

🤖 Generated with Claude Code

https://claude.ai/code/session_011rgEMvYYi4Egj99dVtvm6E

Found by an adversarial pass over work shipped 2026-09-11. All three are mine,
and all three are in the half nobody could look at: mobile has no component test
runner at all.

1. Mark-as-finished was a silent no-op on a device clock behind the server. The
   helper added to make web and mobile write the same locator also sent
   updatedAt from the device; the server reads that as a last-write-wins guard
   and answers 200 with the row untouched. The shelf had already flipped
   optimistically. Web's markAsRead never sent one. Removed, with a payload test —
   and the ordinary queued progress write keeps its timestamp, which is what the
   guard is actually for.

2. Apple sign-in never warned about a dropped guest merge — #609 wired three of
   the four entry points. An iOS reader was landed in a new account with no
   indication their work stayed behind. A literal scan now covers all four.

3. The Tutor kept ordering get_example_sentence from BuildGoal on every re-plan
   turn; #605 removed it from AllowedTools and SystemPrompt and missed that copy.

The guard from #605 could not have caught (3): it reflects over a string array
while the instruction is prose. It now reads the words. Two false starts are in
its docblock — matching against REGISTERED tools left the mutation green, because
a deleted tool is registered nowhere; and a naive scan failed on a correct file,
because these prompts wrap and a name lands across a concatenation. Both
mutations are red now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011rgEMvYYi4Egj99dVtvm6E
@mrviduus
mrviduus merged commit 5f40661 into main Sep 12, 2026
10 checks passed
@mrviduus
mrviduus deleted the fix/qa-006-findings branch September 12, 2026 22:55
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