A statement keeps the document's words - #731
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
…e belonging Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
WaylandYang
force-pushed
the
feat/a-statement-keeps-the-documents-words
branch
from
September 16, 2026 14:15
9ac5458 to
4140233
Compare
This was referenced Sep 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #729. Cut 1 of 0044 (#710): the open graph lands in the ledger and extraction writes only that layer (decision 2). This is the breaking upgrade the record allows: no released version, no legacy layer. The typed extraction path stays as an opt-out per base (
open_extraction = false), which is the optional bound pass of decision 3, kept until alignment reaches parity.Ledger (migration 0061)
facts.layer('typed' | 'open') andfacts.phrase; an open row keeps the document's relation phrase and has no predicate (facts_open_statement_shape). Dedup is on (base, subject, phrase, object), which also closes the NULL-predicate dedup hole of 0010.statement_qualifiers: qualifiers keyed by the document's own role word ("to", "amount", "compared to"), value or entity.time_mentions: the words a statement uses for time, with the char offset in the chunk. Never a computed date; interpretation comes with 0045.fact_evidence.quote_start/quote_end: server-computed char offsets of the quote in the chunk.entities.description: a described, unnamed thing is an entity. It gets noknown_asfact and is excluded from name recall, so a description never bridges two documents.knowledge_bases.open_extraction(default on), settable throughPATCH /kbs/{id}; off selects the typed path.Both clocks:
attested_fromis always set;attested_atcomes from the document date only whendoc_time_sourceiscontentorsource(#714). Open rows write novalid_*.Contract
utopia_extract::open: a prompt with no ontology, no document date and no dates to compute; a compact reply ofethings (name or description, kind word, named/described),sstatements (subject name, phrase, object name or literal value, qualifiers keyed by role word,when/endedtime words, verbatim quote) andnother names. Parsing is per item: malformed items are counted, truncated replies are repaired to the last complete item.Statements name their subject and object in words and carry their own quote. The first version used numeric ids and quote indices to save tokens; measured on a dense earnings-release chunk, the model mixed the ids up ("NVIDIA has reached AI" for "AI has reached its inflection point"). Names fixed it (table below).
Write path
extraction_open::run_open, entered fromextraction::rununless the base opted out or the document is a memory document (memory facts await a nod and have no phrase column yet). It reuses the chunk loop, epoch checks, rate-limit retries, the identity path (resolve_handle, name facts of 0041) and the govern/adjudicate enqueues; it skips the ontology lists, predicate matching, the temporal reconcile, signature checks, type resolution and ontology bootstrap. Names are resolved against the reply's list and the document's earlier things; an unlisted object becomes a literal value with a signal (object_undeclared), an unlisted subject is a drop (unknown_ref). Quotes are located in the chunk (quote_not_in_chunkwhen not verbatim); a time mention is recorded only when its words occur in the statement's own quote (time_not_in_quote), because the model attaches one time to unrelated sentences otherwise.proposed_predicate = phraseis written on the evidence, so every read path that already tolerates a NULL predicate shows an open statement under its phrase. Adoption (proposed_predicates,adopt) is restricted to typed rows so a phrase is never auto-adopted as a relation type; adjudication profiles and disambiguators read open rows through LEFT JOINs.Measured (deepseek-v4-flash extraction; deepseek-v4-pro judges)
Reference units of three domains (10 paragraphs each, reference fact lists from the prototype bench). Six rounds: ids contract (r1); names contract (r2); prompt rule 4 no longer unfolds a bare belonging (r3, r4 same prompt); temperature 0 (r5, r6 same prompt). Columns: statements / judged stated / not stated / stated-fact coverage.
What the rounds say:
NVDA full documents on
scripts/bench/recall.mjs(52 truth items, no ontology in the base): 38/52 with ids, then 44, 46, 45 with names (1σ ≈ 2.7 items). The README's typed baseline (90%+) was measured with a schema.org pack and a different model, so it is not a like-for-like number; the typed path on this branch is unchanged.Tests
an_open_statement_keeps_the_documents_words(phrase shows in overview, entity detail, neighborhood, paths and export; second observation reuses the row; qualifier, time mention and offsets round-trip; not offered for adoption; shape constraint),a_described_thing_is_an_entity_without_a_name,a_time_mention_is_words_not_a_date. Existingno_predicate_still_shows,a_name_is_a_fact,a_qualifier_is_not_the_edges_identity, adjudication and disambiguator tests pass.open.rs. Server: offsets are characters, a time is located inside its own sentence only, names match up to whitespace and case.Bench
scripts/bench/recall.mjsruns the open path by default and--typedthe old one, scoring both with the same rules (qualifiers and time words included), so the two paths are comparable.scripts/bench/judge_open.mjssamples open statements and has a judge model read the chunk: stated / misworded / not_stated, with the 0044 threshold of at most 2% not stated.Not in this cut
Alignment and typed facts derived from open statements (cut 2), time interpretation and document time context (0045), identity profiles, a layer marker in the UI (open rows render as today's unnamed relation), deleting the typed path. Until cut 2 lands, a freshly extracted base holds open statements only: no typed facts, so the conflict and signature queues, timelines and ontology proposals stay empty for it.
🤖 Generated with Claude Code