Skip to content

v0.25.1

Choose a tag to compare

@ca1773130n ca1773130n released this 25 Jul 05:10
· 151 commits to main since this release

Tesserae v0.25.1 — the compile no longer wedges, and degraded docs are recoverable

한국어 · 中文 · 日本語 · Русский · Español · Français · Deutsch

Released 2026-07-25 · PyPI · GitHub release · pip install --upgrade tesserae==0.25.1

A bugfix release. No API changes — drop-in over v0.25.0, with one behaviour
default flipped (see Upgrading).

Every fix here came out of one investigation. A compile on a real project sat at
0% CPU for 5 hours 43 minutes, behind a codex exec child that had been idle
for 4 hours 6 minutes. It had already minted 32 COMMUNITY_SUMMARY nodes in
memory and never lived to persist them, so graph.json ended with zero. Pulling
that thread surfaced three more defects.

Fixes

  • The extraction wedge guard is armed by default. v0.25.0 shipped a per-file
    extraction timeout, but opt-in — so it stayed switched off and the failure it
    prevents kept happening. _run_cli's process-group killpg was correctly
    wired the whole time; it simply never fired, because communicate(timeout=None)
    never raises. The bound is now 1800 s per attempt by default. Killing the
    wedged child's process group let the parent compile resume within seconds
    it had been parked in communicate() for four hours.

    A typo must not silently disarm a safety valve, so an unusable value
    (10m, 600s, negative, inf) now warns and keeps the default instead of
    falling back to "no cutoff". TESSERAE_EXTRACT_TIMEOUT=0 is the explicit
    escape hatch.

  • compile --retry-fallbacks recovers docs that degraded to deterministic.
    When an extraction fails, the doc is served by the deterministic baseline —
    but its manifest entry was byte-identical to a clean extraction, so
    --changed-only skipped it on every later compile and the degradation was
    permanent until the file's own content changed
    . Recovering a handful of docs
    meant hand-editing manifest.json, with the standing risk of instead
    deterministic-filling the whole corpus and destroying hours of typed work.
    Such entries are now marked and re-attempted on demand, mirroring
    distill --retry-fallbacks.

  • live_member_count on graph_map cards. size and leaf_member_count
    both come from the hierarchy.json sidecar, which is written mid-compile. When
    graph.json is rewritten afterwards the two diverge, and a card can advertise
    hundreds of members that resolve to nothing — with no way for a client to tell
    it from a healthy card without re-reading graph.json itself. Graph-derived
    cards (kind=community|node) now also report how many members the current
    graph carries. 0 means the scope is dead: skip it rather than descend.

    On one real 7,133-node graph this immediately surfaced 2 dead root cards and
    42 partially-resolved ones that nobody had noticed.

  • The _CLIENT_FACTORY test seam honours the caller's timeout.
    build_default_json_client dropped it, handing the injected fake a 30 s default
    regardless — so a test pinning a timeout silently proved nothing. Seam-only;
    production composition was already correct.

Upgrading from v0.25.0

Drop-in, with one thing to know: extraction is now bounded by default
(1800 s per attempt). If you deliberately want unbounded runs, set
TESSERAE_EXTRACT_TIMEOUT=0.

The bound is per attempt, not per document — on timeout the client rotates to
the next CODEX_HOME / claude config dir, so a document's worst case is
timeout × configured profiles.

If a past compile left documents stuck on deterministic extraction, recover them
with:

tesserae compile --changed-only --retry-fallbacks

Only documents whose typed extraction actually failed are re-attempted; clean
ones stay skipped.