Files
upbeatBytes/tests/test_wordsearch_grid.py
T
thejayman77 ddcfab3a11 Admin: source Articles inspector (verify metrics against real evidence)
New per-row "Articles" button on the Sources table expands a read-only inline
panel of the source's ACTUAL ingested articles — so the automated metrics
(paywall/image/acceptance/duplicate) can be verified against evidence instead of
trusted blind. Distinct from "Check" (which re-samples the LIVE feed for
would-pass quality); this shows what's already in the DB, which is what the table
metrics are computed from.

- Backend: GET /api/admin/sources/{id}/articles?filter=&limit=&offset= (admin,
  read-only). queries.source_articles + source_articles_summary — per article:
  title, url, date, accepted, reason (the "why"), topic/flavor, paywalled
  (domain rule), has_image, duplicate. Summary = counts + source-level paywall
  rule.
- Frontend: expandable panel with a summary header ("27 ingested · 18 accepted
  · … · paywall rule: ON (domain)"), filter chips (All/Accepted/Rejected/No
  image/Duplicates), compact rows with title→link + badges + reason, Load more.

So "100% paywall" or "0% images" becomes clickable evidence: open two articles
to tell a real paywall from a mis-flagged domain, or a true image gap from an
enrichment failure. Test: test_source_articles_inspector. 241 pytest + 11 vitest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 21:37:51 -04:00

79 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Locks the word-search placement qualities players actually feel:
1. Every word gets placed (exhaustive candidate search — nothing silently dropped).
2. Grids INTERLOCK like a real puzzle (the "clean isolated words" regression).
3. Words SPREAD across the board (the "all clumped in one corner" regression).
4. Same date/seed → same grid (cross-device players must see identical puzzles).
Thresholds were calibrated against all curated themes × 12 seeds × 3 tiers
(288 grids/tier): crossing fraction averaged ~0.7 (old algorithm: ~0.3, with a
third of small grids having ZERO crossings), worst quadrant share 0.42, and all
four quadrants always held word cells. Deterministic, so no flake margin needed.
"""
import random
import statistics
from goodnews.games import _WS_FALLBACKS, WS_TIERS, _WS_ORDER, _build_grid, _place_words, _zone
def _tier_grids(tier):
"""Yield (placements, size) for every curated theme × 12 seeds in a tier."""
t = WS_TIERS[tier]
for _, words in _WS_FALLBACKS:
for seed in range(12):
rng = random.Random(seed * 1000 + 7)
ws = list(words)
rng.shuffle(ws)
_, placements = _place_words(ws[: t["count"]], t["grid"], seed)
yield placements, t["grid"]
def _cross_fraction(placements):
"""Fraction of placed words sharing at least one cell with another word."""
owners: dict[tuple[int, int], list[str]] = {}
for w, cells in placements:
for cell in cells:
owners.setdefault(cell, []).append(w)
crossing = set()
for ws in owners.values():
if len(ws) > 1:
crossing.update(ws)
return len(crossing) / len(placements)
def test_all_words_placed():
for tier in _WS_ORDER:
for placements, _ in _tier_grids(tier):
assert len(placements) == WS_TIERS[tier]["count"]
def test_grids_interlock_without_clumping():
for tier in _WS_ORDER:
fracs = []
for placements, size in _tier_grids(tier):
fracs.append(_cross_fraction(placements))
# Spread: word cells must reach all four quadrants, and no quadrant
# may hoard more than half of them (perfectly even would be 0.25).
quad: dict[tuple[int, int], int] = {}
cells = {c for _, cs in placements for c in cs}
for r, c in cells:
quad[_zone(r, c, size)] = quad.get(_zone(r, c, size), 0) + 1
assert len(quad) == 4, f"{tier}: words confined to {len(quad)} quadrant(s)"
assert max(quad.values()) / len(cells) <= 0.5, f"{tier}: clumped in one quadrant"
# Interlock: every grid has some crossings; on average most words connect.
assert min(fracs) >= 0.3, f"{tier}: a grid came out as disconnected clean words"
assert 0.55 <= statistics.mean(fracs) <= 0.9, f"{tier}: avg crossing {statistics.mean(fracs):.2f}"
def test_grid_deterministic_and_honest():
"""Same inputs → byte-identical grid, and every reported word is really in it
(forward or reversed along some line — spot-checked via placements)."""
words = _WS_FALLBACKS[0][1][:9]
rows1, placed1 = _build_grid(words, 11, 42)
rows2, placed2 = _build_grid(words, 11, 42)
assert rows1 == rows2 and placed1 == placed2
_, placements = _place_words(words, 11, 42)
for word, cells in placements:
assert "".join(rows1[r][c] for r, c in cells) == word