mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-06-12 01:45:14 +02:00
mutate_as and load now write directly to target tables and call the publisher once at the end with per-table expected versions; the Run state machine, _graph_runs.lance writers, __run__ staging branches, and server /runs/* endpoints are removed. Multi-statement mutations remain atomic at the manifest level via an in-memory MutationStaging accumulator that gives read-your-writes within a query and a single publish at the end. Concurrent-writer conflicts surface as ExpectedVersionMismatch (HTTP 409 manifest_conflict) instead of the old DivergentUpdate merge shape. Documents one known limitation in docs/runs.md: a multi-statement mid-query failure where op-N writes a Lance fragment and op-N+1 fails leaves Lance HEAD ahead of the manifest until a follow-up introduces per-table Lance branches. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
4.2 KiB
4.2 KiB
Omnigraph v0.4.0
Omnigraph v0.4.0 demotes the Run state machine to commit metadata via the publisher's CAS, fixing the cancellation hole that motivated MR-771 and reducing the engine's surface area.
Highlights
- Direct-to-target writes (MR-771):
mutate_asandloadwrite directly to the target tables and callManifestBatchPublisher::publishonce at the end withexpected_table_versions. No more__run__<id>staging branches, no moreRunRecordstate machine. Cross-table OCC is enforced inside the publisher's row-level CAS on__manifest. - Cancellation safety by construction: a dropped mutation future
leaves no graph-level state — only orphaned Lance fragments, reclaimed
by
omnigraph cleanup. The "zombie run" cascade documented in.context/zombie-run-investigation.mdis gone. - Read-your-writes inside multi-statement mutations: a
.gqquery that inserts and then references a row in the same statement now sees its own writes via an in-processMutationStagingcache, even though no manifest commit happens between ops. - Structured conflict surface: concurrent writers race through the
publisher's CAS; the loser surfaces as
ManifestConflictDetails::ExpectedVersionMismatch { table_key, expected, actual }. The HTTP server maps this to 409 Conflict with a structuredmanifest_conflictbody so clients can detect-and-retry without parsing the message.
Removed
This is a breaking release. Pre-0.4.0 / no SLA.
omnigraph::db::{RunRecord, RunStatus, RunId}types and the_graph_runs.lance/_graph_run_actors.lanceLance datasets.- Engine APIs
begin_run,begin_run_as,publish_run,publish_run_as,abort_run,fail_run,terminate_run,list_runs,get_run. - HTTP endpoints:
GET /runs,GET /runs/{run_id},POST /runs/{run_id}/publish,POST /runs/{run_id}/abort. TheRunListOutputandRunOutputschemas are removed from the OpenAPI document. - CLI subcommands:
omnigraph run list,omnigraph run show,omnigraph run publish,omnigraph run abort. Useomnigraph commit listreading the commit graph for audit history. - Cedar policy actions
run_publishandrun_abort. Existingpolicy.yamlfiles referencing these actions will fail validation — remove the rules; thechangeaction covers the equivalent gating.
Behavior changes
mutate_as/loadare now atomic per query, single publish at the end. A failed mutation leaves the target unchanged with no intermediate manifest commits.- The
OmniError::manifest_conflictshape produced by concurrent writers is nowExpectedVersionMismatch(wasMergeConflict::DivergentUpdatevia the run merge path). Clients that match on the conflict body must switch to inspectingmanifest_conflict.table_key/expected/actual.
Known limitation
A multi-statement mutation that writes a Lance fragment in op-N and then
fails in op-N+1 leaves the touched table with Lance HEAD ahead of the
manifest. The next mutation against that table fails with
ExpectedVersionMismatch. Most validation runs before any Lance write,
so single-statement mutations are unaffected; the narrow path is
multi-statement queries with late-op failures. Tracked as a follow-up;
see docs/runs.md
for the workaround.
Upgrade notes
- Stale
__run__*branches and_graph_runs.lancein legacy v0.3.x repos are inert — the engine no longer reads them — but they remain on disk until production cleanup. MR-770 owns the destructive sweep; this release deliberately does not touch legacy bytes. - The
is_internal_run_branchpredicate is kept as a defense-in-depth guard against users naming a branch__run__*. It will be removed in a follow-up alongside MR-770. - External scripts hitting
/runs/*will now receive 404. Migrate them to/commitsfor audit history; mutation status is implied by the HTTP response on/changeitself.
Included Changes
- MR-771 — Demote Run: write directly to target via publisher
- MR-766 —
ManifestBatchPublisher::publishaccepts per-tableexpected_table_versions(landed earlier; this release wires it in end-to-end)