Fix #36, #42: reaction toggle/remove, immediate show, no comment-row #53

Merged
crueber merged 1 commit from fix/issue-36-42 into main 2026-09-04 20:06:08 +00:00
Owner

Closes #36, closes #42.

Reaction surface on the issue thread page (web/src/pages/Issue.jsx):

  • #36: summary chips toggle — click removes your own reaction (DELETE own reaction endpoint); a remove-404 falls back to add (GitHub semantics, summary carries no per-user state). Non-404 remove failures only report (old code re-added on ANY error). One in-flight mutation per (seq, content) disables its buttons, so double-clicks never double-fire (server also dedups sequential adds per (actor,target,content)).
  • #42a: clicks paint IMMEDIATELY — immutable adjustSummary step committed via the new generation-safe patchCached() path in web/src/lib/data.js (retires pre-mutation in-flight bodies under the #41 ordering guard; reconciled — or rolled back on failure — by the guarded invalidate() refetch). No unguarded commits.
  • #42b: reaction_changed events FOLD into the summary (GitHub-style) — they never render as timeline rows (the screenshot's comment-looking row is gone). after_seq cursor unaffected (seq cursor, not a count). reactionChangedText kept for logs/diagnostics + its unit test.

Docs (law 12): docs/features/02_issues.md UI paragraph updated in the same change. No new dependencies (law 1); no new seams/routes (law 8).

Verification:

  • node --test web/test/unit/*.test.js: 227/227 green (incl. 5 new adjustSummary tests + 4 new patchCached/optimistic tests in web/test/unit/reaction-cache.test.js).
  • vite build clean (103 modules); gofmt clean.
  • Real browser (hub chrome-cdp, local scratch backend @ae16709): dark — 2 rows, no reaction rows; click heart chip painted same-task pre-network, persisted after refetch; chip-toggle removed same-task, persisted; light — rocket cycle immediate + persisted. Zero own-origin console errors. Screenshots: dark/light thread pages.
  • Known limit: true-simultaneous duplicate POSTs can still double-count (documented best-effort dedup in 02 §8, unchanged); per-(seq,content) busy guard covers the real double-click case.
  • Emoji glyphs render as boxes in bare headless Chrome (no emoji font installed) — environmental; wire words remain in aria-label/title.
Closes #36, closes #42. Reaction surface on the issue thread page (web/src/pages/Issue.jsx): - #36: summary chips toggle — click removes your own reaction (DELETE own reaction endpoint); a remove-404 falls back to add (GitHub semantics, summary carries no per-user state). Non-404 remove failures only report (old code re-added on ANY error). One in-flight mutation per (seq, content) disables its buttons, so double-clicks never double-fire (server also dedups sequential adds per (actor,target,content)). - #42a: clicks paint IMMEDIATELY — immutable adjustSummary step committed via the new generation-safe patchCached() path in web/src/lib/data.js (retires pre-mutation in-flight bodies under the #41 ordering guard; reconciled — or rolled back on failure — by the guarded invalidate() refetch). No unguarded commits. - #42b: reaction_changed events FOLD into the summary (GitHub-style) — they never render as timeline rows (the screenshot's comment-looking row is gone). after_seq cursor unaffected (seq cursor, not a count). reactionChangedText kept for logs/diagnostics + its unit test. Docs (law 12): docs/features/02_issues.md UI paragraph updated in the same change. No new dependencies (law 1); no new seams/routes (law 8). Verification: - node --test web/test/unit/*.test.js: 227/227 green (incl. 5 new adjustSummary tests + 4 new patchCached/optimistic tests in web/test/unit/reaction-cache.test.js). - vite build clean (103 modules); gofmt clean. - Real browser (hub chrome-cdp, local scratch backend @ae16709): dark — 2 rows, no reaction rows; click heart chip painted same-task pre-network, persisted after refetch; chip-toggle removed same-task, persisted; light — rocket cycle immediate + persisted. Zero own-origin console errors. Screenshots: dark/light thread pages. - Known limit: true-simultaneous duplicate POSTs can still double-count (documented best-effort dedup in 02 §8, unchanged); per-(seq,content) busy guard covers the real double-click case. - Emoji glyphs render as boxes in bare headless Chrome (no emoji font installed) — environmental; wire words remain in aria-label/title.
Sign in to join this conversation.
No description provided.