mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 21:07:03 +01:00
The solver only ran behind ./run.sh, had one media query in the whole
stylesheet, and kept the inventory in a 46vh scroll box that showed maybe a
third of the 43 dice. Setting it up on the PC did nothing for the phone.
Deployment
dice.kuhy.duckdns.org, behind the existing gitea-caddy edge. DuckDNS already
wildcards *.kuhy.duckdns.org (checked against 1.1.1.1 and 8.8.8.8), so no
dashboard step. deploy_build.sh builds to dist.staging and rsyncs into dist/
with --delete-after --delay-updates; plain --delete removes stale assets
before writing the new ones, which 404s a client mid-load. A post-commit hook
starts a MemorySwapMax=0 systemd user unit, so a rebuild can neither slow a
commit nor thrash zram.
Three traps found by driving the live URL in a browser rather than curling it:
a site address of "127.0.0.1:8089" reads as a HOSTNAME, so Caddy enabled
auto-HTTPS and started an HTTP->HTTPS redirect listener that bound *:80 next
to the edge -- SO_REUSEPORT would then split inbound HTTP and intermittently
break ACME for every domain here. The same address also made a Host matcher,
so the edge's forwarded Host matched nothing and served an empty 200 while the
local health check passed. And watching dist/'s own inode could never detect a
detached bind mount: rsync into an existing directory never changes it. Each
now has a guard that asserts positively rather than failing open.
Dice list
All 43 on screen at every width, no inner scrollbar. Column count and size
tier are chosen together from a container query on the panel -- not the
viewport, which mispredicts by 2x at the point the columns split. Two
invariants govern it: the list fits above the fold, and the name column stays
wide enough to tell Painter's die B, G and R apart. The left column holds the
grid alone, so it is sized to fill the height it owns: one --die-row value
drives the type, buttons and bar strip, giving a 52px row and 44px buttons on
a 1296px-tall screen and 20px rows on a phone.
Three safe-design rules are broken inside .die-list deliberately: sub-16px
body text, square icon buttons, sub-8px intra-cell gaps. 43 items with a name,
a chart and a counter in one viewport is arithmetically incompatible with 16px.
Import / export
A file, the clipboard, or a link carrying the inventory in the URL fragment.
One validator behind all four entry points including localStorage; it keeps
what it can and reports what it dropped, so a die added in a later game patch
costs you that entry, not the inventory. A link never silently overwrites what
is saved here -- it offers Keep or Discard, and only a link that actually
carries dice is applied at all, because one encoding a count of zero parsed
cleanly, blanked the screen, disabled Clear and left Keep writing the emptiness
over the visitor's own loadout.
session_autopsy
parse.py (551) and report.py (504) were over the repo's 500-line limit, so
test_file_length has been failing on main since 5ffd035. Extracted TurnTracker
and the two candidate-cell helpers. Report output is byte-identical on real
data apart from its timestamp, checked against HEAD in a worktree.
Verified: 288 TS tests and 911 Python tests, 100% coverage both, lint and
pre-commit clean, 8 viewports measured on the live HTTPS site, solver confirmed
through the real module worker.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
44 lines
1.2 KiB
Python
44 lines
1.2 KiB
Python
"""Cell labels for the candidate table in REPORT.md.
|
|
|
|
Split out of ``report.py`` to keep it inside the repo's 500-line-per-file
|
|
limit. Both functions are pure label logic with no formatting dependencies,
|
|
which is why these two came out and the rest of the table rendering did not:
|
|
the detail block needs ``fmt_tokens`` and would make the import circular.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from python_pkg.session_autopsy.detectors import Candidate
|
|
|
|
|
|
def action_cell(cand: Candidate, handled: set[str]) -> str:
|
|
"""The table's action column for one candidate.
|
|
|
|
Args:
|
|
cand: The candidate.
|
|
handled: Ids with a recorded verdict.
|
|
|
|
Returns:
|
|
The suggested action, or a pointer to where its verdict lives.
|
|
"""
|
|
if cand.id in handled:
|
|
return "already handled — see Reviewed/scoreboard"
|
|
return cand.action
|
|
|
|
|
|
def verdict_label(entry: dict[str, object]) -> str:
|
|
"""Human label for a reviewed entry's verdict.
|
|
|
|
Args:
|
|
entry: A compiled.json entry.
|
|
|
|
Returns:
|
|
``"dropped (workflow removed)"`` or ``"keep LLM"``.
|
|
"""
|
|
if entry.get("verdict") == "dropped":
|
|
return "dropped (workflow removed)"
|
|
return "keep LLM"
|