Skip to content

Release: dev into main - #717

Merged
WaylandYang merged 140 commits into
mainfrom
dev
Sep 15, 2026
Merged

WaylandYang merged 140 commits into
mainfrom
dev

Conversation

@WaylandYang

Copy link
Copy Markdown
Contributor

Merges dev into main (139+ commits since #478). Includes, among others, the chat loop on rig (#548), names as facts (#670), the temporal engine rework (#679), OIDC single sign-on (#684), written dates (#689), second-precision connector timestamps (#691), the Databricks schema fallback (#702), reasoning-model replies (#707), clearer Models cards (#708), the entity names panel (#711) and the extraction progress fix (#715).

Not included: #699 (held after review), #710 (record being rewritten), #712 and #713.

No tag in this release.

🤖 Generated with Claude Code

WaylandYang and others added 30 commits September 8, 2026 09:22
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…nel shows (#480)

* Classes, properties, attributes and knowledge edit in dialogs; the panel shows

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

* Groups fold, entries are rows, the hover card is a tooltip, every edge kind fans out

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

* Only the Danger zone icon carries the warning colour

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

* Relations reads From and To, the past folds in place, evidence is a source count

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

* The entity panel's rows carry the direction arrow, as on the ontology page

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

* A fact is one row: the relation on the left, the entity on the right

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.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>
Three records were written as 0026-0028 on three branches on the same day. By the order the pull requests were opened, the adjudication stack (#473-#475) keeps 0026-0028, the rules stack (#484, #485) becomes 0029 and 0030, and the event record (#487) becomes 0031.

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* A decision records why

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

* An automatic merge is gated by what it can undo

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.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>
* The import history shows what each import actually did

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The import history does not say empty while it is loading

Signed-off-by: WaylandYang <wayland0916@gmail.com>

* One import is one line

Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* The rule editor opens; only saving waits for a condition

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* Rules read as a table, and a rule is written in a dialog

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The rules page has a search, on the same row as its buttons

Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* A rule may say or, once

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The rule sentence says or where the rule says or

Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The rule editor writes blocks

Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The or record takes the number dev left open

Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* A rule may read what a rule concluded, written down

Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A rule reads what a rule concluded

Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The chaining record takes the number dev left open

Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
…n down (#523)

* A Chinese name does not stop the queue

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* One knowledge base adjudicates one at a time

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A table keeps its rows

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A stated figure is written down

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The ontology offers what a class can have

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A value finds its subject the way a relation does

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A role is a fact, and a spacer column is not

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A blank header row gives way to the real one

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A list of names is a list of facts

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A bench that asks whether the document made it into the graph

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* Extraction waits for the ontology it is about to search

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* cargo fmt

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
* A rule computes what it concludes, written down

Signed-off-by: WaylandYang <wayland0916@gmail.com>

* Aggregation is refused for what it claims, not for retirement

Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
* An operand and a conclusion can be an arithmetic tree

Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A rule computes what it concludes

Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* The schema diagram draws the biggest classes, and reads lighter

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The class count has no stepper

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
(cherry picked from commit fe5ac50119a38553a947557e87aec8eb045a9ebc)

* The name you point at reads like the name you picked

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The node you picked keeps its mark while you point at it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A hovered name is painted once

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* The ontology reads as three tables

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The rail switches between the diagram and the tables

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* A fact row leads with the fact

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* Evidence expands to something you can read

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* A fact row reads as a sentence

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
(cherry picked from commit 8b3a6cd5f83532e9da405851829c5b3133191631)

* A floating panel does not borrow the colour behind it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The class legend opens like every other panel

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A switched-off class is struck through, not just faded

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* Record source-scoped RSS summaries

Signed-off-by: danwood <118035379+Floating-Y@users.noreply.github.com>

* Scope RSS summaries to the source being listed

Signed-off-by: danwood <118035379+Floating-Y@users.noreply.github.com>

* Record 0026 becomes 0033

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

* A source list counts only the listed source

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

---------

Signed-off-by: danwood <118035379+Floating-Y@users.noreply.github.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* fix(store): wake workers when jobs are queued

Publish transactional PostgreSQL notifications for new and immediately requeued jobs so idle workers do not wait for the polling interval.

Closes #517

Signed-off-by: RKS <rajesh.sharma@owasp.org>

* The idle wait is one function, and it sleeps when the listener fails

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

* A queued job wakes an idle worker, and not before its row

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

---------

Signed-off-by: RKS <rajesh.sharma@owasp.org>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* The web app gets a unit-test runner

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

* A query stays fresh for as long as its key says

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.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 Opus 5 <noreply@anthropic.com>
* The ontology page renders before the ontology arrives

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The graph page waits the same way the ontology does

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* Selecting a class goes straight to its highlight

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A property with no classes does not dim the whole diagram

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
WaylandYang and others added 28 commits September 13, 2026 21:02
* The chat loop runs on rig

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

* rig comes without its provider clients

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

* The prompt says what the base is

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

* 0042 records that the chat loop is a runner with hooks

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* A period is when a fact holds, and a unit leaves the value it was read from

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

* A period is neither subject nor entity

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* Shape checks read structure, not words

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* An empty cell with a period after it is still empty

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A corporate form is left to identity, not to a word list

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A shape check keeps what it cannot tell apart

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* 0041 records that a name is a claim about an entity

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* 0041 settles that a name is a value fact and never a node

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The identity bench measures merges and splits in both arrival orders

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The identity bench pins an anchor to the fact its sentence is about

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* 0041 records what cut 1 measured and where it revised decisions 2 and 5

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* Schema columns carry primary-key, foreign-key and nullability flags (#502 cut 1)

explore_mappings tells the model 'table X has these columns' and currently
the model has no way to tell an ID column from a measure on a wide table
(the 80-column TPC-H case in #502: proposal coverage 25%, the
seven-query core revenue metric dropped because nothing in the schema
said which column was the key).

Adds four flags to SchemaColumn and surfaces them in the schema text the
explorer prompt receives:

  * is_primary_key     single-column PRIMARY KEY only; composite members
                       stay false so the prompt does not mistake them
  * is_foreign_key     the column itself is an FK
  * references_table   <schema>.<table> the FK points at
  * nullable           false for any NOT NULL column (PKs included)

This cut lands Postgres end-to-end (catalog query + mapping consumer +
three live tests gated behind UTOPIA_TEST_DATABASE_URL). MySQL, Trino,
Snowflake and Databricks get the new struct fields with default-false
so the workspace compiles, but their catalog queries are deferred to
per-engine cuts (#502 cuts 2..5). Databricks intentionally stays
is_primary_key=false across the board because Unity Catalog does not
register PK/FK.

Tests added (env-gated, all pass against postgres://localhost:1517):

  * a_primary_key_column_is_marked_and_not_null
  * a_single_column_foreign_key_carries_its_target
  * a_composite_primary_key_member_stays_unmarked

The prompt format adds ' -- PK' / ' -- FK ->schema.table' / ' -- NOT NULL'
markers after the existing comment, preserving line order so existing
tests stay green.

Signed-off-by: rollroyces <rollroyces@users.noreply.github.com>

* Keys come from pg_catalog, and a lookup that fails leaves the columns

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: rollroyces <rollroyces@users.noreply.github.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: rollroyces <rollroyces@users.noreply.github.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…670)

* 0041 records that a name is a claim about an entity

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* 0041 settles that a name is a value fact and never a node

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The identity bench measures merges and splits in both arrival orders

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The identity bench pins an anchor to the fact its sentence is about

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* 0041 records what cut 1 measured and where it revised decisions 2 and 5

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A name is a fact, and the extractor reports the other names it reads

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A name another entity already has sends the pair to the adjudicator

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The adjudicator sees an entity's other names

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A name already declared for another entity is not an alias

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A name keeps to its own path: decided pairs stay decided, the attribute stays builtin, a memory waits for a nod

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A name lookup stays inside its base

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* 0041 carries the cut-1 numbers measured on DeepSeek-V3

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* Schema columns carry PK/FK on MySQL/MariaDB (#502 cut 2)

follows #671 (now merged with revisions). The struct change lands in
#671 — this PR adds the MySQL implementation only, against the new shape
(is_primary_key: bool, references_table: Option<String>). Drops the two
fields (#671 cut: is_foreign_key, nullable) that the maintainer
explicitly removed for not being used by the explore prompts.

keys() helper mirrors postgres.rs's pattern:

  * single-column PRIMARY KEY from information_schema.statistics with the
    same composite-PK guard Postgres uses (index column count = 1)

  * single-column FOREIGN KEY from information_schema.key_column_usage with
    ORDINAL_POSITION = 1 + composite-FK guard (a column appears in
    key_column_usage once per FK constraint it's part of; without the
    composite guard, both members of a composite FK get marked)

  * UNION ALL on a five-column shape with NULL placeholders on the PK
    side, because sqlx's query_as wants a uniform tuple. PK and FK rows
    are distinguished in the merge loop by whether the FK target columns
    are NULL

  * Graceful degradation on the same line as #671: a failing keys()
    returns an empty Keys + a tracing::warn, leaving the columns without
    key marks rather than failing the whole fetch_schema call. The
    read-only role test exercises this on MySQL — same permission issue
    as PG (information_schema constraints are empty for SELECT-only
    users), same fix shape.

fetch_schema keeps its existing CAST(... AS CHAR) treatment — MySQL 8.0
binary protocol reports VARCHAR columns in information_schema as
VARBINARY, sqlx strict-typed decoding refuses to read them as String.

Three live tests gated on UTOPIA_TEST_MYSQL_URL, mirroring the
maintainer's three Postgres tests:

  * a_single_column_key_is_marked_and_a_composite_one_is_not_mysql
    — single-column PK and FK both marked; both members of a composite
    PK and a composite FK stay unmarked

  * a_foreign_key_points_at_its_own_target_mysql
    — self-referencing FK resolves correctly; cross-database FK
    resolves correctly; the PK on a table whose FK name collides with
    another table's PK stays marked as PK (not as FK)

  * a_read_only_login_still_sees_the_keys_mysql
    — a SELECT-only role still gets the PK/FK marks. information_schema
    reads succeed for SELECT roles (per #671 followup), but the test
    gracefully skips if CREATE USER / GRANT fail.

Fx test harness mirrors postgres.rs's: per-test schema with random uuid
suffix (CREATE DATABASE here — MySQL's 'schema' is 'database'), no
Mutex for parallel safety, SET FOREIGN_KEY_CHECKS = 0 around cleanup
so cross-database FK cleanup doesn't fight the drop order.

Verified locally against mysql:8.0 on 127.0.0.1:13306 with
UTOPIA_TEST_MYSQL_URL set: 269 passed, 1 failed (pre-existing
a_live_server_answers_with_typed_values needs the sales.orders fixture
from #316; not a regression). My new tests all pass; no regressions to
existing tests.

Signed-off-by: rollroyces <rollroyces@users.noreply.github.com>

* MySQL keys are counted once per view, and the tests leave nothing behind

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: rollroyces <rollroyces@users.noreply.github.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: rollroyces <rollroyces@users.noreply.github.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The entity panel's 'blocked' key is asked alongside derived, facts,
and same_name, all of which already carry as_of through entity_detail.
blocked_for_entity hard-coded 'v.status = ''open''', so a violation
detected in March and closed in April still haunted the rewound panel.

Wire as_of through blocked_for_entity and the entity panel callsite.
violation_open_at is the same shape as derived_held_at / facts_held_at,
with a different clock (detected_at / decided_at). Write paths
(decide_violation, retract_from_violation, etc.) keep the existing
status filter — 0019.

Test (DB-backed, UTOPIA_DATABASE_URL-gated):
- still_open: detected 3 月, never resolved
- resolved: detected 3 月 20, resolved 4 月 15

回看 Mira 的 blocked:
- 当下:still_open 一条
- 2 月:都未检出 → 0 条
- 3 月 25 日:resolved 在 decided_at 之前还开着 → 2 条
- 5 月:resolved 在 decided_at 之后消失 → still_open 一条

The two violations cross over between 3 月 25 日 and 5 月 — without
as_of the same two rows always return just still_open today.

cargo check -p utopia-store -p utopia-server clean. cargo fmt
clean. cargo clippy -p utopia-store -p utopia-server --all-targets
-- -D warnings clean. cargo test -p utopia-store --test
blocked_for_entity_respects_as_of passes; the existing
a_contradiction_points_upstream test still passes after passing
None to the new signature.

Signed-off-by: Royce <roycelam@umich.edu>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
* Same-name peers follow the recording axis (#307)

The same-name list on the entity panel is asked from the panel
that already forwards as_of to entity_detail. same_name_peers
hard-coded 'e.merged_into IS NULL', so a Zhang Wei merged in March
stayed invisible at every as_of, and the panel could only ever
report today's same-name collisions.

Wire as_of through same_name_peers and the entity panel callsite.
The write-side callers (update_entity, which always means today)
pass None explicitly so their behaviour is unchanged.

Test (DB-backed, UTOPIA_DATABASE_URL-gated):
- zhang_wei_a: 1 月记下事实,3 月合并进 zhang_wei_b
- zhang_wei_b: 1 月记下事实,从不合并(查询的锚点)
- zhang_wei_c: 5 月记下事实,从不合并

回看 b 的同名:
- 当下:c 一条
- 2 月:a、c 两条
- 4 月:c 一条
- 6 月:c 一条

a 在 2 月回到同名列、3 月合并后消失——没有 as_of 时 a 永远不在。
c 一直都在(5 月创建,在所有 ≥ 5 月的时刻数 1 条)。

cargo check -p utopia-store -p utopia-server clean. cargo fmt
clean. cargo clippy -p utopia-store -p utopia-server --all-targets
-- -D warnings clean. cargo test -p utopia-store --test
same_name_peers_respects_as_of passes.

Signed-off-by: Royce <roycelam@umich.edu>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* A merged peer is counted by who held its facts at the time

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: Royce <roycelam@umich.edu>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…act format (#680)

* A chunk reads the opening of its document

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A date keeps the contract format when a literal keeps its units

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The opening is the document's first live chunk, and a quote from it is not evidence

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* An obligation belongs to the agreement that imposes it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The point-search box on the graph page already passes as_of from
the time slider, but search_entities hard-coded node_sql(None, None)
in its degree subquery: a fact corrected in March still counts
toward a node's degree at every as_of, so the dropdown's numbers
disagree with the canvas they're meant to be picking from.

Thread as_of through graph::search_entities. NULL is unchanged
(today's degree); Some(t) hands the subquery the held_at predicate
plus a bound parameter. Tool callers (chat / MCP) keep passing
None so their behaviour is unchanged.

Test (DB-backed, UTOPIA_DATABASE_URL-gated):
- alpha: 1 live fact, no retraction. degree stays 1 at every as_of.
- beta: Jan fact, retracted March, new fact recorded May.
    Today degree=1; Feb degree=1 (old fact alive); Apr degree=0
    (retracted + not yet re-recorded); Jun degree=1.

The two cross over between Apr and Apr — without as_of the same
two rows always return degree=1 each.

cargo check -p utopia-store -p utopia-server clean. cargo fmt
clean. cargo clippy -p utopia-store -p utopia-server --all-targets
-- -D warnings clean. cargo test -p utopia-store --test
search_entities_degree_respects_as_of passes.

Signed-off-by: Royce <roycelam@umich.edu>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* Add single sign-on (OIDC)

A narrow OIDC authorization-code flow (PKCE, one-use state, nonce,
issuer/audience and RS256 verification), off by default and enabled
only once all four UTOPIA_OIDC_* variables are set. Accounts must be
explicitly linked by an administrator on a new Administration >
Single sign-on page; a subject that has never been linked is refused
at callback rather than silently provisioned.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136c4gq3BDppPhcWcRdy5MJ
Signed-off-by: Nafeeur Rahman <hello@nafeeur.nyc>

* An identity is linked by its owner, and a refusal says why

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: Nafeeur Rahman <hello@nafeeur.nyc>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
* A value that arrives late takes its place in history

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A value with no start ends where the next known one begins

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A timeline is placed whole, under one lock, whatever the order its values arrive

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A deadline relative to an event is kept as written and still ends the one before it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* Rule 8a points a relative deadline at rule 10's flag

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* An end the engine drew moves with what follows it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A row on two timelines ends at the earlier side, and the engine keeps what people and texts said

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A chained revert brings facts home, a large deletion locks by predicate, and a read start follows its anchor

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* A date the text spells out is read as a date

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The interval ends and literal check read written dates, with tests

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* Every prompt rule has its own number

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* A Databricks schema read falls back to the system information_schema, and a failed sync stops hiding the engine's error

Signed-off-by: Qishang Zhong <zhongqishang@gmail.com>

* A schema read falls back only when the table is missing, and an empty fallback is a failure

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: Qishang Zhong <zhongqishang@gmail.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* Connector timestamps carry an instant precision beside day

#610 提案的第一刀。一个来源可以在 config 里写 "precision": "instant",
连接器就把 created_at / updated_at 写成完整 RFC 3339(与 #351 后
change_line 用的同一形式),下游 facts.valid_from_precision 跟着变成
"second"。缺省仍是 day,旧来源的形状不变。

四件事:

- Source::precision() 读 config.precision,缺省 day,typo 不翻转
- time_text::world 接受 Some("instant"),输出与无精度路径一致但语义
  不同——给抽取器的精度字段是 second,不是 day
- github_issues::render_with 接 precision 参数,render() 保持 day 精度
  作为旧别名
- ingest_sources::sync_github_issues 把 source.precision() 传给 render_with

测试:721 个全过,3 个新加(time_text 的 instant 路径与跨午夜回归,
models 的 precision 默认与 typo 政策,github_issues 的 instant 精度
端到端——含注释/历史/抬头三个时间点)。

设计稿:.roadmap-proposals/instant-precision.md
留待维护者回复的 5 个问题:默认、迁移、typo 政策、doc_time 单独、
JQL 游标。

Signed-off-by: rollroyces <rollroyces@users.noreply.github.com>

* GitHub and Jira write their timestamps to the second, with no setting

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: rollroyces <rollroyces@users.noreply.github.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: rollroyces <rollroyces@users.noreply.github.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…hing (#696)

* A confident merge waits for no one, and a succession clashes with nothing

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A clash one side already had is not the merge's

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* The per-chunk ontology list keeps to the prompt budget

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* Test strings spell their line breaks

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* 0006 records that the per-chunk list keeps to the budget

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* An agreement keeps its identity through its amendments

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* A name that raises doubt is settled by what the second look finds

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The governance bench waits out a deferred extraction

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* 0025 records what the second look settles

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

* The settled shape has a test

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
)

Signed-off-by: Aniruddha Adak <aniruddhaadak80@users.noreply.github.com>
Co-authored-by: Aniruddha Adak <aniruddhaadak80@users.noreply.github.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
* Say which test and save each Models card's note refers to

Signed-off-by: Aniruddha Adak <aniruddhaadak80@users.noreply.github.com>

* A Models card with unsaved changes says so instead of testing the saved one

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: Aniruddha Adak <aniruddhaadak80@users.noreply.github.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Aniruddha Adak <aniruddhaadak80@users.noreply.github.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: WaylandYang <145302500+WaylandYang@users.noreply.github.com>
…ine (#715)

* The extraction progress counts each document once, not once per pipeline

Signed-off-by: Qishang Zhong <zhongqishang@gmail.com>

* The progress counts are tested against live, deleted and failed documents

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>

---------

Signed-off-by: Qishang Zhong <zhongqishang@gmail.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@WaylandYang
WaylandYang merged commit dda6046 into main Sep 15, 2026
3 of 4 checks passed
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