Skip to content

v0.27.0

Choose a tag to compare

@ca1773130n ca1773130n released this 26 Jul 12:57
· 142 commits to main since this release
d212c9d

Tesserae v0.27.0 — agents can write to the graph, and ask it what it licenses

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

Released 2026-07-26 · PyPI · GitHub release · pip install --upgrade tesserae==0.27.0

Until now an agent could only hand Tesserae prose and hope the extractor guessed
the right types back out. This release opens the write path and the verification
path: agents record findings as typed structure, and can ask the graph whether it
actually licenses a claim.

Agents write typed findings

graph_write takes schema-validated typed nodes and edges with mandatory
provenance. It refuses rather than coerces — untyped edges, types outside the
controlled vocabulary, dangling endpoints and missing provenance are all
rejected; duplicate writes are idempotent.

Agent-written nodes survive a full recompile, a deleted graph.json, --limit,
and total corpus deletion. Under adversarial testing, 60 concurrent writes
against a live compile came through with zero torn reads across 1,483 reads.

Agents verify against the graph

verify_claim answers whether the graph licenses a triple. The verdict is a
pure function of graph bytes: no LLM, no embedding, no fuzzy matching anywhere
on the decision path.
A verifier that hallucinates is worse than no verifier.

It takes (subject, predicate, object) and has no natural-language
parameter
— deliberately. Seven verdicts, including PRESENT_UNEVIDENCED
(the edge exists but nothing document-backed stands behind it) and ABSENT
("this graph does not assert that" — never a refutation).

Two guarantees worth stating plainly. supersedes never produces a verdict: it
says a node was replaced, not that a triple is false. And an agent write can
only ever weaken a provenance class, never upgrade one — nothing an agent
asserts can present as document-grounded.

Also

  • Semantic entity resolution. Embedding-clustered candidates now feed the
    existing review queue rather than auto-merging. Precision over recall: a
    wrong merge silently fuses two real entities and every downstream traversal
    inherits the error.
  • Question-shape routing for ask. Graphs win multi-hop, temporal and
    synthesis questions and lose simple fact lookup and cost, so paying graph
    prices for everything is a loss. The routing decision is in the envelope so a
    cheap answer is auditable; --route overrides.
  • Validity intervals on temporal facts, derived from source timestamps —
    never wall-clock.
  • --llm-limit holds under concurrent extraction. Since v0.26.0 made
    extraction parallel, the old check-then-increment let every worker read the
    counter before any of them wrote it, so --llm-limit 1 bought one call per
    worker
    . It is a spend cap, so it now fails closed.
  • Compile coverage is an invariant, not a claim. Four silent-data-loss paths
    closed, then the machinery behind them removed entirelycompile(loader=…)
    has no production caller, and defending that library-only API was the source of
    every serious defect across several review rounds. One of them was a regression
    v0.26.0 itself introduced.
  • New documentation for the write, verify and routing
    surfaces.

What did not ship, and why

A contrast pass to mine contradicts_claim / derived_from / criticizes
edges was built, measured, and cut. It minted 0 edges from 80 judged pairs
across two real corpora, and 60 of 60 judge rationales gave the same reason: the
pairs were near-duplicates with nothing to contradict.

The cause was structural. Candidate generation blocked on shared rare tokens,
which optimises for similarity — but contradiction and derivation hold between
claims that differ. A redesign evaluated five new generators offline, at zero
LLM cost: the high-volume one scored 0/10 on hand inspection (its "conflicting
numbers" were arXiv IDs and publication dates), and the only precise one produced
six candidate pairs on one corpus and none on the other.

A control run settled it — judging 15 reasoning edges that already exist
returned recall 7/15. The judge was always working; the candidates were always
wrong.

The REASONING_EDGE_RATIO lint rule stays, and pins the honest baseline: 7.5%
of edges carry reasoning, with contradicts_claim, derived_from,
attributes_improvement_to and criticizes at zero instances.

Upgrading from v0.26.0

Drop-in. If you set TESSERAE_CONTRAST_PASS, it no longer does anything — the
pass is gone.