mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 23:07:03 +01:00
Closes the two CPU-only cells of the art bake-off and builds the bridge the diffusion cell will reuse. Pins the bake-off to the SAME twelve subjects item-icons measured, with its easy/hard split intact. Without this a route tested on distinctive silhouettes beats the 6/12 baseline for free and the decision table means nothing. It also makes the subject-routing rule falsifiable: a generator route is predicted to lift specifically the six human-prior failures, and if it does not, the rule is recorded as wrong. Route (a) procedural: all twelve subjects drawn deterministically from a 7-colour locked palette. Every shape gets a distinguishing feature up front, because item-icons measured that plain primitives read as placeholders however correct the geometry is. Machine gate: 12/12 -- which proves "not malformed", NOT quality. A procedural generator satisfies palette/alpha/canvas constraints trivially; the human contact sheet is the real verdict. Route (d) code-as-art: SVG emitted as text and rasterised by rsvg-convert, so no new Python dependency (cairosvg/svgwrite stay absent). The structural finding, measured on real rasteriser output rather than a synthetic stand-in: raw vector renders pass 0/5 -- every one fails ALPHA_NOT_BINARY, most also TOO_MANY_COLORS. After the finishing stage, 5/5. Continuous-tone routes are therefore GENERATORS FEEDING A FINISHER, not pixel-art generators. finish.py binarises alpha before quantising colour, mirroring the gate order: quantising first blends transparent pixels' arbitrary RGB into the palette. Verified: 92 tests, 100% branch coverage across all ten modules, zero suppressions, all hooks pass. The PLR2004 lint refactor was confirmed pixel-neutral by byte-comparing all 12 icons before and after (12/12 identical). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9rQ12yZ7sJxiPQTCS5dUF
99 lines
3.3 KiB
Python
99 lines
3.3 KiB
Python
"""The fixed subject set the bake-off is pinned to.
|
|
|
|
Every route and every applicable style is tested on the SAME twelve subjects,
|
|
because a route evaluated on easy subjects beats a 50% baseline for free and
|
|
the comparison would measure the subject list rather than the route.
|
|
|
|
The split comes from the `item-icons` skill's measured human verdicts: six
|
|
subjects passed and six failed on a first attempt, and the pattern predicting
|
|
failure was not drawing difficulty but whether the viewer holds a precise
|
|
mental image of the object. That makes the routing rule below falsifiable --
|
|
a generator route is predicted to lift specifically the HUMAN_PRIOR six.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from enum import Enum
|
|
from typing import Final
|
|
|
|
|
|
class Difficulty(str, Enum):
|
|
"""Why a subject is expected to be easy or hard, not how hard to draw."""
|
|
|
|
SAFE = "SAFE"
|
|
HUMAN_PRIOR = "HUMAN_PRIOR"
|
|
PRIMITIVE = "PRIMITIVE"
|
|
|
|
def __str__(self) -> str:
|
|
"""Return the bare value for report tables."""
|
|
return self.value
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Subject:
|
|
"""One bake-off subject.
|
|
|
|
Attributes:
|
|
name: Lowercase identifier, used in filenames and report rows.
|
|
difficulty: The predicted failure mode, or SAFE.
|
|
note: Why this subject sits in that category.
|
|
"""
|
|
|
|
name: str
|
|
difficulty: Difficulty
|
|
note: str
|
|
|
|
|
|
# The six that PASSED in the item-icons measurement: distinctive silhouettes
|
|
# with no canonical proportions, so the viewer has a wide error budget.
|
|
_SAFE: Final = (
|
|
Subject("key", Difficulty.SAFE, "wards make it unmistakable"),
|
|
Subject("scroll", Difficulty.SAFE, "no canonical proportions"),
|
|
Subject("book", Difficulty.SAFE, "clasp gives it a feature"),
|
|
Subject("bone", Difficulty.SAFE, "organic, no fixed ratio"),
|
|
Subject("gem", Difficulty.SAFE, "facets read at any size"),
|
|
Subject("bomb", Difficulty.SAFE, "fuse is a strong feature"),
|
|
)
|
|
|
|
# The six that FAILED. Kept verbatim so the bake-off measures the same task.
|
|
_HARD: Final = (
|
|
Subject("potion", Difficulty.HUMAN_PRIOR, "flask shoulders are specific"),
|
|
Subject("sword", Difficulty.HUMAN_PRIOR, "blade/hilt ratio is known"),
|
|
Subject("shield", Difficulty.PRIMITIVE, "a slab reads as a placeholder"),
|
|
Subject("coin", Difficulty.PRIMITIVE, "a circle with a rim is barebones"),
|
|
Subject("ring", Difficulty.PRIMITIVE, "a torus with no feature"),
|
|
Subject("meat", Difficulty.HUMAN_PRIOR, "a ham has a specific shape"),
|
|
)
|
|
|
|
SUBJECTS: Final = _SAFE + _HARD
|
|
|
|
# The measured baseline this bake-off must beat: 6 of 12 accepted by a human,
|
|
# unchanged after a second redraw round. A cell that cannot beat this is
|
|
# reported as such rather than dressed up.
|
|
BASELINE_PASS = 6
|
|
BASELINE_TOTAL = 12
|
|
|
|
# item-icons ran two rounds and stayed at 6/12, so a third is not
|
|
# evidence-backed. Each cell gets this many rounds, then its number is recorded.
|
|
MAX_ROUNDS = 2
|
|
|
|
|
|
def by_name(name: str) -> Subject:
|
|
"""Look up a subject.
|
|
|
|
Args:
|
|
name: The subject's lowercase identifier.
|
|
|
|
Returns:
|
|
The matching subject.
|
|
|
|
Raises:
|
|
KeyError: If the name is not part of the fixed set.
|
|
"""
|
|
for subject in SUBJECTS:
|
|
if subject.name == name:
|
|
return subject
|
|
msg = f"{name!r} is not one of the {len(SUBJECTS)} fixed subjects"
|
|
raise KeyError(msg)
|