Fix Level 2 candidate grid rendering empty until a chip is touched - #63
Merged
Merged
Conversation
Root cause: per-question local state (chipStates/revealed/ filterExpanded/selectedCandidateId/etc) reset via a separate useEffect keyed on [item?.card.identifier, item?.type]. That dependency array silently skips the reset whenever two consecutive feed items share both values - which happens for real, since a single card can carry more than one pending question, or the same question can be re-served. A chip left "positive" from the previous card then filters the new card's candidate grid against an unrelated attribute, hiding candidates (up to all of them) until the user happened to touch a chip themselves - the only other thing that ever updated chipStates, which incidentally "fixed" it by replacing the stale filter with a fresh one. Not a #58 regression - the layout reconciliation pass touched CardPanel/ChipRing's CSS only, not this state-reset logic, which predates it. Fix: reset the per-question state inside the same .then() callback that calls setItem(), rather than a separate effect with a dependency array that can fail to change. This removes the whole bug class rather than trying to compute a "definitely always changes" key. Verified the new Jest test fails against the pre-fix code (confirmed by temporarily reverting the fix and re-running: the second item's reveal overlay never appears, since `revealed` never resets when identifier+type repeat) and passes against the fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014dB7mGPQyoML2Ri5ZrprdK
5 tasks
WilfordGrimley
added a commit
that referenced
this pull request
Jul 18, 2026
…staleness mini-pass (#79) * publish_wiki.py: fix link rewriting for parent-relative paths and slug casing GitHub wiki's native [[...]] auto-linking reinterprets our own docs/ [[file.md]] convention: [[../troubleshooting.md]] became a dead literal slug, and [[printing-tags.md]] linked the raw filename casing instead of the published page name "Printing-Tags" (both visible live on Catalog-Completion-Plan). Every internal link is now resolved against its source file's real repo path and mapped through wiki-publish-map.json: a published target becomes a same-wiki link using its real page name, an unpublished-but-real target becomes an absolute GitHub blob URL, and a target resolving to neither is a hard publish error. docs_lint.py can't catch this class of bug since it only checks links within docs/ itself, not the wiki-transform's own reinterpretation downstream - the script now self-checks at publish time instead. Also adds two docs/ pages that were listed in docs/README.md's index but missing from the mapping entirely (found via the new validation): documentation-process.md and upstream-wiki-drift.md. * Docs staleness pass: Part 3 write-pass status + proposal B/C/E-1/E-2 markers catalog-completion-plan.md: Part 3 heading and Status section updated to reflect the completed write pass (run_id 20260718T145157-a12b1387, 13,275 votes, all hard bounds passed, 0/7,124 zero-resolution violations at full population), pointing to docs/reports/2026-07-18-part3-write-pass-complete.md. Filled the dangling "see the follow-up entry below" reference and replaced the now-stale "HOLD #P3 stands" language. Part 4's heading now notes it's confirmed unstarted with HOLD #B prep queued. proposal-b-bleed-normalization.md: top summary no longer lists the prior-resolution batch fetch as remaining work - it shipped as PR-1 (#72). proposal-g-user-accounts-saved-decks.md: noted the build-order queue (E-1 #61, E-2 #62, Level-2 grid fix #63, audit pass #64, GIS error UX #65, Proposal B #66/#72, Proposal C part (a) #67) has fully cleared. docs/README.md: added proposal-b and proposal-c to the "Plans & proposals" table - both have dedicated docs but were missing from the index entirely, despite the section's own stated policy that any proposal with a dedicated doc gets a row. printing-tags.md and vote-system.md checked per the mini-pass's minimum list; no changes needed - printing-tags.md already defers Stage 8+ status to catalog-completion-plan.md, and vote-system.md has no AI-terminology or merged-PR staleness. * Report relay: wiki review findings (publish-script fix, Part 3 status, staleness mini-pass) * CI: black-format publish_wiki.py, prettier-format cache-transition-resilience.md black reformatting for publish_wiki.py (never run locally - only py_compile was checked, missing the repo's black rev 22.8.0 pinned in .pre-commit-config.yaml). cache-transition-resilience.md's prettier drift predates this PR (introduced by #75) and is unrelated to its content - swept here since the "Formatting and static type checking" check runs pre-commit against all files, not just the diff, and this PR's own CI needs to go green. --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Owner-observed, post-#58: Level 2's candidate grid sometimes shows only the suggested match with an empty grid until the user interacts with an attribute-chip filter (observed on Kiku, Night's Flower — CHK original absent until chips touched).
Diagnosis: (a) real bug, not (b) intentional design gap. Not a #58 regression — the layout reconciliation pass touched
CardPanel/ChipRing's CSS only; this is a pre-existing state-reset bug inQuestionFeed.tsx's data flow, unrelated to layout.Root cause: per-question local state (
chipStates/revealed/filterExpanded/selectedCandidateId/etc) reset via a separateuseEffectkeyed on[item?.card.identifier, item?.type]. That dependency array silently skips the reset whenever two consecutive feed items share both values — which happens for real: a single card can carry more than one pending question (printing + artist + tags), or the same question can be re-served. A chip left "positive" from the previous card then filters the new card's candidates against an unrelated attribute, hiding some or all of them — until the user happens to touch a chip themselves, which is the only other thing that ever updateschipStates, incidentally "fixing" it by replacing the stale filter with a fresh one.Fix: reset the per-question state inside the same
.then()callback that callssetItem(...), instead of a separate effect with a dependency array that can fail to change between renders. This removes the entire bug class rather than trying to compute a "definitely always changes" key.Checklist
pre-commitand installed the hooks withpre-commit installbefore creating any commits.revealednever resets when identifier+type repeat) — then restored the fix and confirmed it passes.npx tsc --noEmit,npx jest --runInBand(251/251 passing, no flakes this run),npx eslint— all clean.QuestionFeedLevels,QuestionFeedConfirmSuggestion,QuestionFeedMobileLayout,QuestionFeedLayoutReconciliation): 17/17 passing.docs/features/printing-tags.md's frontend architecture section updated in place with the root cause and fix rationale.Merge-time checklist
None — this is layout-independent state-management logic, no real-device or live-CDN dependency; the Jest test's revert-and-confirm methodology is a stronger correctness guarantee than a real-device pass would add here.
Generated by Claude Code