Skip to content
This repository was archived by the owner on Oct 8, 2026. It is now read-only.

v0.28.0

Latest

Choose a tag to compare

@VirInvictus VirInvictus released this 15 Sep 19:43
· 3 commits to main since this release

v0.28.0 (2026-09-15)

The final blitz release: the game becomes losable, and the skin becomes
playable.
The 2026-09-13 final audit's verdict was that the engineering
contracts are pristine and the play experience is the finding: under the
shipped skin, the game could neither be played nor lost. This release fixes
exactly that, gives the Ring an honest opening, lands the corpus campaign's
first batch, and pays the audit's comment-truth debts.

The terminal loop is gone, in the one lane the audit said it should be.
run_until_interrupted stops on a shortfall forecast before resolving, and
with the shipped all-zero standing orders and a stub editor it stopped
forever: no turn resolved, no deaths occurred, and GAME_OVER was unreachable
through the skin. Two things land together. The standing-orders editor is
real: five labour lines against the adults the clan actually has, the
rationing policy, and the forecast rendered live underneath, which is the
engine's own turn.forecast (produced, demand, net, idle hands, the
shortfall in red). The same forecast now sits in the rail in play, so the
allocation is decided against numbers instead of against a guess. And the
stop has a way through: "accept the shortfall and resolve anyway" resolves
one season on the standing orders, deaths and all, recorded exactly as a
background season would be (turn.resolve_and_record is the driver's
per-season ritual, named and shared). A winter the orders cannot fix no
longer ends the run by hanging it. The pilot tests lose an all-zero run end
to end; the skin can lose now.

The Ring waits to be earned. It shipped gating on households >= 3, true
from turn zero, at weight 100 against everyone else's 1: it fired as the
first event of nearly every run while its own comments claimed the
conditions kept it locked. The gate is year >= 2 and people >= 10 (the
founding clan is eight), the comments tell the truth, and corpus tests pin
year-one immunity and the growth floor structurally. Measured honestly on
the way: a household-count gate is unreachable inside a twenty-season run
because hearths barely split, so the gate prices growth in people.

Also in the skin: --seed 0 is a seed now, not a typo for random; Save and
Load while a question is up dismiss the question instead of swapping state
out from under the answer; saves are a stamped envelope, so a save from
another format of the game is refused at load instead of unpickling and
dying seasons later on a slot it never had; --replay --seed N plays one
run headless and prints the annotated chronicle, season by season,
allocation, forecast, events, and answers (the standing gate's reading, as
a command instead of an edited test); the chronicle pane renders event
bodies at last; and the number keys reach options four through nine.

The corpus grew from ninety to a hundred and two. The batch includes a
second take-in route (a man with a sled, distinct from the woman at the
treeline) repairing the doctrine payoff chain that the Ring fix squeezed,
and two gate widenings measured against the reachability harness:
debts.another_at_the_edge's food > 18 never once coincided with a
taken-in stranger across fourteen hundred ladder runs (it reads > 12
now), and the buried-enough event sat one grave above every run's ceiling
(it keys on two graves now). The liveness guard holds over all 102.

The honesty pass. The director's comment claimed an enforcement backed by
nothing ("the fact MUST have existed for at least a few turns") and a
random draw that did not exist ("50% of the time" was deterministic
turn-parity); it now describes the real mechanism (the massing announcement
is what makes the raid learnable, and the low-slack hold is the calendar,
not a coin), and the never-used rng parameter is gone from
Director.evaluate. The band-economy numbers that lived inline in
agents.py moved to balance.py, which is where its own header contract says
they belong. The three unexplained type: ignores are resolved the house
way (runtime imports and parameterised factories; chronicle's cycle broken
with a lazy annotation). turn.py's mid-file imports are hoisted and the
driver sits above the helpers banner. The rest of the audit's comment-truth
set is swept, and the audit's rendered-prose recasts are done: no em-dashes
or spaced-hyphen surrogates left in the docs.

GitHub: the pushed v0.27.0 tag was rewritten (annotated force-push,
Brandon-approved) to carry both entries that release shipped, verified with
git cat-file tag before pushing, and the v0.27.0 Release, the repo's
first, was created from the corrected tag. Topics stand at exactly the
20-topic cap, the description carries the deterministic hook, and the wiki
is off. CI gained workflow_dispatch and a 10-minute timeout; *.pkl is
ignored. The audit's removal candidates were asked (check_emergence,
Intent.target, and the rest) and the answer did not come back, so nothing
was deleted: each is marked in code, and the gate stays open in the
roadmap.

12 new tests; suite at 427; pyright strict zero. The textual floor is
raised to the tested 8.2, lock re-run in this commit.