Skip to content

Merge dev into main - #1045

Merged
WaylandYang merged 88 commits into
mainfrom
dev
Oct 2, 2026
Merged

WaylandYang merged 88 commits into
mainfrom
dev

Conversation

@WaylandYang

Copy link
Copy Markdown
Contributor

Brings main up to date with dev: the 88 commits merged since #915.

Main areas:

  • Readers: Word, slides, spreadsheets, CSV and PDF text are read more faithfully (headings, tables, captions, dates, numbers, merged cells, truncation alerts), and the OCR reader can use Volcengine Ark.
  • Extraction and time: time is read during extraction (ADR 0064), statements are attested by the dates their sections state, and derived rows keep their premises.
  • Ontology: proposed from the open graph and judged by its questions (ADR 0061), with SHACL import fixes.
  • Chat: stop and retry, citations to the sentence a fact was read from, copy actions, stable error codes.
  • Benches and CI: recall, typed and temporal benches; the workflow file is checks.yml.

No version bump and no tag: this is not a release.

🤖 Generated with Claude Code

WaylandYang and others added 30 commits September 26, 2026 05:24
Back-merge main into dev after v0.1.0-rc7
…o end (#928)

A reader could learn the philosophy and the feature list and still not
answer which problem they would bring (#890). Both READMEs gain a Use
cases section ahead of Features: four scenarios in the shape of the
question someone brings, each with its input, what comes back, what the
base adds over search, and its status, drawn from the corpora and
guides already in the repository.

docs/walkthrough.md runs the observations scenario from sample data to
answer with evidence in curl: a class and a functional attribute, a
Statements source, two dated pushes, the phrase meeting the ontology,
the timeline that closes the earlier value, and what the base does not
do. It is the run that #884 and #911 were verified with.

Closes #890

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…t while one is pending (#926)

* Queue phrase alignment after the last kind-word round, and let it wait while one is pending

Kind-word alignment queued phrase alignment at the end of every round,
including a round that had just queued another round of itself because
new words had arrived. On the typed-graph bench the second kind-word
round (562 words) and the first phrase round (1010 signatures) then ran
side by side; the kind words re-bound classes under the signatures, the
signatures' fingerprints changed, and the next phrase round re-decided
713 of them. Two fifths of the phrase decisions were repeats.

Kind-word alignment now queues phrase alignment only from a round that
queues no further round of itself (no new or stale words, and no reask
pending or reasks exhausted). Phrase alignment, whichever entry queued
it, checks for a queued or running kind-word job on its base before it
takes its lock and, if there is one, queues itself for half a minute
later and returns.

Tests: the kind-word reask test asserts that phrase alignment is not
queued while a reask is pending and is queued from the final round; a
phrase test asserts nothing is asked while a kind-word job is queued,
one deferred phrase round exists, and the votes are asked once the
kind-word job is gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

* Record the sequencing fix's two groups and a dev control, and judge 600 facts by default

Two groups on the branch and one on dev at the same hour, same corpus,
model and judge. Signatures are clean (about 1000 transitional "none"
rows gone, phrase decisions 1847 to 980), recall unchanged, tokens
nearly unchanged because the repeated decisions were cheap. With 600
judged facts the branch and dev are indistinguishable (77.2 / 81.8
against 81.7 / 82.0); with 200 the same base scored 70.6 and 81.8, so
--judge now defaults to 600 and the README says earlier precisions are
200-sample figures.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

---------

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: dada-yan <BinjunYann@gmail.com>
… the bottom (#930)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…uous name (#933)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…#938)

The same-KB provenance invariant from 0048 was pinned to migration
0070's table list. The catalog guard's scratch database stopped
migrating at 0070, so every KB-owned table created afterwards was
structurally invisible to it — a table-granularity replay of the
column-granularity blind spot #846 fixed. Single-column foreign keys
on those tables prove a referenced row exists, not that it shares the
referencing row's knowledge base, so implied-fact lineage, rule
signatures, errata records, and rule-definition history could all
anchor across knowledge bases and silently corrupt materialization,
invalidation, and exports.

Migration 0091 reuses the ADR 0048 mechanisms verbatim — no new
abstractions:

* composite same-KB foreign keys on the thirteen edges whose source
  row carries its own kb_id (implication_rules, phrase_readings,
  errata_runs, errata_actions, attribute_rule_versions, and
  derived_facts.attribute_rule_version_id), preserving
  errata_actions.new_fact_id's column-scoped ON DELETE SET NULL;
* an owner-derived trigger on implied_fact_sources, whose KB
  authority is the parent fact's kb_id — the same shape
  typed_fact_sources already used;
* UNIQUE (kb_id, id) support constraints on the three newly
  referenced tables (implication_rules, attribute_rule_versions,
  errata_runs);
* keep_their_kb ownership immutability on the five KB-owned tables
  that lacked it (name_vectors already carried it).

The migration fails closed: a precondition scan counts existing
cross-KB or dangling rows on all sixteen covered edges and aborts
atomically, naming each offending edge, rather than installing the
invariant over a ledger that already violates it.

The catalog guard's scratch database now migrates through the
current chain end instead of stopping at 0070, so future tables can
never become structurally invisible to the guard again. Three edges
that were born protected but never registered
(attribute_rules.join_predicate_id and name_vectors' two composite
keys) join the ledger list and the export preflight scan, which now
checks all 58 protected edges. The provenance-integrity sweep grew
branches for every covered edge so exports still refuse a KB whose
references point outside it.

Regression coverage exercises cross-KB inserts and updates on every
new edge, KB re-anchoring, replica-mode-loaded malformed rows, the
dirty-ledger migration abort with no partial installation, and
installation under empty, hostile, and normal search paths.

Signed-off-by: Anson <310461893+ansonnmm@users.noreply.github.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…ose inputs moved is not accepted (#932)

* Record the inputs a kind-word decision considered, so an edit made while the model answers is asked about again

Signed-off-by: dada-yan <BinjunYann@gmail.com>

* Document the kind-word basis in 0053 and the ontology design

Signed-off-by: dada-yan <BinjunYann@gmail.com>

* Merge dev after #938; the schema version counts 0091 and 0092

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

---------

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…922)

* Export what is contested: fact conflicts and axiom violations in RDF (#564)

The export carried the assertions but not the epistemic state Utopia has
already established about them — a downstream consumer had to reimplement
conflict and violation detection to know which statements are contested.

Two distinct resource classes per ADR 0062:

- FactConflict: the prior and incoming statements on a disputed slot, with
  status, resolution, and truthful timestamps (a withdrawn row's closedAt is
  the invalidation moment, not a page open).
- AxiomViolation: the statements the finding is about, an ordered rdf:List
  for cycle evidence, status/resolution, and — for open rows only — the
  governing criterion and the relation it lives on.

Precondition is the current-ontology invariant: status = open means the
finding has been reconciled against the current ontology. Criterion-changing
ontology edits (axiom flags, temporal, inverse_of/sub_property_of,
domain/range, class parent hierarchy, deleting a referenced class or linked
relation) now settle superseded open rows as criterion_changed and re-detect
in the same transaction; criterion_changed is system-generated and stays
outside the human review vocabulary. Label-only edits skip detection.

Export stays read-only inside the existing REPEATABLE READ snapshot; no
lazy cleanup or detection is triggered. Cross-KB or unresolved references,
and open violations without a resolvable criterion, refuse the export.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

Follow-up from review: ontology import now captures the pre-import
detection baseline and reconciles after apply (same criterion_changed
semantics as interactive edits; a failed reconciliation errors instead of
reporting violations: 0). A contested-state preflight refuses the export
before the first byte when referenced facts are foreign/dangling, storage
values fall outside the contract vocabulary, or an open violation's
criterion cannot be resolved — including a malformed derived_contradiction
detail.predicate_id, which no longer falls back to the asserted fact's
predicate. signature maps to rdfs:domain + rdfs:range per the ADR.

Second review pass: reconciliation now partitions stale rows by row
identity, not stored evidence — non-cycle kinds compare (kind, left,
right) like their unique index, so a drifted evidence path can no longer
demote a baseline finding from criterion_changed to deletion. A failed
import still reconciles against the already-committed criteria
(best-effort, original error preserved). Preflight additionally rejects
status↔resolution-inconsistent rows; duplicate onStatement for
self-pointing findings is deduplicated; two more store tests pin
evidence-drift partition and sub_property_of unlinking.

* Bump CURRENT_SCHEMA_VERSION to 79 for migration 0081

The backup manifest compatibility constant is the count of migration
files, guarded by schema_version_policy_compares_against_current.
0081 added a file without bumping it (78 != 79).

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* DCO Remediation Commit for Anson <310461893+ansonnmm@users.noreply.github.com>

I, Anson <310461893+ansonnmm@users.noreply.github.com>, hereby add my Signed-off-by to this commit: 67d36a9
I, Anson <310461893+ansonnmm@users.noreply.github.com>, hereby add my Signed-off-by to this commit: c876303

Signed-off-by: Anson <310461893+ansonnmm@users.noreply.github.com>

---------

Signed-off-by: Anson <310461893+ansonnmm@users.noreply.github.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
ghcr.io/deeplethe/utopia has been amd64 only (0.1.0-rc7 and earlier carry
a single linux/amd64 manifest), so `docker pull` on Apple Silicon or
Graviton fails with "no matching manifest for linux/arm64/v8", and forcing
--platform linux/amd64 runs the server under emulation.

The release workflow now builds each platform natively on its own runner
(ubuntu-latest for amd64, ubuntu-24.04-arm for arm64, free for public
repositories), smoke-tests both, pushes each by digest, and a final job
assembles the manifest list and applies the tags, following the
docker/build-push-action multi-platform guide. Tags only move once both
platforms have passed the smoke test. The GHA build cache is scoped per
architecture. QEMU is not used: a Rust release build with thin LTO takes
over an hour emulated and about five minutes native.

The Dockerfile needed no change. Verified locally with
`docker buildx build --platform linux/arm64` on an arm64 Colima VM (cargo
step 310 s); the image booted against a fresh database, ran all 78
migrations, answered /api/v1/health and registered a user.

README (both languages) now states the published platforms. The change
takes effect on the next tag; docker-compose.yml still pins 0.1.0-rc5,
which is amd64 only, so the Quick start works on arm64 hosts once that
pin moves to the first multi-arch tag.

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…lease moves it (#944)

docker-compose.yml defaulted UTOPIA_IMAGE to 0.1.0-rc5 since #333, and
neither rc6 nor rc7 moved it, so the README's one-command start ran a
build three weeks behind the release. The pin points at rc7; both
contributing guides now list moving the pin as part of cutting a
release, next to the back-merge rule, and say why arm64 hosts wait for
the first multi-arch tag.

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…its questions (#945)

0044 cut 5 as a record. Competency questions become rows of the base
and the standard an element is judged by; an ontology agent reads the
unbound signatures and classless kind words against them and proposes
types, properties and rules with a definition, the statements they
would bind and the questions they serve; approval writes the element
with its structure and re-decides those signatures through 0053's
basis; every approved element carries regression cases rerun when its
definition changes. Measured by questions answered correctly and by the
share of proposals people change. No automatic adoption; the 0003
Suggest path retires once this replaces it.

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…ons: cut 1 (#947)

* The ontology is proposed from the open graph and judged by its questions: cut 1

ADR 0061 cut 1. A base can say what it is for: competency questions are
rows (`competency_questions`, migration 0077), a person writes them and
they are accepted on arrival. An ontology agent reads the phrase
signatures alignment decided bind to nothing and the kind words with no
class, against the glossary and the accepted questions, and proposes
classes and properties with a definition, the shapes they would bind and
the questions they serve. Proposals land in `ontology_proposals`
(`proposed_by = 'agent'`, `serves`, `signatures`) beside Suggest's;
shapes already proposed are not offered again. Adoption writes the
element through the same store calls the editor uses, marks the
proposal, and enqueues alignment so the shapes re-decide on their 0053
fingerprints. Rejection records a reason. Alignment calls the agent when
it settles with twenty or more unbound shapes; the ontology page has
"Ask the agent", the agent's fields on each proposal, Reject, and a
competency-questions panel.

Batches are twelve shapes plus up to six kind words per call with the
glossary once per batch; a round is capped at 120 shapes. Nothing is
adopted automatically (0012).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

* ADR 0061 and the index record that cut 1 landed in #947

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

---------

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…matches (#940)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…t their limits (#941)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…ology becomes a proposal: 0061 cut 1.1 (#950)

* The agent remembers what it has seen, and "already in the ontology" becomes a proposal

ADR 0061 cut 1.1, from the first real round (bench4, 100 documents, #947):
120 shapes went to the model, 35 came back in proposals, and the other 85
had no record, so the next round would have offered the same shapes first
and spent seven tenths of its tokens on them. The shapes with the most
statements (died in, wrote, directed, is in) were answered as "the
ontology already has this" (placeOfDeath, author, director, locatedIn),
and cut 1 dropped that answer.

Every shape offered is now recorded in `ontology_agent_reviews`
(migration 0078) with its outcome: proposed, existing or declined, and
the glossary fingerprint it was judged against. Proposed shapes are never
offered again; existing and declined ones return when the glossary
changes. An "existing" answer is saved as a `map_to` proposal with the
property, the direction the shape reads it in, and the shapes; adopting
it writes a person's binding per shape (the same call as the review
queue) or classes each kind word, and enqueues the projection. The prompt
asks for the direction and says not to propose the inverse of an existing
property. The ontology page shows the agent's map_to items with their
shapes and a Reject.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

* Direction belongs to the shape, a declined shape returns when its statements double, and adoption embeds the element

Three more things the real base showed (bench4, rounds 2 and 3):

Two answers for one existing property in two rounds overwrote each other
(p1056 lost "was long a center of" to "continued to produce"), and the
direction they disagreed on was per shape, not per property. A map_to
row now merges across rounds and each shape carries its own direction;
adoption reads it per shape.

Re-offering declined shapes whenever the glossary changed would resend
every declined shape after every adoption (165 shapes, a dozen calls).
Alignment already re-decides unbound shapes against a new element on its
0053 fingerprint, so the agent has nothing to add there. A declined shape
now returns only when its statement count has doubled since it was seen.

An adopted property never entered the alignment shortlist: the shortlist
is picked by vector when a shape has many structural candidates, and a
new element has no vector until something refreshes the index. Adoption
now refreshes the ontology index before enqueueing alignment. On the
bench base this bound the adopted `houses` and four neighbouring
phrasings within a minute, and caught up the five "is bordered to the …
by" shapes left unbound by the earlier `bordered_by` adoption.

Also: map_to items carry the target's label, the page no longer shows
0003's "reclassifies N facts" on agent items, and "Add all" counts only
Suggest's proposals (an agent proposal is signed one at a time, 0012).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

* ADR 0061 and the index record cut 1.1 (#950)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

---------

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…etween found no path (#948)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…ist in place while a search loads (#949)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…, and send the turn back once (#946)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
… in the reader's language (#951)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
…ment repeats (#953)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
… marks (#952)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
… page has no Clipboard API (#954)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…gy is measured by two numbers: 0061 cut 3 first slice (#955)

* The agent proposes questions for a base that has none, and the ontology is measured by two numbers

ADR 0061 cut 3, first slice. Three real rounds of the agent on the
Re-DocRED base showed why decision 1 matters: with no questions the agent
judges only by what documents say, and after the first 120 shapes its
proposals drift to one-off phrasings. The standard was missing.

A base with no questions gets them proposed (decision 1): the job
`propose_questions` shows the model what the open graph says most (the
forty most frequent shapes with the property each binds to, the twenty
most frequent kind words, the twenty most connected entities), the
ontology, and the questions already written, and asks for up to ten
competency questions with the classes and properties an answer must
traverse; keys the ontology lacks are dropped from `needs`, since that gap
is the point. They arrive `proposed` and a person accepts, edits or
rejects them on the workbench. The ontology agent runs this first when a
base has no question of any status.

Two numbers (decision 5). `competency_questions` records how each
accepted question last went; `ontology_proposals.edited` (migration
0079) records that a person changed a proposal before adopting it.
`GET /kbs/{id}/questions/report` returns questions answered over
checked, and agent proposals changed or rejected over decided; the
workbench shows both. The asking is done by `scripts/bench/competency.mjs`
the way a person asks, through the chat endpoint, judged against the
expected answer by a model or, without one, by whether the shape the
question needs exists and holds facts; it writes each result back through
`POST /kbs/{id}/questions/{qid}/result`. The server does not ask on its
own: chat has no in-process entry point, and decision 6 keeps chat as it
is.

On the bench base: eleven written questions, 11 of 11 answered (two need
the adopted `bordered_by` and `p40`); the agent's ten proposed questions
each name existing properties and connected entities.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

* ADR 0061 and the index record cut 3's first slice (#955)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

---------

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
… a class or property, before alignment runs (#956)

The four editor handlers (create and update for classes and for
properties) wrote the element and enqueued `align_types` or
`align_phrases`, but nothing refreshed the ontology vector index. The
phrase aligner picks its shortlist by vector whenever a signature has
more than ten structural candidates, and the kind-word aligner retrieves
candidate classes by vector, so an element without a vector never
reached the model; the 0053 fingerprint of the shapes it could bind did
not change and they were never re-decided. Only OWL import, bootstrap,
type resolution, build_proposals and (since 0061 cut 1.1) the agent's
adoption refreshed the index; the `bordered_by` case on a real base was
this gap on the adoption path, and the editor had the same one.

The handlers now share one step: queue `embed_ontology` with a two
second debounce, then the alignment job with its existing five second
one. The embed job is deduplicated against queued copies only
(`enqueue_unless_queued_after`), not running ones: a refresh already
running has read its stale set and cannot see this edit, so a second
copy must follow it. A changed label or description is covered without
any extra bookkeeping, because the index judges staleness by comparing
the stored text with label plus description.

The debounce alone does not order the two jobs, so both aligners now
wait while an `embed_ontology` job for the base is queued or running,
the way the phrase aligner already waits for the kind-word round: they
re-enqueue themselves thirty seconds later, at most one queued copy. The
order is therefore vectors, then kind words, then phrases. This also
covers OWL import, which queues the same job.

Tests, scripted model and real Postgres: a property created through
`create_relation_type` leaves the embed job queued ahead of the
alignment, the alignment defers without a model call while it is
pending, the property is in the vector table once the job body has run
and the model is then asked with it among the candidates; an update that
changes the description queues the refresh again and re-embeds exactly
that row. The kind-word aligner has the matching wait test.

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…tch needed the repair (#919)

gemini-3.5-flash through an OpenAI-compatible gateway writes a raw newline inside a
quoted reason. serde refuses it ("control character (\u0000-\u001F) found while
parsing a string"), the adjudicate_entities job retries three times on the same
reply, and the whole batch is marked failed; on a 100-document Re-DocRED base 2903
resolution_reviews stayed pending.

utopia-extract: parse_adjudication_repairing tries serde first; on failure it
escapes bare control characters inside string literals (\n, \r, \t, \u00XX) and
parses again, returning whether the repair was needed. parse_adjudication keeps
its signature and output. Newlines between tokens are untouched; \" does not end
a string; already-escaped sequences stay as they are.

utopia-server: adjudication.rs and governance.rs use the repairing parser and log
a WARN with the kb (and run) id, the batch size and the first pair's names when
the fallback was taken, the way #894/#895 report a reshaped alignment reply.

Tests: a well-formed reply is not repaired and reads the same as before; a reply
with a raw newline and a raw tab inside "reason"/"why" strings parses with the
newline kept in the reason; the escaper only touches control characters inside
strings.

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…ge, and let a query step carry its SQL, rows and failure (#957)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…PI, and say when a copy fails (#959)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
* Speed graph rebuilds by indexing foreign key lookups

Signed-off-by: Jun Du <dujun@tib.cas.cn>

* Index every foreign key onto entities and facts in one plain migration

Maintainer edits on #958. The repo has never used CREATE INDEX CONCURRENTLY in a migration:
sqlx wraps each migration in a transaction and the tenancy ledger test replays them the same
way, so the fifteen no-transaction files failed there. The same indexes, plus the eleven
references the PR left out (derived_facts, pending_facts, rejected_facts, fact_qualifiers,
fact_conflicts, axiom_violations, concept_mappings), are now one migration of plain
CREATE INDEX IF NOT EXISTS statements; the two nullable columns are indexed only where they
reference something. CURRENT_SCHEMA_VERSION is 85.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

---------

Signed-off-by: Jun Du <dujun@tib.cas.cn>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
Maya-Kid and others added 27 commits September 29, 2026 12:45
…#997)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…ed end names (#993)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…re (#1001)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…eeps it out of the table (#1014)

A round whose extraction failed chunk by chunk (the endpoint down for the whole
round) ends with an empty queue, so the settle wait is satisfied at once and the
record carries settled=true with a score of 0. --table then pulls it into the
group means. The record now says complete=false when the extracted count is
below the chunk count; --table leaves such rounds out of every group and names
them under the table. Records from before this change are judged by their
per-document counts.

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…em by item (#1011)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…e moment it was computed (#1012)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…nd ligatures that look like them (#1013)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…e Ark vision model read in one pass (#1015)

* The OCR reader chooses its provider: MinerU as before, or a Volcengine Ark vision model read in one pass

Scans and images can now be read by an Ark vision model beside the
MinerU service. llm_settings gains ocr_provider (default mineru) and
ocr_model; a key stays with its provider and is cleared when the
provider changes, in one SQL statement. The Ark path sends an image
whole, renders a PDF page by page with Poppler, asks the model for the
written text of each page as JSON, retries a page that hit a rate limit,
a timeout or a server error three times inside the pass, and builds the
same Reading as MinerU. Nothing is remembered between passes: a failed
pass re-reads every page on the document's ordinary retry. ADR 0065.

The prompt, the probe image, the URL rules and the Poppler subprocess
handling come from Fonna's implementation in #1007, which this narrows.

Co-authored-by: Fonna <jiangpeng274@outlook.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

* The Ark OCR migration moves to 0102: 0101 landed with #1012

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

* 补齐方舟 OCR 的响应上限、配置兼容与验收 (#1016)

* 修复方舟 OCR 的响应读取上限与旧客户端配置兼容

在读取响应时执行大小上限,复用现有代理规则。省略供应商的旧请求保留已有配置,显式切换仍隔离密钥。补充整篇重读、空白页页码和真实接口验收,并更新 Agent Plan 地址提示与设计说明。

Signed-off-by: Fonna <jiangpeng274@outlook.com>

* 补强扫描原文验收并处理测试替身的部分读取

Signed-off-by: Fonna <jiangpeng274@outlook.com>

---------

Signed-off-by: Fonna <jiangpeng274@outlook.com>

* The README says which readers scans, images and recordings go to

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

---------

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Signed-off-by: Fonna <jiangpeng274@outlook.com>
Co-authored-by: Fonna <jiangpeng274@outlook.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Fonna <35397279+Fonna@users.noreply.github.com>
…day count (#1017)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
…iling to what the window leaves, and history trimming leaves a list shorter than the stored history unchanged (#1021)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…th a heading keeps its last chunk (#1026)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…h the chunks and each section is dated by its own date (#1018)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…1019)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…val failures (#1027)

Signed-off-by: Floating-Y <118035379+Floating-Y@users.noreply.github.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…d draws it (#1020)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
… asks (#1041)

CI installs stable Rust, which moved from 1.98.1 to 1.99.0 on 2026-10-01.
Its clippy rejects the borrowed closure in the chunker's caption run
(needless_borrows_for_generic_args), so every pull request fails lint
the next time its checks run. The closure captures only a reference and
is Copy; behaviour is unchanged.

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…numbers on either side of it stay apart (#1031)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…l keeps, not the binary tail of a computed value (#1032)

Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
Signed-off-by: dada-yan <BinjunYann@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…1037)

Signed-off-by: Yi-111-a <153097222+Yi-111-a@users.noreply.github.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
* A merged spreadsheet cell fills every row and column it covers

Signed-off-by: Harbor404 <2657212322@qq.com>

* Keep the newer stable Clippy happy

Signed-off-by: Harbor404 <2657212322@qq.com>

---------

Signed-off-by: Harbor404 <2657212322@qq.com>
* Keep every interval of a triple alive through axiom steps

The derivation frontier and reached set used only predicate, subject and object as identity. When two facts had the same triple over different validity intervals, the second proof was discarded before later schema axioms could use it. Key assertions and derived facts by the triple plus both interval ends, and order the frontier by that same identity so the temporal closure does not depend on input order. Add a regression covering the inverse-then-transitive reproduction in both orders.

Signed-off-by: Harbor404 <2657212322@qq.com>

* Drop derived intervals covered by a wider span

An asserted or already reached span now suppresses a derived interval only
when it contains the candidate. Non-overlapping or incomparable intervals
still stay, and the three reviewer examples are covered by regressions.

Signed-off-by: Harbor404 <2657212322@qq.com>

---------

Signed-off-by: Harbor404 <2657212322@qq.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…ptions (#1038)

* A Word paragraph ends a Markdown block, so split tables keep their captions

Signed-off-by: Harbor404 <2657212322@qq.com>

* Remove a needless borrow so the caption loop passes current clippy

Signed-off-by: Harbor404 <2657212322@qq.com>

---------

Signed-off-by: Harbor404 <2657212322@qq.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
* A capped spreadsheet or CSV says what was left out (#1022)

* A parse warning carries its own detail instead of a provenance

A provenance says where text came from. A truncation warning says what was
left out, so it carries a plain detail value and the alert stores that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>

---------

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Wayland Yang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
@WaylandYang
WaylandYang merged commit 9ba1413 into main Oct 2, 2026
12 checks passed
@WaylandYang WaylandYang mentioned this pull request Oct 2, 2026
Floating-Y pushed a commit to Floating-Y/utopia that referenced this pull request Oct 2, 2026
Brings main's merge commit of deeplethe#1045 into dev so dev is up to date with main.

Signed-off-by: Wayland Yang <wayland0916@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants