Skip to content

feat(opal): tint a guess red once its guesser ran out of guesses - #564

Merged
vEnhance merged 1 commit into
mainfrom
claude/opal-guess-log-styling-q0fbnt
Aug 27, 2026
Merged

feat(opal): tint a guess red once its guesser ran out of guesses#564
vEnhance merged 1 commit into
mainfrom
claude/opal-guess-log-styling-q0fbnt

Conversation

@vEnhance

Copy link
Copy Markdown
Owner

Enhancement, following up on #563.

What this changes

Yellow says a guess led nowhere, but it doesn't separate someone who wandered off from someone the puzzle actually shut out — and the second is the sharper signal, since they wanted the answer and the guess limit took it away.

This adds a red tint (table-danger) for a row whose guesser has no correct answer for that puzzle and has spent its whole guess limit. It slots in between the finisher and unsolved branches:

testsolver → blue
finished the hunt → green
unsolved AND out of guesses → red   ← new
unsolved → yellow
otherwise → plain

So the hunt-wide tints still win, and every red row is one that would otherwise have been yellow. Given how few yellow rows there are in practice, this should be a rare and meaningful marker rather than a wall of color.

Keeping "out of guesses" honest

_eligibility was the only definition of which guesses count against the limit — not correct, not close, not excused. The log has to agree with it, or a row goes red while the puzzle page is still happily taking answers. Both now read one COUNTS_AGAINST_GUESS_LIMIT Q object.

test_guess_log_out_of_guesses_matches_puzzle_page pins the two together directly: it walks a guesser to the limit (with a close guess and an excused guess mixed in, since neither should count) and asserts can_attempt flips from True to False in the same step the tint goes from yellow to red.

Query cost

Still one query for the standings, not two. Rather than add a second query to count spent guesses, _standings now groups every guess on the hunt by (guesser, puzzle) and reads two filtered aggregates off each group:

.annotate(
    first_correct=Min("created_at", filter=Q(is_correct=True)),
    num_counted=Count("pk", filter=COUNTS_AGAINST_GUESS_LIMIT),
)

That carries all four facts a standing holds — solved set, exhausted set, testsolver, finisher — with identical semantics to the previous correct-attempts-only query. Measured at 2, 50, and 100 rows, all four logs are unchanged: 10 (hunt log), 9 (recent activity), 12 (per-puzzle), 12 (per-user).

Testing

test_guess_log_row_styling now also walks Bob to the meta's guess limit and checks his rows on it turn red while his rows on the puzzle he did solve stay plain, then that finishing the hunt flips everything green.

Full suite passes (424), make check clean.


Generated by Claude Code

Yellow says a guess led nowhere. It does not separate someone who wandered
off from someone the puzzle actually shut out, which is the sharper signal:
they wanted the answer and the guess limit took it away.

Tint that case red -- an unsolved puzzle whose guesser has also spent its
whole guess limit. It sits between the finisher and unsolved branches, so
the hunt-wide tints still win and every red row is one that would otherwise
be yellow.

What "spent the limit" means now lives in one place. `_eligibility` was the
only definition of which guesses count -- not correct, not close, not
excused -- and the log has to agree with it, or a row goes red while the
puzzle page is still taking answers. Both now read
`COUNTS_AGAINST_GUESS_LIMIT`, and a test pins the two together by walking a
guesser to the limit and checking `can_attempt` flips in step with the tint.

Still one query for the standings. Rather than add a second, `_standings`
now groups every guess on the hunt by guesser and puzzle and reads the
first correct timestamp and the spent-guess count off each group, which
carries all four facts a standing holds. Counts measured at 2, 50 and 100
rows are unchanged.
@vEnhance
vEnhance merged commit 56f7ea8 into main Aug 27, 2026
5 checks passed
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