fix(webapp): opening a thread marks it read by an explicit POST; a test pins which GETs may write (#1163) #1177
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/1163-get-routes-that-write"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #1163 (the logout part merged in #1165).
Threads.
GET /discussions/{id}no longer marks the thread read. NewPOST /discussions/{id}/read(204, idempotent, same auth and 404 as the GET). The thread page calls it when the thread is shown: once on open, again after a refetch only if that refetch brought a new post into view, and never while the tab is hidden (it marks when the tab becomes visible). A failed mark-read is swallowed and never breaks the page. From the reader's side nothing changes: opening a thread clears its unread state, and so does a post that arrives while they are looking at it.The test.
tests/test_get_routes_do_not_write.pywalks every GET route, scans the handler and one level ofapp.*callees for writes (commit/add/delete, update/insert/delete statements, Redis writes,enqueue), and fails on any writer not on an allow-list of(module, function, reason). Its docstring states what it cannot see (a write behind a second helper, or through an unusually named session). A stale allow-list entry also fails.Allow-listed, read and confirmed: the OIDC callback and Discord link GETs; the lore image GET (lazy move of a legacy file); the campaign ownership offer GET (lazy expiry); the four sheet-definition GETs (
ensure_builtin).Allow-listed, found by the scan and not yet reviewed (follow-up, not this PR): the planning names GET (writes a
generation_resultsrow on every cached call, and runs the LLM synchronously on a cold cache; wants to be a POST);GET /admin/settings/secrets-health(upgrades plaintext secrets and commits); the two content-pack export GETs (an audit row each); the server-ownership offer GET (lazy expiry).No bot API change (
/api/bot/*has no thread GET), no migration.Verified
On
docker-test:tests/discussions, the new test,test_wiki_crawl.py,test_commit_before_response.py,tests/export/test_export_bin.py(113 passed); ruff; changelog and version checks; discussions vitest (57 passed); frontend lint. Journeys run for real in the desktop project: J6 (opens a thread) on the final page code, and J2 (creates a thread) before the last change.Not run: phone and keyboard projects, the full backend and frontend suites (CI). This PR touches no journey or stack file, so it should take the desktop-only path from #1174: the first real run of it.
🤖 Generated with Claude Code
POST /api/discussions/{id}/read (204, idempotent, same 404 as the GET); the thread page calls it once when it shows the thread. A static scan test lists the GET handlers allowed to write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>