diff --git a/.github/workflows/gq-logic-tests.yml b/.github/workflows/gq-logic-tests.yml index a1747f4ef..6a972a65d 100644 --- a/.github/workflows/gq-logic-tests.yml +++ b/.github/workflows/gq-logic-tests.yml @@ -183,6 +183,12 @@ jobs: RUSTFLAGS: "" run: cargo test -p omnigraph-gqt --locked --timings --lib --test runner_dispatch -- --nocapture + - name: Test ordinary GQT core execution + if: needs.classify_changes.outputs.run_gqt == 'true' && matrix.mode == 'ordinary' + env: + RUSTFLAGS: "" + run: cargo test -p omnigraph-gqt-core --locked --timings --lib -- --nocapture + # A case's `at:` name arms a seam in the seam guard, so a cases-only # diff can change its verdict while `Test Workspace` is skipped. - name: Run the seam guard the case corpus arms @@ -191,15 +197,23 @@ jobs: RUSTFLAGS: "" run: cargo test -p omnigraph-seams --locked --timings --test failpoint_names_guard + # This parity test reads a corpus case, so it must run when a + # cases-only diff skips `Test Workspace`. + - name: Test benchmark fixture parity with the GQT corpus + if: needs.classify_changes.outputs.run_gqt == 'true' && matrix.mode == 'ordinary' + env: + RUSTFLAGS: "" + run: cargo test -p omnigraph-bench --locked --timings --lib branch_merge::tests::generated_dataset_matches_the_legacy_fixture_and_reversible_history -- --exact --nocapture + # The workspace .cargo/config.toml enables the seeded Tokio runtime # from any directory; these steps run from the repo root. - name: Run complete GQ logic tests with DST if: needs.classify_changes.outputs.run_gqt == 'true' && matrix.mode == 'dst' - run: cargo test -p omnigraph-gqt --locked --timings -- --nocapture + run: cargo test -p omnigraph-gqt -p omnigraph-gqt-core --locked --timings -- --nocapture - name: Clippy GQT with DST if: needs.classify_changes.outputs.run_gqt == 'true' && matrix.mode == 'dst-clippy' - run: cargo clippy -p omnigraph-gqt --all-targets --locked --timings -- -D warnings -W clippy::dbg_macro + run: cargo clippy -p omnigraph-gqt -p omnigraph-gqt-core --all-targets --locked --timings -- -D warnings -W clippy::dbg_macro - name: Retain GQT invocation reports if: always() && needs.classify_changes.outputs.run_gqt == 'true' && matrix.mode != 'dst-clippy' diff --git a/.github/workflows/gqt-slow-nightly.yml b/.github/workflows/gqt-slow-nightly.yml index 021c0babf..062719802 100644 --- a/.github/workflows/gqt-slow-nightly.yml +++ b/.github/workflows/gqt-slow-nightly.yml @@ -47,6 +47,30 @@ jobs: - name: Run the slow cases run: cargo run -p omnigraph-gqt --locked --bin omnigraph-gqt -- crates/omnigraph-gqt/cases_slow + - name: Validate full benchmark datasets + run: | + cargo run -p omnigraph-gqt --locked --bin omnigraph-gqt -- \ + benchmarks/fixtures/branch_merge_d50.gqt \ + benchmarks/fixtures/equal_current_narrow_one_batch.gqt \ + benchmarks/fixtures/equal_current_wide_four_batches.gqt \ + benchmarks/fixtures/equal_current_wide_one_batch.gqt \ + benchmarks/fixtures/hot_table_idle_base.gqt \ + benchmarks/fixtures/hot_table_idle_branches_4.gqt \ + benchmarks/fixtures/hot_table_idle_branches_4_aged.gqt \ + benchmarks/fixtures/hot_table_idle_tables_4.gqt \ + benchmarks/fixtures/identity_lifecycle.gqt \ + benchmarks/fixtures/nearest_ranks_updated_embedding.gqt \ + benchmarks/fixtures/nearest_skips_deleted_rows_and_fills_limit.gqt \ + benchmarks/fixtures/parallel_tables.gqt \ + benchmarks/fixtures/repeated_deletion_recreation_branches.gqt \ + benchmarks/fixtures/repeated_deletion_recreation_rows.gqt \ + benchmarks/fixtures/threshold_crossings_after.gqt \ + benchmarks/fixtures/threshold_crossings_at.gqt \ + benchmarks/fixtures/threshold_crossings_before.gqt \ + benchmarks/fixtures/threshold_crossings_production_control.gqt \ + benchmarks/fixtures/tiny_graph.gqt \ + benchmarks/fixtures/very_long_history_32.gqt + - name: Retain GQT invocation reports if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 diff --git a/Cargo.lock b/Cargo.lock index c829f832d..b79feac51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5591,6 +5591,7 @@ dependencies = [ "object_store", "omnigraph-compiler", "omnigraph-engine", + "omnigraph-gqt-core", "predicates", "serde", "serde_json", @@ -5724,6 +5725,7 @@ dependencies = [ "datafusion", "frostem", "futures", + "globset", "lance", "lance-core", "lance-file", @@ -5761,7 +5763,6 @@ dependencies = [ "async-trait", "bytes", "futures", - "globset", "lance-core", "lance-io", "object_store", @@ -5837,8 +5838,6 @@ dependencies = [ name = "omnigraph-gqt" version = "0.13.0" dependencies = [ - "arrow-array", - "arrow-schema", "async-trait", "datatest-stable", "futures", @@ -5846,14 +5845,33 @@ dependencies = [ "omnigraph-compiler", "omnigraph-dst", "omnigraph-engine", - "omnigraph-planner", + "omnigraph-gqt-core", "omnigraph-reference-engine", "serde", "serde_json", + "sha2 0.10.9", + "tempfile", + "tokio", +] + +[[package]] +name = "omnigraph-gqt-core" +version = "0.13.0" +dependencies = [ + "arrow-array", + "arrow-schema", + "futures", + "libm", + "omnigraph-compiler", + "omnigraph-engine", + "omnigraph-planner", + "serde", + "serde_json", "serde_yaml", "sha2 0.10.9", "tempfile", "tokio", + "unsafe-libyaml", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 15b773e6d..b2a720bcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ members = [ "crates/omnigraph-server", "crates/omnigraph-dst", "crates/omnigraph-gqt", + "crates/omnigraph-gqt-core", "tools/omnigraph-vocabulary-guard", ] default-members = [ @@ -111,6 +112,9 @@ uuid = { version = "1", features = ["v4"] } hmac = "0.12" httpdate = "1" +[workspace.lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ["cfg(tokio_unstable)"] } + [workspace.lints.clippy] # Nested guards often read clearer than one merged condition (Polars allows this too). collapsible_if = "allow" diff --git a/benchmarks/README.md b/benchmarks/README.md index 5238f4d01..26ab11469 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -1,410 +1,226 @@ # Benchmark catalog -This directory contains the checked-in inputs for the end-to-end benchmark -harness. A case describes one benchmark point. A suite selects cases and says -how many samples to collect. These files are experiment definitions, not run -records, fixtures, or result storage. - -## Branch operation diagnostics - -The engine's `scenarios` target supplements the declarative merge cases with -one-operation create, create-from, list, and delete measurements: +Start with a named scenario or your own YAML: ```bash -cargo bench --locked -p omnigraph-engine --bench scenarios -- \ - --scenario branch-create-from --branches 8 --tables 4 \ - --rows 1000 --dims 32 --runs 5 --out /tmp/branch-create-from.jsonl +omnigraph-bench list scenarios +omnigraph-bench show tiny-read +omnigraph-bench run tiny-read +omnigraph-bench run --config benchmarks/custom.example.yaml ``` -Use `branch-create`, `branch-create-from`, `branch-list`, or `branch-delete`. - -The same setup/operation/verify owner also provides: - -- `branch-pointer-adopt-lazy`: fast-forward a changed source into a lazy named target. -- `branch-pointer-adopt-owned`: fast-forward a descendant source into a named target that already owns a table fork. -- `branch-first-write`: append one row to a target that inherits its source's table fork. -- `branch-cleanup`: collect retired forks while preserving a native table parent required by a live child. - -These four scenarios verify complete rows, exact published table pins and physical table refs outside the timed operation. Pointer scenarios require zero instrumented table writes and verify a later isolated target write in the separate verification child. Cleanup creates collectible work even with `--retired-branches 0`; its effective collectible count is recorded separately. The age/cache/layout controls remain available, and the full-row fixtures are bounded to 16,384 rows, 16 dimensions and eight branches/tables. A larger cold fixture with a one-row delta can use `--rows 4096 --dims 4`; warm/compacted controls retain their smaller limits. Setup and the verification child's isolation write are never included in operation latency. -`--branches` counts existing siblings, excluding `main` and scenario-specific targets or cleanup parent/child branches; -`--tables` counts populated tables. One table contains `--rows` vectors of -`--dims` dimensions, and each remaining table contains one scalar row. -Create-from uses a named source with data distinct from main. The delete -target owns a native fork for every table. Counts must be positive and these -scenarios do not accept `--baseline`. - -Each repetition prepares a fresh fixture, measures one public operation, and -verifies the resulting branch registry and pinned table views in separate -processes. Operation time excludes graph open. Operation-process peak RSS -includes runtime initialization and graph open, but excludes setup and final -verification. Delete leaves table forks for explicit cleanup and reports no -reclaim wait. Compare identical parameters, builds, and machines; these JSONL -records are diagnostic evidence and do not enter the durable archive. - -`fenced-adopt-all-new` measures an insertion-only merge into an unchanged -target. `general-merge-updates --delta-rows 50 --source-mode update` measures -updates into a diverged target; `--source-mode insert` selects new IDs instead. -Their route counters report the classifier and write adapter actually used. -Hold the delta fixed while changing `--rows` to measure scaling, and run -`OMNIGRAPH_MERGE_LINEAGE=off`, `on`, and `verify` separately when comparing -classification paths: the operation child reads that variable through the -process-default settings reader before it opens the fixture, records the -mode as `merge_lineage` in its metrics, and refuses any other value with the -reader's message. Verify mode executes both paths and is not comparable -to a single-path throughput sample. - -### Small graph-age fixtures - -`--history-commits N` adds paired, real updates of one existing row before -forking, then restores its original embedding. The accepted row count and -content stay fixed while graph commits, table versions, and deletion history -accumulate. N defaults to zero and must be even, at most 256. -`--retired-branches N` creates, writes and deletes N temporary graph branches -before the measured workload, at most 32. Their table forks remain until -explicit cleanup. This is a -separate churn dimension; retired branches do not add reachable main history. -Both options apply to branch controls and `general-merge-updates` only. -The setup records and checks actual history growth and content restoration. -Explicit age diagnostics also record fixture file count and byte size through -a metadata-only census between setup and the operation process. - -Two optional controls separate history from physical layout and reusable -views. `--cache-state cold` (the default) uses a fresh operation process and -graph handle without prewarming; it does not evict the OS page cache. -`--cache-state warm` performs one read-only branch-registry and accepted -snapshot metadata pass over every live branch on that same handle. It opens -no user-table payloads. Fresh open, prewarm, and the operation each have their -own timers and foreground I/O counters. - -`--manifest-layout uncompacted` (the default) preserves the generated layout. -`--manifest-layout compacted` runs Lance compaction on every live `__manifest` -native ref after setup. This is direct physical preparation of a disposable, -exclusively owned benchmark fixture, not a public graph-maintenance API. It -does not optimize user tables, build indexes, or clean up versions. Setup -compares every typed manifest cell before/after and verifies retained native -versions, full reachable graph history, heads, table pins, and branch identity. -The receipt records fragment counts, logical row counts, and native versions; -the compacted arm must actually rewrite fragments. Physical compaction keeps -logical history, so fewer files must not be reported as less retained history. -Warm or compacted controls are limited to 256 rows, 16 dimensions, eight -siblings, and eight tables. Existing scenario defaults remain unchanged. - -Use the small sequential matrix to compare accumulated history without a -large data fixture: +The [shared config](benchmarks.yaml) defines all scenarios and groups. GQT files +hold the data, operations and expected results: -```bash -python3 scripts/bench-branch-age.py --plan -python3 scripts/bench-branch-age.py \ - --binary /absolute/path/to/scenarios \ - --build-receipt /absolute/path/to/build.json \ - --output /tmp/branch-age-results +```text +benchmarks/ + fixtures/ # starting states; registered references/preparation together + workloads/ # operations and verification + deferred/ # inactive sources awaiting language/executor support + benchmarks.yaml # scenario names, groups and run settings + custom.example.yaml # optional example to copy + README.md ``` -The runner requires a saved release scenario executable and a matching clean -source build receipt (`source.before/after`, successful locked Cargo command, -and `binary.path/sha256`). It never compiles implicitly. Its default matrix -uses 16 rows, four-dimensional vectors, 0/16/64 extra history commits, and a -separate eight-retired-branch case. Branch controls use two populated tables -and two sibling branches; general merge uses one table, two source updates, -and eight disjoint target updates. Each point collects three samples. -`--extended` additionally varies live siblings and populated tables to eight; -`--smoke --runs 1` checks one tiny aged/churned fixture per operation. -`--history-only` selects just H0/H16/H64, and `--scenario` can select fewer -operations. Cache/layout selectors choose one condition per invocation; -the runner never expands a Cartesian matrix implicitly. For example, inspect -matched history plans, then run each with the same saved binary and separate -output directories: +Use `omnigraph-bench --help`, `help config` or `help cache` for the complete +workflow. `help --json` describes this binary's commands for agents. Discovery +works with a debug build; measurements require the qualified release build +[described below](#run-locally). -```bash -python3 scripts/bench-branch-age.py --plan --history-only --scenario branch-delete -python3 scripts/bench-branch-age.py --plan --history-only --scenario branch-delete --cache-state warm -python3 scripts/bench-branch-age.py --plan --history-only --scenario branch-delete --manifest-layout compacted -``` +## End-to-end workloads -The runner uses one process group at a time, lower scheduling priority, two -threads per Tokio/Lance CPU/Rayon pool, two Lance I/O slots, a 256 MiB Lance -memory pool, and three-second pauses between points. These are recorded -runtime settings, not a hard CPU or process-memory cap. Each point has a -180-second whole-process watchdog. All child phases and fixture parameters -must verify before a sample is accepted. Counters cover foreground operation -I/O through instrumented handles, including the exported table-write count; -they do not represent all storage requests or deletes. Explicit cleanup is -a separate scenario. Open time remains separate from operation latency. -Explicit age runs of create/create-from additionally time the first accepted -snapshot, pinned opens, and one payload row per inherited table after the fork. -Those reads have separate counters and do not enter acknowledgement or -operation-completion time. The operation child's whole-process RSS includes -open, optional prewarm and first read; its pre/post-operation high-water marks -remain available. Final exact branch/table verification still runs in the -third process. The bounded SHA reader works on Python 3.9 and later. - -These fixtures model accumulated history on the current format. They do not -claim compatibility with old binary formats or legacy bare branch refs, and -their constrained-runtime timings are not comparable to unrestricted runs. - -## Concurrent-writes throughput diagnostics - -The `concurrent-writes` scenario is the instrument RFC 0067's "What to -measure before promising numbers" section asks for: sustained commits per -second per branch under N concurrent writers, before and after each step of -the RFC's throughput path, on a compact and on a fragmented manifest, on -local storage and on an S3-compatible store. Its baseline exhibits the -serialization the path's second step targets: every writer crosses the -exclusive schema gate during publication, so adding writers raises -service-time percentiles long before it raises the commit rate. +All active benchmarks are fixture/workload GQT pairs in the shared catalog. +The `end-to-end`, `query-shapes` and `traversal` groups contain bounded graph +operation representatives. Run `omnigraph-bench list scenarios` for the exact +inventory. The default remains `local-fast`. -```bash -RUSTFLAGS= cargo bench --locked -p omnigraph-engine --bench scenarios -- \ - --scenario concurrent-writes --writers 8 --duration-secs 30 \ - --rows 256 --dims 8 --history-commits 64 --manifest-layout uncompacted \ - --runs 3 --out /tmp/concurrent-writes.jsonl -``` +The representatives have independent expected rows and new experiment identities. +Their fixture sizes, cache preparation and repetition boundaries differ from +the historical Rust instruments; their timing series must not be combined. -`RUSTFLAGS=` (empty) is part of the command: the workspace Cargo -configuration otherwise injects `--cfg tokio_unstable`, whose runtime cost -is unmeasured, and the record's `attestation` block captures the cfg, the -enabled engine features, `LANCE_MEM_POOL_SIZE`, and the effective Tokio -worker count so a mixed comparison is visible rather than silent. - -**The driver is closed-loop and therefore not claim-grade.** Each writer -task issues its next insert only after the previous acknowledgement, which -is the right shape for finding the ceiling but — per RFC 0039 Rule 1 — is -subject to coordinated omission: the driver pauses exactly when the system -stalls. The record self-labels `driver: "closed-loop"` and -`claim_grade: false`, and its latencies are `service_time_*` (time to serve -one acknowledged write), never arrival latency. Claim-grade throughput or -latency numbers require the future open-loop scheduled-arrival benchmark -kind; these records are decision evidence for the RFC's ordered path. - -One repetition is one measured child: it builds a fresh `Chunk` fixture -(`--rows`, `--dims`, the age and layout controls above), then runs -`--writers` closed-loop tasks over clones of one `Session` — the production -server shape — issuing insert-only mutations with disjoint per-worker keys -for `--warmup-secs` plus `--duration-secs`. `--write-branches B` spreads -writers round-robin over `B` forks instead of `main`; the first write on -each fork pays the deferred first-touch fork of `node:Chunk`, which the -warm-up absorbs unless `--warmup-secs 0` puts it inside the window. Setup, warm-up, -verification and teardown sit outside the measured window. After every -counter and clock is read, a fresh handle verifies exact per-branch row -counts (seeded rows plus this run's acknowledgements) and reads sampled -acknowledged keys back. `Omnigraph::mutate` replays a typed read-set -conflict (the graph head moved under a concurrent writer) itself, up to 32 -times for an insert-only mutation; the record counts those replays as -`reprepares` and `io.per_op.reprepares_per_commit`. A conflict reaches the -driver only when that loop is exhausted; the driver retries it like a real -client and counts the exhaustion as `authority_conflicts`. Both kinds of -retry sit inside the op's service time. Any other worker error, any key -conflict, or a verification mismatch fails the run rather than emitting a -green record. - -`commits_per_sec` divides by `window_us`, the measured window alone; -`drain_us` is the time ops in flight at the stop took to finish. -`commits_by_second` is the acknowledgement count per second of the window, -which is where a plateau or a stall shows; `completed_in_drain` holds the -ops that finished after the stop. - -Op counting rides the ungated instrumentation surface: Lance manifest- and -table-plane logical calls through per-run `IOTracker` wrappers installed on -the graph open and on every writer task, and control-plane calls through -`CountingStorageAdapter`. Counters are logical calls, not physical -requests; the `io.per_op` block divides them by acknowledged -commits, which is where a future group-commit change must show -`manifest_writes_per_commit` falling below one. The unit is one range get -or one put at the seam, so these counts are not the round trips RFC 0067 -counts per write and must not be divided by them. The totals are read from -each probed Lance `ObjectStore`'s own `io_tracker`, not from the wrapper: -on a local target Lance writes and reads file bodies through its direct -local writer and reader, which never reach a wrapped store, and the -store's own tracker sees both paths. `--no-probes` runs the same -workload without any counting for an A/B of the counting overhead. - -To measure an S3-compatible store, pass `--target-uri s3://bucket/prefix`; -the child appends a unique `cw-{nanos}` segment, refuses (exit 78) when the -store is unreachable, and deletes the prefix afterwards unless -`--keep-fixture`. Credentials and endpoint come from the standard `AWS_*` -variables; the RustFS recipe CI uses (`.github/workflows/ci.yml`, the -`rustfs_integration` job: `docker run rustfs/rustfs`, then -`AWS_ENDPOINT_URL_S3=http://127.0.0.1:9000`, `AWS_ALLOW_HTTP=true`, -`AWS_S3_FORCE_PATH_STYLE=true`, access key pair, `create-bucket`) works -verbatim on a laptop. The harness passes the parent environment through to -the measured child, so exporting those variables is sufficient. - -These records are diagnostic evidence and do not enter the durable archive. - -## Layout - -- `cases/*.case-v1.yaml` assigns the fixture, workload, environment, and - protocol for one point. -- `suites/*.suite-v1.yaml` lists cases to run. Suite files live directly in - `suites/`, whose parent is the authoritative catalog root. A `case` path is - resolved relative to the suite file that contains it, and its canonical - target must remain under the same catalog's `cases/` directory. Suite and - referenced-case symlinks cannot escape the catalog. -- `fixtures/*.fixture-reference-v1.yaml` is the path-free logical contract for - an imported node-and-edge graph: builder provenance, logical data shape, - declared physical state, and expected schema/content digests. -- `real-graph/*.run-v1.yaml` selects one registered fixture, the fixed - real-graph workload, repetition count, and operation deadline. This narrow - diagnostic path is separate from CaseV1 suites and durable run records. - -The `version` field selects the document schema. Keep identifiers and enum -values in kebab-case. The scenario and fixture-builder versions identify the -code contracts that interpret the remaining typed fields. - -Index state is an inventory rather than a global label. Use `indexes: []` for -an unindexed fixture; each indexed entry names its `table`, `column`, `kind`, -and `freshness`. Synthetic branch-merge builder v3 supports only -`compaction_recency: not-optimized`, because OmniGraph optimization -materializes physical indexes outside this builder's exact inventory contract. - -Builder v3 interprets `fixture.data.tables` as the total user-table count and -requires an even value: half are immutable node endpoint tables and half are -edge tables in a uniform type ring. Every edge row connects equal ordinals in -adjacent node types. `workload.diverged_tables` selects edge tables only, so it -must not exceed half of `fixture.data.tables`. Source and target update -disjoint stable edge IDs, delete disjoint edge cohorts, and append distinct -edge IDs while retaining valid endpoints. - -`protocol.deadline_seconds` is required. Set it to an integer from 1 through -3600, or to YAML `null` when the measured operation has no deadline; the -executor must still enforce a separate bounded safety watchdog. Leading and -trailing whitespace in S3 identity fields and index table/column names is -normalized before validation and hashing. - -`environment.cache_condition` is structured, not a single cold/warm label. -Every current point uses `process: fresh-per-repetition`. Select one of these -exact engine/page-cache/program combinations: - -```yaml -# Process-cold: fresh worker, no declared warm-up, OS page cache uncontrolled. -cache_condition: - process: fresh-per-repetition - engine: preparation-only - page_cache: uncontrolled - program: none - iterations: 0 - -# Warm: named program, then measurement on the same handle. -cache_condition: - process: fresh-per-repetition - engine: warmed-by-program - page_cache: program-conditioned - program: branch-merge-read-set-v1 - iterations: 1 - -# Post-reopen: named program, then a new engine handle; no invalidation claim. -cache_condition: - process: fresh-per-repetition - engine: reopened-after-program - page_cache: program-conditioned - program: branch-merge-read-set-v1 - iterations: 1 -``` +Unsupported workloads are preserved temporarily in [deferred/](deferred/README.md). +Cleanup and optimization require GQ support. Concurrent, HTTP and streaming +instruments require an executor that preserves their scheduling and transport. +Their preserved sources are outside Cargo discovery and are not active scenarios. +Raw Lance and Rust collection comparisons are retired from the benchmark suite. -All five fields enter point identity. `program-conditioned` says the named -reads ran immediately before measurement; it is not a page-residency proof. -Page-cache-cold is deliberately absent: it requires both a named -platform/backend eviction control and a post-control witness. Storage-cold is -neither supported nor representable because controlling the OS page cache says -nothing about device, object-store, or remote-service caches. -Case definitions deliberately contain no source branch, system-under-test -build, machine identity, AWS account, bucket URI, result location, or -credentials. Record finalization binds the clean source/build, backend, -complete typed process observations, session, and invocation to each completed -run. Its hostname-derived label is only a non-secret, non-stable correlation -hint—not a privacy boundary or proof of machine identity. -Repetition count is run quantity, so it belongs to the suite rather than the -case's experiment identity. - -`fixture.state.history_depth` is the exact number of reachable OmniGraph graph -commits on **each already-diverged frozen branch**, including the history -shared before the branch was created. It is not merely the number of commits -made after branching. Builder v3 measures both frozen branches and refuses a -case whose declaration does not match; it does not silently pad or squash -history. For the checked case, the reachable depth is 213: one genesis commit, -200 base-load publications (25 chunks for each of four node and four edge -tables), and 12 branch-local edge-divergence publications on each branch. +## Configuration -### Preparing additional write history +One [version-2 YAML file](benchmarks.yaml) defines named scenarios. A scenario +pairs a fixture with a workload and selects one measured operation. Groups +select scenario IDs without duplicating their definitions. The `run` list is +the explicit default selection: the repository selects only `local-fast`. +Large histories and registered FinBench require explicit selection. -To vary accumulated write history while keeping the current graph contents -fixed, add a versioned `fixture.preparation` recipe to a synthetic builder-v3 -case. For the checked-in 213-commit case, these fixture fields add 64 real -commits and require a frozen depth of 277: - -```yaml -# Fields within fixture; retain its existing builder and data declarations. -preparation: - kind: reversible-updates-v1 - additional_commits: 64 - rows_per_commit: 1 - seed: 42 - maintenance: none -state: - aging: small-commits - indexes: [] - deletion_history: reversible-updates - compaction_recency: not-optimized - history_depth: 277 +- `fixtures/*.gqt` contains schema, seed and preparation/history steps. +- `fixtures/finbench/` keeps a registered graph's logical reference and GQT + preparation together. The invocation supplies its physical source bundle. +- `workloads/*.gqt` omits schema/seed and contains optional preparation reads, + the selected operation, then explicit verification. +- `defaults` supplies repetitions, deadline, environment and protocol settings; + a scenario may override them. `--repetitions` changes only sample quantity. + +Use the complete [custom example](custom.example.yaml), or generate a config +from the parser's exact selected operation: + +```bash +omnigraph-bench show --workload benchmarks/workloads/tiny_read.gqt +omnigraph-bench init --fixture benchmarks/fixtures/tiny_graph.gqt \ + --workload benchmarks/workloads/tiny_read.gqt --step 1 --output custom.yaml +omnigraph-bench show custom --config custom.yaml +omnigraph-bench run --config custom.yaml ``` -After the base load and before either branch is created, each pair chooses -one existing edge table and a wrapping batch of distinct row IDs from the seed -and pair number. The first public Merge load replaces every selected row's -nonnegative `val` with `-1 - val`; the second restores it. Each load publishes -once. Keys, endpoints, cohorts and payloads stay fixed. The builder checks exact -history growth and every restored row before branching, then performs its -normal full fixture verification and freezes the result. Each measured -repetition still starts from those same frozen bytes; preparation is outside -the merge timer. - -All recipe fields are required. `additional_commits` must be even, from 2 to -10,000; omission of the recipe is the zero-history control. `rows_per_commit` -is 1 through 4,096, cannot exceed the existing rows per table, and must fit the -payload-derived single-load bound. Only `maintenance: none` is supported: -no optimization, index build or cleanup runs during preparation. The update -history retains its replacement files and commits, so it is declared explicitly -as `deletion_history: reversible-updates` even though final logical rows match -the base graph. - -Preflight includes preparation in the exact history, generated-row, file-count -and free-space budgets. Its scratch estimate separately reserves space for -quadratically growing retained manifest history and three physical copies. -The existing one-hour fixture-process watchdog includes preparation, full -verification and freezing; failure produces no measured sample. The 1,000- and -10,000-commit boundary tests qualify planning arithmetic, not runtime or disk -cost on a particular machine. Start with a small history count before scheduling -larger acquisitions. - -The recipe and state fields enter point identity and the stamped logical -fixture. Omitting preparation preserves existing case and record identities. -Build-proof requirements and claim eligibility remain unchanged. Imported -fixture references describe already-built history; this recipe applies only -to the synthetic CaseV1 builder. +`init` refuses existing files. Put the output YAML in a directory containing +both sources. YAML paths resolve relative to its directory and stay within it; +absolute paths, parent traversal and symlink escapes are refused. CLI file +arguments are relative to the working directory. An explicit `--config` never +falls back to another config. With no `--config`, the CLI searches the working +directory and its ancestors for `benchmarks.yaml` or `benchmarks/benchmarks.yaml`. + +A minimal config inherits five repetitions, a 60-second deadline, per-phase +attribution, manual scheduling and a monotonic timer. Local defaults are +APFS/clonefile on macOS or qualified XFS/plain-copy elsewhere. The repository +config explicitly retains each scenario's original environment and repetitions. +`show` reports all effective settings before a run. `deadline_seconds: null` +removes the measurement deadline; the supervisor remains bounded. Protocol +fields are `attribution`, `schedule`, `reset` and `timer`. + +The internal validated case remains one experiment. Legacy case/suite readers +and explicit `suite run --dataset ... --queries ...` remain available for +existing callers; the authored catalog needs no separate case or suite files. + +The echo includes the complete operation header and body, including branch +selection. It excludes expectations and separate parameter sections; the full +queries SHA-256 binds those too. Moving a step or changing its text without +updating the selector is refused. The selected step cannot occur in a loop. +A generated load is selectable only when its recipe makes exactly one loader +call; generation happens before its engine timer. Multi-call loads remain +valid dataset construction steps. + +Cache treatment is derived, never authored as a label. No prefix reads means +process-cold. Prefix reads on the same handle mean warmed-by-program. Prefix +reads followed by one restart mean reopened-after-program. A read after that +restart is refused. Settings and show steps are neutral; prefix writes belong +in the dataset and are refused. Only reads that actually reach an engine +operation prove the preparation. A prefix expected parameter error that never +calls the engine cannot establish a warm treatment. Every repetition is a +fresh process; the OS page cache remains uncontrolled or conditioned by the +named GQT read program. No page-cache-cold or storage-cold claim is implied. -## Validate and inspect +### Preparing additional write history -From the repository root: +History is ordinary generated loads or GQ mutations in the dataset. The +retired `fixture.preparation` Rust recipe is retained only for historical +archive validation and parity tests. The checked-in D50 dataset reproduces +its base load/divergence recipe, while the core parity tests cover reversible +aging. Current-content and normalized lineage witnesses distinguish different +histories without hashing random commit IDs or physical Lance versions. + +The D50 warm prefix is 24 authored aggregate queries. This is the new +`gqt-read-set-v1` program, distinct from the retired Rust `warm_read_set` +scans. Fixture parity does not make their wall-clock values or point IDs +interchangeable. + +## Bounded scenario pairs + +The `local-regression` suite selects the following sequential cases, each with +one measured engine operation. Dataset assertions check the prepared state; +query suffixes check exact resulting rows and repeat those checks after restart. +These inputs establish correctness conditions, not performance results. + +| Scenario | Cases and treatment | Verification and scope | +| --- | --- | --- | +| Very long history | `very-long-history-32-{read,write,reopen}` | One fixed live row, 32 real updates alternating 1/0, then a selected read, next write, or reopen. The build witness checks 34 reachable commits including genesis and seed. | +| Hot table with idle registrations | `hot-table-idle-{base,tables-4,branches-4,branches-4-aged}` | Separate controls add four idle tables or four live branches. The aged branch case adds eight updates only on an idle branch. Every sentinel and unchanged branch is checked. | +| Parallel tables | `parallel-tables-{1,2,4}` | One mutation touches one, two, or four of the same four populated tables. All touched and untouched rows are checked. This tests fan-out shape; it makes no actor-overlap or internal parallel-span claim. | +| Identity lifecycle | `identity-lifecycle` | Delete and recreate a branch name, then measure its first write. Exact current views prove that the recreated branch inherits main while an old child retains its original parent view. Table-schema lifecycle and held snapshots are outside this subset. | +| Repeated deletion/recreation | `repeated-deletion-recreation-{rows,branches}` | Four bounded cycles followed by the next insertion or branch creation. Every cycle verifies exact rows; the final branch inventory and reopened views are checked. Row churn and branch churn are separate treatments. | +| Threshold crossings | `threshold-crossings-{before,at,after,production-control}` | A configured history-release boundary: two, three, or four updates at `history_release_bytes = 2048`, plus a three-update control at the production budget 262144, followed by an insert. Exact main/child contents are checked. | +| Equal current state, different history | `equal-current-{narrow-one-batch,wide-one-batch,wide-four-batches}` | Four identical final rows after eight past/restore cycles. Prior payload width varies from 8 to 4096 bytes; a separate treatment publishes each load in four batches. Build witnesses check equal current contents and 18/18/66 reachable commits. | + +The threshold fixtures preserve the configured shapes from the engine's +history-release correctness cases. Their row assertions do not prove that a +release counter fired, and they do not model an optimize, index-build, or +cache-capacity threshold. There is no maintenance or cleanup step in these +pairs. Concurrent interleavings, held-snapshot lifetimes, and historical row +images need their own observations; these sequential cases do not establish +those properties. + +Dataset and query basenames use the same scenario names with underscores. +The history operations share `workloads/very_long_history_{read,write,reopen}.gqt` +across depths, and equal-current cases share +`workloads/equal_current_different_history.gqt`. The owning benchmark catalog +test executes all 20 bounded pairs through dataset construction and the +measured adapter, including their explicit restart verification. Parsing and +suite admission also cover the larger recipes without executing them. + +### Opt-in history scale + +The `history-1000`, `history-10000` and `history-100000` groups select read, +next-write and reopen operations over fixed live contents with the named +number of real updates. Their recipes live in `fixtures/`; nightly names its +20 ordinary recipes explicitly and does not select these larger inputs. + +Each fixture retains one `HistoryRow` at `key = "hot"`, `value = 0`, +`payload = "fixed"`. Updates alternate value 1 and 0, producing 1,002, 10,002 +or 100,002 reachable commits including genesis and seed publication. The +100,000-update recipe uses five loops of 10,000 iterations, with two updates +per iteration. Every workload verifies rows and repeats verification after +restart. Their 600,000 ms whole-file budget may expire on a slow host. ```bash -cargo run --locked -p omnigraph-bench -- \ - case validate benchmarks/cases/branch-merge-d50-warm.case-v1.yaml +target/debug/omnigraph-gqt benchmarks/fixtures/very_long_history_1000.gqt +omnigraph-bench run history-1000 --dataset-cache /qualified/cache --json +``` -cargo run --locked -p omnigraph-bench -- \ - case list benchmarks/cases +These inputs have not been run as a scale campaign. Their authored scale is +not a timing claim; no one-million-update recipe is included. The groups use +one repetition by default. Cache construction and verification remain outside +the selected operation timer. -cargo run --locked -p omnigraph-bench -- \ - suite validate benchmarks/suites/local-smoke.suite-v1.yaml +## Validate and inspect -cargo run --locked -p omnigraph-bench -- \ - suite plan benchmarks/suites/local-smoke.suite-v1.yaml +From the repository root, use these read-only commands: -cargo run --locked -p omnigraph-bench -- \ - fixture reference validate /path/to/graph.fixture-reference-v1.yaml +```bash +omnigraph-bench list fixtures --json +omnigraph-bench list workloads --json +omnigraph-bench list scenarios --json +omnigraph-bench show tiny-read --json +omnigraph-bench cache status tiny-read --dataset-cache /qualified/cache --json +omnigraph-bench cache status tiny-read --dataset-cache /qualified/cache --verify --json +omnigraph-bench cache list --dataset-cache /qualified/cache --limit 100 --json ``` -Each command accepts `--json` for machine-readable output. `suite plan` also -accepts `--case ` to select one case from a suite. +Listings include unselected local inputs and keep missing or invalid references +visible with diagnostics. They scan only config-relative content folders and +references, never the workstation. `show --workload FILE` lists parser ordinals +and exact operation text; `init` validates whether the selected operation is measurable. + +Cache status reports source availability separately from the matching cache +variant. Source states are `available`, `missing`, `invalid`, `unbound`; cache +states are `missing`, `present`, `cached`, `busy`, `invalid`, `incomplete`, `unknown`. +`present` validates the published evidence; `--verify` also audits metadata and +physical bytes before reporting `cached`. A busy entry returns immediately. +Inspection never builds, creates directories/locks, restores, cleans or quarantines. +A missing/unbound source gives an unknown current key, not a cache miss. A known +miss is a successful observation; invalid or unreadable evidence exits nonzero. + +The default cache path is `target/gqt-datasets` relative to cwd. Use the same +`--dataset-cache` for inspection and execution. Keys bind recipe, engine/builder, +backend/reset, cache location, index needs and registered source identity. An +older variant in `cache list` may coexist with a current miss. Listing is paged +at 1..100 entries; continue with `--after` and the returned `next_cursor`. +Inspection is a snapshot, not a reservation for execution. + +Discovery success/error JSON carries `cli_output_version: 1`, `ok`, `value` +(on success or status inspection), and `diagnostics`. Diagnostics have severity, +code, path and message. JSON goes to stdout; progress goes to stderr. Execution +retains `runner_output_version: 2` and its complete archive/failure evidence. +`help --json` includes command syntax, defaults, effects and examples without +reading any catalog or cache. Legacy `dataset validate` acquires a lease and +stages worker files; it is not a read-only inspection command. An operator-quiesced external snapshot tree uses a location-free two-entry bundle: @@ -436,9 +252,8 @@ target/release/omnigraph-bench fixture preflight-copy \ ``` These commands prove only physical byte identity and copy preflight. Physical -identity is audit/reset evidence, not `point_id` input. They do not add the -fixture to a CaseV1 suite or run a benchmark; CaseV1 remains the synthetic -builder contract. No copied tree remains after preflight success. +identity is audit/reset evidence, not `point_id` input. A registered `gqt-v1` case separately binds the logical reference and its +preparation GQT. No copied tree remains after preflight success. ### Observe and validate a registered graph @@ -460,17 +275,17 @@ tree after observation and removes it. It never opens the registered source as an OmniGraph database and does not mutate that source. The declarative expectations for the frozen FinGraph fixture live in -`benchmarks/fixtures/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml`. +`benchmarks/fixtures/finbench/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml`. Validate the YAML structure first, then recompute its implemented witnesses against the registered bytes: ```bash target/release/omnigraph-bench fixture reference validate \ - benchmarks/fixtures/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml \ + benchmarks/fixtures/finbench/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml \ --json target/release/omnigraph-bench fixture validate-graph \ - benchmarks/fixtures/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml \ + benchmarks/fixtures/finbench/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml \ --fixture finbench-2026-08-21-sf10-v1=/path/to/finbench-2026-08-21-sf10-v1 \ --scratch-root /path/to/existing-apfs-scratch --json ``` @@ -504,188 +319,112 @@ runner slice. ## Run locally -### CaseV1 suite runner +Wall-clock execution requires a flag-free release-profile binary. The +workspace development configuration injects `--cfg tokio_unstable`; the +existing documented release build uses `RUSTFLAGS= cargo build --release +--locked -p omnigraph-bench`. The guard refuses builds that retain encoded +Rust flags, debug assertions, unsupported engine features, or unmodeled +runtime overrides. Durable publication additionally requires a clean, +committed source tree matching that executable's provenance. -Wall-clock execution is available only from a flag-free release-profile binary -(`RUSTFLAGS=` clears the workspace's development `--cfg tokio_unstable`; the -runner refuses a build whose build script saw encoded Rust flags): +Start with the small correctness-oriented catalog: ```bash -RUSTFLAGS= cargo run --release --locked -p omnigraph-bench -- \ - suite run benchmarks/suites/local-smoke.suite-v1.yaml \ - --archive .bench/archive - -# On the AWS lab's XFS instance-store mount: -target/release/omnigraph-bench suite run \ - benchmarks/suites/aws-xfs-process-cold.suite-v1.yaml \ - --scratch-root /mnt/nvme --archive /mnt/nvme/omnigraph-bench-archive +target/release/omnigraph-bench dataset build benchmarks/fixtures/tiny_graph.gqt --dataset-cache /qualified/cache +target/release/omnigraph-bench run local-fast --dataset-cache /qualified/cache --json ``` -Use `--case ` to select one suite entry, `--scratch-root ` to -place disposable fixture trees on a particular volume, `--archive ` to -publish immutable canonical records, and `--json` for machine-readable output. -The host probe examines the created scratch tree, not merely the path supplied -on the command line. Durable publication requires a release binary built from -a clean committed tree so the record has honest source provenance. The exact -system under test is bound separately by the executable SHA-256, Cargo/compiler -observations, checked-in release-profile declarations, and engine feature -inventory. The inventory includes Cargo's `default` feature and execution -refuses manifest/registry drift or an unsuppressed implicit optional-dependency -feature. Effective LTO/codegen/strip settings remain explicitly unproved -until controlled benchmark infrastructure supplies a digest-bound receipt. - -Runner-v1 constructs and verifies one fixture whose `bench-source` and -`bench-target` branches are already diverged, closes it, and freezes the -complete directory by physical SHA-256. The fixture is built at a stable -`active` path because Lance shallow-branch manifests can retain absolute base -paths. Public execution constructs it in a dedicated process group under a -bounded watchdog. The child freezes a byte-digested template and removes -`active` before returning an identity-checked handoff. APFS uses forced -clonefile with no byte-copy fallback. Linux XFS uses verified copies only for -the process-fresh point: reset reads bytes outside timing, so its page cache is -truthfully declared uncontrolled. Every repetition restores the exact stable -`active` path; failed construction quarantines the workspace. - -Every repetition uses a fresh worker process and starts from the same frozen -state. The parent pins and records the worker executable SHA-256 and requires -matching source commit/dirty state, release-profile, target/compiler, -engine-feature, and effective engine-environment evidence in the private -handshake. Fixture and repetition children clear inherited environment. The -fixture child receives an empty protocol-owned scratch sibling as `TMPDIR`; a -measured worker receives a fresh per-repetition scratch sibling as both -`TMPDIR` and `OMNIGRAPH_MERGE_STAGING_DIR`. Each child validates the exact real, -absolute path and uses it as its current directory before work, so relative -dependency spill cannot escape the verified disposable workspace. Cleanup -occurs only after containment is proved. -`LANCE_MEM_POOL_SIZE` is admitted only as the canonical decimal `u64` byte -count Lance actually applies and is recorded as typed SUT identity. Unknown -`LANCE_*`, engine-facing `OMNIGRAPH_*`, or process-runtime thread-count -overrides fail closed without recording their values. Credentials and unrelated -host knobs never reach the child or enter a record. The supervisor also records -the repetition worker's peak RSS. The -complete cache condition is part of point identity. A declared read-only -warm-up program runs inside each repetition before measurement. A storage -firewall allows only each read-write open's one balanced, empty -create-if-absent capability probe and rejects any other preparation write; a -complete metadata-shape witness independently catches path, kind, or length -drift. Measured counters are then cleared and exactly one branch merge is -timed. The repetition's writes disappear when `active` is removed rather than -aging the next sample, and the never-opened template is checked after every -worker exits. - -Before it initializes a fixture, the runner derives the exact builder-v3 -publication count, rejects a mismatched history declaration, applies explicit -local row/byte/entry/history limits, and proves that the scratch volume has its -conservative frozen-copy capacity allowance plus space for the staged, -descriptor-bound worker executable. The concrete runner limits are listed in -`crates/omnigraph-bench/README.md`; they are deliberately narrower than the -host-independent case schema. - -The supervisor starts the declared hard deadline immediately before releasing -the prepared worker with `Begin`. The worker must send `Settled` after its merge -future returns. On timeout the supervisor kills the worker's complete process -group without a grace period, waits for and reaps it, and proves the group is -gone. Every repetition failure, including a frame after `Complete`, rejects the -sample. Cleanup is allowed only after the direct child is reaped, its process -group is gone, and bounded capture has observed clean EOF on both pipes; -otherwise the disposable workspace is quarantined. A failure with complete -containment may therefore clean up safely, but no killed or partial operation -becomes a sample. Preparation and exact verification have separate bounded -watchdogs with a 300-second minimum allowance. - -After timing and call counters stop, the worker reads and verifies exact IDs, -values, cohorts, payloads, insertions, and deletions across every table on -target, source, and main, including tables that should remain untouched, and -requires unchanged source/main branch heads. The parent does not reread those -content bytes; it independently derives and validates the point/case identity, -general three-way route, and declared table/total-row count attestations -returned by the worker. Exactly one `TableWalk` interval is required per -diverged edge table. This -full runner-v1 verification is O(store), deliberately outside timing. -Receipt-based O(delta) certification starts with the future versioned-S3 reset -slice. A future DST oracle adds independent evidence but never replaces these -per-repetition probes. Reported storage counts are logical engine calls, not -physical requests or cloud-cost estimates. - -The warm-up program `branch-merge-read-set-v1` reads the reachable commit list -and a coherent snapshot for `main`, `bench-source`, and `bench-target`, then -fully consumes every diverged edge table plus the union of its endpoint node -tables using type-appropriate projections. A -`reopened-after-program` point runs that same program and reopens the engine -handle before measurement; it does not claim invalidation. A process-cold point -uses `preparation-only`, `program: none`, and `iterations: 0`: the worker is -fresh and no declared warm-up program runs, but ordinary engine open and -protected-head capture still occur and `page_cache: uncontrolled` states the -OS cache limitation explicitly. A true page-cache-cold point remains refused -until a named platform/backend eviction control has a post-control witness; -storage-cold is also unsupported and unrepresentable. - -### FinGraph diagnostic runner - -The real-graph run is declared independently from the synthetic CaseV1 suite. -The checked-in run file has this strict shape: - -```yaml -version: 1 -fixture_id: finbench-2026-08-21-sf10-v1 -workload: finbench-disjoint-insert-merge -repetitions: 5 -operation_deadline_seconds: 600 -``` +`dataset build ` prepares the exact cache entry needed by that +case. `dataset build --queries ` includes the +queries' index requirements without selecting or measuring an operation. +Without `--queries`, only dataset index needs apply. The union of dataset and +query requirements is part of the cache key, and indexes are built with the +seed **before** authored updates/deletes. This preserves stale-index and +fallback scenarios. Building an unindexed raw dataset cannot satisfy a later +indexed case's `--no-build` request. + +`dataset validate` takes the same inputs and verifies a published matching +entry without building. `suite run --no-build` refuses a miss. `--filesystem +apfs|xfs` applies to raw dataset and explicit-pair commands; case/suite files +supply their own backend. APFS requires forced clonefile, and qualified Linux +XFS uses verified plain copies. The host probe must establish the declared +backend. Clonefile has no byte-copy fallback; copies condition the OS page +cache outside measurement. + +An explicit pair uses the same resolver, cache, worker, and archive pipeline: -`repetitions` must be from 1 through 20 and -`operation_deadline_seconds` from 1 through 3600. Unknown fields are refused. -The logical reference path and local bundle path stay outside the run file so -neither a checkout location nor an operator's storage location becomes -experiment identity. +```bash +target/release/omnigraph-bench suite run --dataset benchmarks/fixtures/tiny_graph.gqt --queries benchmarks/workloads/tiny_restart.gqt --measured-step 1 --measured-text '--- restart' --repetitions 5 --deadline-seconds 60 --dataset-cache /qualified/cache +``` -Build the CLI in release mode and run the checked-in FinGraph declaration and -logical reference against a local registered bundle: +The full D50 suites are `local-smoke` (warm APFS) and +`aws-xfs-process-cold` (qualified XFS). They build 800,000 +base rows. The small `local-fast` suite is a separate smoke test, not proof of +full-scale performance or correctness. + +Every build runs in a contained child, at its cache entry's final stable +`active` path. The engine closes before freezing the never-opened `root/` +template. Publication writes `fixture-source.json` and then +`dataset-build.json` last. The parent accepts the handoff only after child +reap, process-group exit, and clean bounded output capture. The exclusive +cache lock remains held through every repetition's verification and cleanup. +All entries restore at their original absolute path, including relocatable +ones; this conservative policy keeps Lance branch base paths valid. + +A cache key includes recipe contents, production engine/builder digest, +backend/reset, index requirements, canonical cache location, and registered +physical source identity when applicable. `GQT_ENGINE_DIGEST` excludes authored +case/data files, which have their own content digests. A hit verifies the +registered descriptor, logical receipt, and full template bytes once. Each +repetition uses metadata and forced-clone/copy witnesses without rereading +all APFS template bytes before its timer. Changed published evidence is +`dataset_cache_corrupt`, never an implicit rebuild. Unknown unpublished state +or uncertain process containment is preserved/quarantined for explicit +inspection; do not remove it while a child could still be alive. + +The selected engine operation alone owns its monotonic interval and logical +store-call deltas. Query results are materialized before the interval closes. +Parsing, generated-row preparation, cache work, assertions, verification, +recording, and cleanup are outside it. Selected restart measures the fresh +engine open, using fresh adapter counters; it does not include preparation +checks. Optional merge-phase probes are installed only for a selected merge +with per-phase attribution. Logical calls do not measure retries, pagination, +multipart fan-out, physical network attempts, or cloud cost. + +A successful record requires the selected expectation and explicit following +verification expectations. Restart alone is not verification. Any failure +rejects the repetition. After `Settled`, a later assertion/protocol/exit +failure may retain closed timing as diagnostic evidence, never as a passing +sample. A declared deadline is measured separately by the parent from Begin; +whole-file GQT budgets also apply. Process containment is required before any +active tree or scratch directory can be removed. + +### Registered FinBench merge + +The old `fixture run-graph` command and `.run-v1.yaml` format are retired. +The ordinary case and suite now select a registered reference plus +[`fixtures/finbench/finbench_disjoint.gqt`](fixtures/finbench/finbench_disjoint.gqt) and +[`workloads/finbench_disjoint_merge.gqt`](workloads/finbench_disjoint_merge.gqt): ```bash -RUSTFLAGS= cargo build --release --locked -p omnigraph-bench - -target/release/omnigraph-bench fixture run-graph \ - benchmarks/real-graph/finbench-2026-08-21-sf10-v1.run-v1.yaml \ - --reference \ - benchmarks/fixtures/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml \ - --fixture finbench-2026-08-21-sf10-v1=/path/to/finbench-2026-08-21-sf10-v1 \ - --scratch-root /path/to/existing-qualified-scratch --json +target/release/omnigraph-bench run finbench --fixture finbench-2026-08-21-sf10-v1=/path/to/bundle --dataset-cache /qualified/cache --json ``` -`run-graph` refuses a debug build. The harness copies and validates the -registered graph, prepares two branches whose disjoint changes each contain -two `Account` nodes and one `AccountTransferAccount` edge, and freezes that -prepared input. Each repetition restores the same path and runs only the branch -merge in a fresh worker process. macOS requires qualified local APFS and uses -forced clonefiles. Linux requires XFS on a directly mounted EC2 instance-store -NVMe namespace, refuses EBS, and uses a complete verified plain copy outside -the timer. Use a dedicated benchmark mount: after freezing and after each -restore, Linux `syncfs` waits for all writeback on that filesystem so reset I/O -does not overlap the merge. The recorded reset is -`xfs-plain-copy-syncfs-same-active-path`. Before making that template, the Linux -path requires free space for one prepared-tree copy plus 1 GiB. The registered -source is never opened as an OmniGraph database and remains unchanged. -Before returning either success or failure, the command explicitly attempts to -remove its disposable workspace. A cleanup failure is reported, and a run plus -cleanup double failure retains both causes. -The result includes raw elapsed samples, p50, merge route/phases, the prepared -physical digest, per-worker machine and backend evidence, and verification evidence for -the inserted delta, protected heads, and untouched tables. Pre-existing rows -in the two changed tables are not yet fully re-read and are reported as -unverified rather than implied to be proved. Machine identity is captured just -before timing in every worker; differing identities fail the run. - -This path deliberately does not make a publishable performance claim. Every -result says `claim_eligible: false` and `durable_record: false`; it has no -warm-up program, and although each measurement uses a fresh process, the -operating-system page cache is uncontrolled; Linux plain-copy reset reads every -fixture byte outside timing and can warm it. `run-graph` does not accept -`--archive`, publish durable telemetry, calculate a noise floor, download an -S3 fixture, or dispatch work through the AWS benchmark infrastructure. AWS may -hold the source snapshot, but an operator must first provide the verified local -two-entry bundle used above. AWS orchestration and durable-record integration -are later connector work, not behavior hidden behind this command. +This shipped case declares APFS. The source bundle remains quiescent and is +never opened as an engine store; a byte-verified disposable copy is validated +against its logical reference before preparation. Registered imports currently +require a main-only, relocation-self-contained source and deterministic node +`@key` columns. Unsupported unkeyed node identity or named source branches is +refused explicitly. + +Preparation publishes two accounts and one transfer atomically on each side. +Post-merge GQT asserts exact reserved account/transfer properties, endpoints, +and table counts on target, source, and main. Transfer IDs are engine-generated +and can differ from the retired Rust recipe. The prepared graph uses logical +equivalence, while an additional identity-aware export digest binds the fixed +registered source's original IDs. The source reference and preparation text +also enter recipe identity. This is a documented equivalence migration, not +an assertion that the old physical bytes or experiment point IDs survive. ## Telemetry and delivery boundary @@ -729,21 +468,27 @@ prefix as state-neutral `unpublished_run` recovery evidence. Resolve any `possib identity with `archive reconcile` before minting a replacement invocation. A later controlled-cloud adapter binds declared S3 facts, applies budget and lifecycle controls, executes the same typed plans, and uploads the same record format. -S3 reset, fixture caching, server-mode execution, comparison/noise-floor +S3 reset, server-mode execution, comparison/noise-floor reports, and proved operating-system page-cache eviction remain outside this slice. -## Add a case - -1. Add a versioned case file with explicit levels for every typed factor. -2. Reference it from a suite with a path relative to that suite. -3. Run both `case validate` and `suite validate`. -4. Inspect `suite plan` before executing the suite. -5. Run from a flag-free release build (`RUSTFLAGS= cargo …`) on a host that can - prove every declared environment fact; an unsupported factor is a refusal, - not permission to approximate it. - -Do not encode a profile such as `micro` or `realistic` in a case. Profiles are -derived from the declared factor levels. Benchmark timing is evidence and does -not gate CI; deterministic count contracts remain in their existing owning -tests. +## Add a scenario + +1. Add a fixture GQT and schema-less workload GQT with explicit expectations. +2. Use `show --workload FILE` and `init` to generate the exact measured selector. +3. Add the scenario to `benchmarks.yaml`, or keep the custom config separately. +4. Inspect it with `show NAME --config FILE`; optionally add its ID to a group. +5. Run the explicit selection on a qualified release host. + +The final point ID binds the verified dataset logical witness, recipe/query +contents, selected operation, derived cache treatment, and protocol/backend. +Planning can report only a pre-build experiment digest until the dataset is +bound. Paths, case display IDs, repetitions, cache-hit status, and physical +tree bytes do not enter the point ID. Historic `branch-merge-v1` records retain +their exact canonical encoding and remain queryable beside GQT records, but +old authored execution is refused. + +Catalog parsing and GQT result assertions are correctness gates. Benchmark +wall-clock and unpinned measured counters remain report-only. The slow nightly +GQT route explicitly selects 20 ordinary recipes from `benchmarks/fixtures`, including full-size D50; reduced parity +tests independently check the generator against the retained legacy test oracle. diff --git a/benchmarks/benchmarks.yaml b/benchmarks/benchmarks.yaml new file mode 100644 index 000000000..6a965d8ab --- /dev/null +++ b/benchmarks/benchmarks.yaml @@ -0,0 +1,813 @@ +# Fixtures describe starting states; workloads describe operations and checks. +# Named runs and settings live here. Large history groups are explicitly opt-in. +version: 2 +defaults: + repetitions: 1 + deadline_seconds: 60 + environment: + backend: + kind: local-fs + filesystem: apfs + storage_class: nvme-ssd + protocol: + attribution: per-phase + schedule: manual + reset: local-clonefile + timer: monotonic +scenarios: +- id: branch-merge-d50-process-cold-xfs + fixture: fixtures/branch_merge_d50.gqt + workload: workloads/branch_merge_d50_cold.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch merge "bench-source" into "bench-target" + repetitions: 5 + environment: + backend: + kind: local-fs + filesystem: xfs + storage_class: nvme-ssd + protocol: + reset: plain-copy +- id: branch-merge-d50-warm + fixture: fixtures/branch_merge_d50.gqt + workload: workloads/branch_merge_d50_warm.gqt + measured_step: + ordinal: 25 + text: | + --- mutate + branch merge "bench-source" into "bench-target" + repetitions: 5 +- id: equal-current-narrow-one-batch + fixture: fixtures/equal_current_narrow_one_batch.gqt + workload: workloads/equal_current_different_history.gqt + measured_step: + ordinal: 1 + text: | + --- query branch: main + query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +- id: equal-current-wide-four-batches + fixture: fixtures/equal_current_wide_four_batches.gqt + workload: workloads/equal_current_different_history.gqt + measured_step: + ordinal: 1 + text: | + --- query branch: main + query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +- id: equal-current-wide-one-batch + fixture: fixtures/equal_current_wide_one_batch.gqt + workload: workloads/equal_current_different_history.gqt + measured_step: + ordinal: 1 + text: | + --- query branch: main + query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +- id: finbench-disjoint-merge + fixture: + kind: registered + reference: fixtures/finbench/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml + preparation: fixtures/finbench/finbench_disjoint.gqt + workload: workloads/finbench_disjoint_merge.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch merge "bench-source" into "bench-target" + repetitions: 5 + deadline_seconds: 600 +- id: hot-table-idle-base + fixture: fixtures/hot_table_idle_base.gqt + workload: workloads/hot_table_idle_base.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query hot_write() { update Hot set { value: 1 } where key = "hot" } +- id: hot-table-idle-branches-4-aged + fixture: fixtures/hot_table_idle_branches_4_aged.gqt + workload: workloads/hot_table_idle_branches_4_aged.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query hot_write() { update Hot set { value: 1 } where key = "hot" } +- id: hot-table-idle-branches-4 + fixture: fixtures/hot_table_idle_branches_4.gqt + workload: workloads/hot_table_idle_branches_4.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query hot_write() { update Hot set { value: 1 } where key = "hot" } +- id: hot-table-idle-tables-4 + fixture: fixtures/hot_table_idle_tables_4.gqt + workload: workloads/hot_table_idle_tables_4.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query hot_write() { update Hot set { value: 1 } where key = "hot" } +- id: identity-lifecycle + fixture: fixtures/identity_lifecycle.gqt + workload: workloads/identity_lifecycle.gqt + measured_step: + ordinal: 1 + text: | + --- mutate branch: feature + query new_lifetime_write() { update Item set { value: 1 } where key = "alice" } +- id: nearest-ranks-updated-embedding + fixture: fixtures/nearest_ranks_updated_embedding.gqt + workload: workloads/nearest_ranks_updated_embedding.gqt + measured_step: + ordinal: 1 + text: | + --- query + query nearest_after_update($q: Vector(4)) { + match { $d: Doc } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 6 + } +- id: nearest-skips-deleted-rows-and-fills-limit + fixture: fixtures/nearest_skips_deleted_rows_and_fills_limit.gqt + workload: workloads/nearest_skips_deleted_rows_and_fills_limit.gqt + measured_step: + ordinal: 1 + text: | + --- query + query nearest_after_delete($q: Vector(4)) { + match { $d: Doc } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 + } +- id: parallel-tables-1 + fixture: fixtures/parallel_tables.gqt + workload: workloads/parallel_tables_1.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query update_tables() { + update T0 set { value: 1 } where key = "row" + } +- id: parallel-tables-2 + fixture: fixtures/parallel_tables.gqt + workload: workloads/parallel_tables_2.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query update_tables() { + update T0 set { value: 1 } where key = "row" + update T1 set { value: 1 } where key = "row" + } +- id: parallel-tables-4 + fixture: fixtures/parallel_tables.gqt + workload: workloads/parallel_tables_4.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query update_tables() { + update T0 set { value: 1 } where key = "row" + update T1 set { value: 1 } where key = "row" + update T2 set { value: 1 } where key = "row" + update T3 set { value: 1 } where key = "row" + } +- id: repeated-deletion-recreation-branches + fixture: fixtures/repeated_deletion_recreation_branches.gqt + workload: workloads/repeated_deletion_recreation_branches.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch create "recycled" from main +- id: repeated-deletion-recreation-rows + fixture: fixtures/repeated_deletion_recreation_rows.gqt + workload: workloads/repeated_deletion_recreation_rows.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query recreate_row() { insert Item { key: "temporary", value: 99 } } +- id: threshold-crossings-after + fixture: fixtures/threshold_crossings_after.gqt + workload: workloads/threshold_crossings_after.gqt + measured_step: + ordinal: 2 + text: | + --- mutate branch: b + query next_publish() { insert Person { name: "carol", age: 1 } } +- id: threshold-crossings-at + fixture: fixtures/threshold_crossings_at.gqt + workload: workloads/threshold_crossings_at.gqt + measured_step: + ordinal: 2 + text: | + --- mutate branch: b + query next_publish() { insert Person { name: "carol", age: 1 } } +- id: threshold-crossings-before + fixture: fixtures/threshold_crossings_before.gqt + workload: workloads/threshold_crossings_before.gqt + measured_step: + ordinal: 2 + text: | + --- mutate branch: b + query next_publish() { insert Person { name: "carol", age: 1 } } +- id: threshold-crossings-production-control + fixture: fixtures/threshold_crossings_production_control.gqt + workload: workloads/threshold_crossings_production_control.gqt + measured_step: + ordinal: 2 + text: | + --- mutate branch: b + query next_publish() { insert Person { name: "carol", age: 1 } } +- id: tiny-branch + fixture: fixtures/tiny_graph.gqt + workload: workloads/tiny_branch.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch create "child" from main +- id: tiny-load + fixture: fixtures/tiny_graph.gqt + workload: workloads/tiny_load.gqt + measured_step: + ordinal: 1 + text: | + --- load generate: v1 seed: 0 mode: append + tables: + - kind: node + name: Item + rows: 1 + commits: 1 + batch_rows: 1 + columns: + key: {kind: key, prefix: c, width: 1} + val: {kind: literal, value: 3} +- id: tiny-mutate + fixture: fixtures/tiny_graph.gqt + workload: workloads/tiny_mutate.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query add() { insert Item { key: "c", val: 3 } } +- id: tiny-post-reopen + fixture: fixtures/tiny_graph.gqt + workload: workloads/tiny_post_reopen.gqt + measured_step: + ordinal: 3 + text: | + --- query branch: main + query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } + } +- id: tiny-read + fixture: fixtures/tiny_graph.gqt + workload: workloads/tiny_read.gqt + measured_step: + ordinal: 1 + text: | + --- query branch: main + query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } + } +- id: tiny-restart + fixture: fixtures/tiny_graph.gqt + workload: workloads/tiny_restart.gqt + measured_step: + ordinal: 1 + text: "--- restart\n" +- id: very-long-history-1000-read + fixture: fixtures/very_long_history_1000.gqt + workload: workloads/very_long_history_read.gqt + measured_step: + ordinal: 1 + text: | + --- query branch: main + query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +- id: very-long-history-1000-reopen + fixture: fixtures/very_long_history_1000.gqt + workload: workloads/very_long_history_reopen.gqt + measured_step: + ordinal: 1 + text: "--- restart\n" +- id: very-long-history-1000-write + fixture: fixtures/very_long_history_1000.gqt + workload: workloads/very_long_history_write.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query next_write() { update HistoryRow set { value: 1 } where key = "hot" } +- id: very-long-history-10000-read + fixture: fixtures/very_long_history_10000.gqt + workload: workloads/very_long_history_read.gqt + measured_step: + ordinal: 1 + text: | + --- query branch: main + query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +- id: very-long-history-10000-reopen + fixture: fixtures/very_long_history_10000.gqt + workload: workloads/very_long_history_reopen.gqt + measured_step: + ordinal: 1 + text: "--- restart\n" +- id: very-long-history-10000-write + fixture: fixtures/very_long_history_10000.gqt + workload: workloads/very_long_history_write.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query next_write() { update HistoryRow set { value: 1 } where key = "hot" } +- id: very-long-history-100000-read + fixture: fixtures/very_long_history_100000.gqt + workload: workloads/very_long_history_read.gqt + measured_step: + ordinal: 1 + text: | + --- query branch: main + query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +- id: very-long-history-100000-reopen + fixture: fixtures/very_long_history_100000.gqt + workload: workloads/very_long_history_reopen.gqt + measured_step: + ordinal: 1 + text: "--- restart\n" +- id: very-long-history-100000-write + fixture: fixtures/very_long_history_100000.gqt + workload: workloads/very_long_history_write.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query next_write() { update HistoryRow set { value: 1 } where key = "hot" } +- id: very-long-history-32-read + fixture: fixtures/very_long_history_32.gqt + workload: workloads/very_long_history_read.gqt + measured_step: + ordinal: 1 + text: | + --- query branch: main + query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +- id: very-long-history-32-reopen + fixture: fixtures/very_long_history_32.gqt + workload: workloads/very_long_history_reopen.gqt + measured_step: + ordinal: 1 + text: "--- restart\n" +- id: very-long-history-32-write + fixture: fixtures/very_long_history_32.gqt + workload: workloads/very_long_history_write.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + query next_write() { update HistoryRow set { value: 1 } where key = "hot" } +- id: e2e-merge-all-changed + fixture: fixtures/e2e_merge_all_changed.gqt + workload: workloads/e2e_merge_all_changed.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch merge "source" into "main" +- id: e2e-merge-all-new + fixture: fixtures/e2e_merge_all_new.gqt + workload: workloads/e2e_merge_all_new.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch merge "source" into "main" +- id: e2e-merge-diverged-updates + fixture: fixtures/e2e_merge_diverged_updates.gqt + workload: workloads/e2e_merge_diverged_updates.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch merge "source" into "main" +- id: e2e-mixed-load + fixture: fixtures/e2e_mixed_load.gqt + workload: workloads/e2e_mixed_load.gqt + measured_step: + ordinal: 1 + text: | + --- load generate: v1 seed: 0 mode: merge branch: main + tables: + - kind: node + name: Chunk + rows: 32 + commits: 1 + batch_rows: 32 + start: 48 + columns: + slug: {kind: key, prefix: base, width: 3} + embedding: {kind: literal, value: [300.0,0.0,0.0,0.0]} +- id: e2e-branch-create + fixture: fixtures/e2e_branch_registry.gqt + workload: workloads/e2e_branch_create.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch create "child" from "main" +- id: e2e-branch-create-from + fixture: fixtures/e2e_branch_registry.gqt + workload: workloads/e2e_branch_create_from.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch create "child" from "source" +- id: e2e-branch-list + fixture: fixtures/e2e_branch_registry.gqt + workload: workloads/e2e_branch_list.gqt + measured_step: + ordinal: 1 + text: | + --- query + branch list +- id: e2e-branch-delete + fixture: fixtures/e2e_branch_delete.gqt + workload: workloads/e2e_branch_delete.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch delete "victim" +- id: e2e-branch-adopt-untouched + fixture: fixtures/e2e_branch_adopt_untouched.gqt + workload: workloads/e2e_branch_adopt_untouched.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch merge "source" into "target" +- id: e2e-branch-adopt-written + fixture: fixtures/e2e_branch_adopt_written.gqt + workload: workloads/e2e_branch_adopt_written.gqt + measured_step: + ordinal: 1 + text: | + --- mutate + branch merge "source" into "target" +- id: e2e-branch-first-write + fixture: fixtures/e2e_branch_first_write.gqt + workload: workloads/e2e_branch_first_write.gqt + measured_step: + ordinal: 1 + text: | + --- mutate branch: target + query insert_chunk($v: Vector(4)) { insert Chunk { slug: "target-only", embedding: $v } } +- id: e2e-nearest-prefilter + fixture: fixtures/e2e_nearest_prefilter.gqt + workload: workloads/e2e_nearest_prefilter.gqt + measured_step: + ordinal: 1 + text: | + --- query + query filtered_nearest($q: Vector(4)) { + match { $d: Doc { status: "hit" } } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 + } +- id: e2e-nearest-nprobes-one + fixture: fixtures/e2e_nearest_nprobes_one.gqt + workload: workloads/e2e_nearest_nprobes_one.gqt + measured_step: + ordinal: 1 + text: | + --- query + set ann_nprobes = 1; + query nearest_matching_rows($q: Vector(4)) { + match { $d: Doc $d.n > 3 } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 + } +- id: e2e-rrf-traversal + fixture: fixtures/e2e_rrf_traversal.gqt + workload: workloads/e2e_rrf_traversal.gqt + measured_step: + ordinal: 1 + text: | + --- query + query recall_two_terms($q1: String, $q2: String) { + match { + $c: Chunk + $a: Artifact + $c chunkOfArtifact $a + search($c.text, $q1) + } + return { $c.slug } + order { rrf(bm25($c.text, $q1), bm25($c.text, $q2)) } + limit 1 + } +- id: e2e-query-scan + fixture: fixtures/e2e_query_shapes.gqt + workload: workloads/e2e_query_scan.gqt + measured_step: + ordinal: 2 + text: | + --- query + query scan() { match { $p: Person } return { $p.name } } +- id: e2e-query-wide-scan + fixture: fixtures/e2e_query_wide.gqt + workload: workloads/e2e_query_wide_scan.gqt + measured_step: + ordinal: 2 + text: | + --- query + query wide_scan() { match { $p: Person } return { $p } } +- id: e2e-query-filter + fixture: fixtures/e2e_query_shapes.gqt + workload: workloads/e2e_query_filter.gqt + measured_step: + ordinal: 2 + text: | + --- query + query filter() { match { $p: Person $p.age >= 90 } return { $p.name, $p.age } } +- id: e2e-query-lookup + fixture: fixtures/e2e_query_shapes.gqt + workload: workloads/e2e_query_lookup.gqt + measured_step: + ordinal: 2 + text: | + --- query + query lookup() { match { $p: Person { name: "p000500" } } return { $p.name, $p.age } } +- id: e2e-query-count + fixture: fixtures/e2e_query_shapes.gqt + workload: workloads/e2e_query_count.gqt + measured_step: + ordinal: 2 + text: | + --- query + query count_all() { match { $p: Person } return { count($p) as n } } +- id: e2e-query-grouped + fixture: fixtures/e2e_query_shapes.gqt + workload: workloads/e2e_query_grouped.gqt + measured_step: + ordinal: 2 + text: | + --- query + query grouped() { + match { $p: Person } + return { $p.team, sum($p.age) as total, avg($p.age) as mean, count($p) as n } + } +- id: e2e-query-top-people + fixture: fixtures/e2e_query_shapes.gqt + workload: workloads/e2e_query_top_people.gqt + measured_step: + ordinal: 2 + text: | + --- query + query top_people() { + match { $p: Person } + return { $p.name, $p.age } + order { $p.age desc, $p.name asc } + limit 20 + } +- id: e2e-query-friends + fixture: fixtures/e2e_query_shapes.gqt + workload: workloads/e2e_query_friends.gqt + measured_step: + ordinal: 2 + text: | + --- query + query friends() { match { $p: Person $p knows $q } return { $p.name, $q.name } } +- id: e2e-query-filtered-friends + fixture: fixtures/e2e_query_shapes.gqt + workload: workloads/e2e_query_filtered_friends.gqt + measured_step: + ordinal: 2 + text: | + --- query + query filtered_friends() { + match { $p: Person $p.age >= 90 $p knows $q } + return { $p.name, $q.name } + } +- id: e2e-query-no-friends + fixture: fixtures/e2e_query_shapes.gqt + workload: workloads/e2e_query_no_friends.gqt + measured_step: + ordinal: 2 + text: | + --- query + query no_friends() { match { $p: Person not { $p knows $q } } return { $p.name } } +- id: e2e-query-count-bare + fixture: fixtures/e2e_query_issues.gqt + workload: workloads/e2e_query_count_bare.gqt + measured_step: + ordinal: 2 + text: | + --- query + query count_bare() { match { $p: Person } return { count($p) as n } } +- id: e2e-query-destination-projection + fixture: fixtures/e2e_query_issues.gqt + workload: workloads/e2e_query_destination_projection.gqt + measured_step: + ordinal: 2 + text: | + --- query + query destination_projection() { match { $p: Person $p knows $q } return { $q.name } } +- id: e2e-query-grouped-fanout + fixture: fixtures/e2e_query_issues.gqt + workload: workloads/e2e_query_grouped_fanout.gqt + measured_step: + ordinal: 2 + text: | + --- query + query grouped_fanout() { + match { $p: Person $p knows $q } + return { $p.team, count($q) as n } + } +- id: e2e-query-destination-search + fixture: fixtures/e2e_query_issues.gqt + workload: workloads/e2e_query_destination_search.gqt + measured_step: + ordinal: 2 + text: | + --- query + query destination_search() { + match { $p: Person $p knows $q search($q.body, "needle") } + return { $q.name } + } +- id: e2e-traversal-hop1 + fixture: fixtures/e2e_traversal.gqt + workload: workloads/e2e_traversal_hop1.gqt + measured_step: + ordinal: 2 + text: | + --- query + query hop1() { + match { + $a: Person + $b: Person + $a knows $b + } + return { $a.name, $b.name } + } +- id: e2e-traversal-hop2 + fixture: fixtures/e2e_traversal.gqt + workload: workloads/e2e_traversal_hop2.gqt + measured_step: + ordinal: 2 + text: | + --- query + query hop2() { + match { + $a: Person + $b: Person + $c: Person + $a knows $b + $b knows $c + } + return { $a.name, $c.name } + } +- id: e2e-traversal-hop3 + fixture: fixtures/e2e_traversal.gqt + workload: workloads/e2e_traversal_hop3.gqt + measured_step: + ordinal: 2 + text: | + --- query + query hop3() { + match { + $a: Person + $b: Person + $c: Person + $d: Person + $a knows $b + $b knows $c + $c knows $d + } + return { $a.name, $d.name } + } +- id: e2e-traversal-selective-csr + fixture: fixtures/e2e_traversal.gqt + workload: workloads/e2e_traversal_selective_csr.gqt + measured_step: + ordinal: 1 + text: | + --- query + query sel($name: String) { + match { + $a: Person { name: $name } + $a knows{1,2} $b + } + return { $b.name } + } +- id: e2e-traversal-selective-indexed + fixture: fixtures/e2e_traversal.gqt + workload: workloads/e2e_traversal_selective_indexed.gqt + measured_step: + ordinal: 1 + text: | + --- query + query sel($name: String) { + match { + $a: Person { name: $name } + $a knows{1,2} $b + } + return { $b.name } + } +groups: + end-to-end: + - e2e-merge-all-changed + - e2e-merge-all-new + - e2e-merge-diverged-updates + - e2e-mixed-load + - e2e-branch-create + - e2e-branch-create-from + - e2e-branch-list + - e2e-branch-delete + - e2e-branch-adopt-untouched + - e2e-branch-adopt-written + - e2e-branch-first-write + - e2e-nearest-prefilter + - e2e-nearest-nprobes-one + - e2e-rrf-traversal + aws-xfs-process-cold: + - branch-merge-d50-process-cold-xfs + finbench: + - finbench-disjoint-merge + history-1000: + - very-long-history-1000-read + - very-long-history-1000-write + - very-long-history-1000-reopen + history-10000: + - very-long-history-10000-read + - very-long-history-10000-write + - very-long-history-10000-reopen + history-100000: + - very-long-history-100000-read + - very-long-history-100000-write + - very-long-history-100000-reopen + local-fast: + - tiny-read + - tiny-restart + - tiny-post-reopen + - tiny-mutate + - tiny-branch + - tiny-load + local-regression: + - very-long-history-32-read + - very-long-history-32-write + - very-long-history-32-reopen + - hot-table-idle-base + - hot-table-idle-tables-4 + - hot-table-idle-branches-4 + - hot-table-idle-branches-4-aged + - parallel-tables-1 + - parallel-tables-2 + - parallel-tables-4 + - identity-lifecycle + - repeated-deletion-recreation-rows + - repeated-deletion-recreation-branches + - threshold-crossings-before + - threshold-crossings-at + - threshold-crossings-after + - threshold-crossings-production-control + - equal-current-narrow-one-batch + - equal-current-wide-one-batch + - equal-current-wide-four-batches + local-smoke: + - branch-merge-d50-warm + search: + - nearest-ranks-updated-embedding + - nearest-skips-deleted-rows-and-fills-limit + query-shapes: + - e2e-query-scan + - e2e-query-wide-scan + - e2e-query-filter + - e2e-query-lookup + - e2e-query-count + - e2e-query-grouped + - e2e-query-top-people + - e2e-query-friends + - e2e-query-filtered-friends + - e2e-query-no-friends + - e2e-query-count-bare + - e2e-query-destination-projection + - e2e-query-grouped-fanout + - e2e-query-destination-search + traversal: + - e2e-traversal-hop1 + - e2e-traversal-hop2 + - e2e-traversal-hop3 + - e2e-traversal-selective-csr + - e2e-traversal-selective-indexed +run: +- local-fast diff --git a/benchmarks/custom.example.yaml b/benchmarks/custom.example.yaml new file mode 100644 index 000000000..fe02a7bb6 --- /dev/null +++ b/benchmarks/custom.example.yaml @@ -0,0 +1,22 @@ +# Run: omnigraph-bench run --config benchmarks/custom.example.yaml +# All source paths are relative to this file. Keep the operation text exact; +# use `omnigraph-bench init --help` to generate it from a workload. +# An explicit run list prevents accidentally running every scenario or group. +version: 2 +defaults: + repetitions: 5 + deadline_seconds: 60 +scenarios: +- id: custom-tiny-read + fixture: fixtures/tiny_graph.gqt + workload: workloads/tiny_read.gqt + measured_step: + ordinal: 1 + text: | + --- query branch: main + query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } + } +run: +- custom-tiny-read diff --git a/benchmarks/deferred/README.md b/benchmarks/deferred/README.md new file mode 100644 index 000000000..0f8a089ee --- /dev/null +++ b/benchmarks/deferred/README.md @@ -0,0 +1,82 @@ +# Deferred benchmark sources + +These are inactive sources preserved during the migration to end-to-end GQT +benchmarks. They are outside Cargo target discovery. The `.disabled` suffix +prevents them from becoming Rust targets or executable scripts by accident. +[sources.json](sources.json) records each original path, preserved path and +SHA-256 of the unchanged source bytes. +The two server examples preserve the upstream 0.13 HTTP route updates; their +manifest entries also record the source revision. They remain inactive. + +The active [catalog](../benchmarks.yaml) contains fixture/workload pairs using +existing GQ operations. Cleanup and optimization must be added to **GQ** before +GQT can benchmark them. GQT must not introduce separate maintenance commands. + +## What is preserved + +- `crates/omnigraph/benches/`: the former scenario harness and its modules. + Branch cleanup and physical compaction controls require GQ maintenance support. + Concurrent writes require a benchmark executor that measures actual overlap. + Forced RRF plans, process settings and physical index treatments need explicit + support before their experiments can return with the same meaning. +- `crates/omnigraph/tests/benchmark_scenario_contract.rs.disabled`: the retired + harness's source and output contracts and included helper tests. They have no + active instrument to guard. Ordinary engine correctness and deterministic + cost tests remain at their owning layers. +- `crates/omnigraph/tests/compaction_memory.rs.disabled`: the stock-Lance + compaction comparator and the engine optimize peak-allocation assertion. + The latter is deferred pending GQ optimization support; it is no longer an + executable resource regression test. Existing deterministic Blob compaction + tests remain active. +- `crates/omnigraph/tests/manifest_history_curve.rs.disabled`: four ignored + acquisition instruments covering publication and schema-outcome histories, + request/byte counts, retained storage and diagnostic timings. Restoring them + requires equivalent schema operations and history/physical observations. +- `crates/omnigraph/tests/manifest_row_bytes.rs.disabled`: history-dependent + physical storage acquisition, including raw Lance re-encoding comparisons. + Restoration needs supported physical storage observations. +- `crates/omnigraph/tests/repro_issue_563.rs.disabled`: preserves the original + file containing a timed join-free ranked read. The active source keeps its + separate overflow-scale correctness test; only timing acquisition is deferred. +- `crates/omnigraph/examples/bench_expand.rs.disabled`: historical traversal + acquisitions and Rust collection comparisons. +- `crates/omnigraph-bench/examples/compare_engines.rs.disabled` and + `issue_shapes.rs.disabled`: historical query shapes, large fixtures and the + external-engine comparison. Equivalent scale, vector distributions and + comparison targets need explicit support before their timing series resumes. +- `crates/omnigraph-server/examples/`: concurrent HTTP and actor-isolation + instruments. Embedded serial queries cannot stand in for transport, bearer + actor resolution, streaming, backpressure or concurrent scheduling. +- `crates/omnigraph-cli/tests/support/`: the HTTP benchmark/retention helpers, + soak instrument and performance-layout checks. Historical records remain + readable by `scripts/analyze-http-perf.py` and `scripts/analyze-http-retention.py`. +- `scripts/bench-branch-age.py.disabled`: the historical branch-age acquisition + driver; its old engine harness is no longer an executable target. + +Raw Lance operations and Rust collection microbenchmarks are retired, not future +GQ benchmark promises. Their source remains here to explain historical results +and the scope of the migration. + +## Bounded replacements + +The `end-to-end` group provides 14 complete graph-operation representatives for +merge, load, branch control/adoption/first-write, nearest and automatic RRF +traversal. The `query-shapes` group provides 14 materialized queries, including +filtering, aggregation, joins, anti-joins and destination search. The `traversal` +group provides five traversal queries, including both existing traversal pins. + +These 33 scenarios have independently authored expected rows and checks after +reopening the database. They use new experiment identities: their bounded +fixtures, vector values, topology, batches, cache preparation or repetition +boundaries differ from the historical instruments. They do not establish +equivalent large-scale, HTTP, concurrency or physical-plan performance. + +## Restoring a deferred scenario + +First expose the required public graph operation in GQ, or add the required +transport/scheduling/observation capability to the generic benchmark executor. +Then author a fixture/workload pair with independent result expectations, +explicit measurement boundaries and an appropriate catalog identity. Verify +its results and declared execution treatment before registering it. Preserve +historical sources until their relevant coverage is accounted for; merely +renaming these files back into Cargo discovery is not a migration. diff --git a/crates/omnigraph-bench/examples/compare_engines.rs b/benchmarks/deferred/crates/omnigraph-bench/examples/compare_engines.rs.disabled similarity index 100% rename from crates/omnigraph-bench/examples/compare_engines.rs rename to benchmarks/deferred/crates/omnigraph-bench/examples/compare_engines.rs.disabled diff --git a/crates/omnigraph-bench/examples/issue_shapes.rs b/benchmarks/deferred/crates/omnigraph-bench/examples/issue_shapes.rs.disabled similarity index 100% rename from crates/omnigraph-bench/examples/issue_shapes.rs rename to benchmarks/deferred/crates/omnigraph-bench/examples/issue_shapes.rs.disabled diff --git a/crates/omnigraph-cli/tests/support/http_bench.rs b/benchmarks/deferred/crates/omnigraph-cli/tests/support/http_bench.rs.disabled similarity index 100% rename from crates/omnigraph-cli/tests/support/http_bench.rs rename to benchmarks/deferred/crates/omnigraph-cli/tests/support/http_bench.rs.disabled diff --git a/crates/omnigraph-cli/tests/support/http_perf_layout.rs b/benchmarks/deferred/crates/omnigraph-cli/tests/support/http_perf_layout.rs.disabled similarity index 100% rename from crates/omnigraph-cli/tests/support/http_perf_layout.rs rename to benchmarks/deferred/crates/omnigraph-cli/tests/support/http_perf_layout.rs.disabled diff --git a/crates/omnigraph-cli/tests/support/http_retention.rs b/benchmarks/deferred/crates/omnigraph-cli/tests/support/http_retention.rs.disabled similarity index 100% rename from crates/omnigraph-cli/tests/support/http_retention.rs rename to benchmarks/deferred/crates/omnigraph-cli/tests/support/http_retention.rs.disabled diff --git a/crates/omnigraph-cli/tests/support/http_soak.rs b/benchmarks/deferred/crates/omnigraph-cli/tests/support/http_soak.rs.disabled similarity index 100% rename from crates/omnigraph-cli/tests/support/http_soak.rs rename to benchmarks/deferred/crates/omnigraph-cli/tests/support/http_soak.rs.disabled diff --git a/crates/omnigraph-server/examples/bench_actor_isolation.rs b/benchmarks/deferred/crates/omnigraph-server/examples/bench_actor_isolation.rs.disabled similarity index 100% rename from crates/omnigraph-server/examples/bench_actor_isolation.rs rename to benchmarks/deferred/crates/omnigraph-server/examples/bench_actor_isolation.rs.disabled diff --git a/crates/omnigraph-server/examples/bench_concurrent_http.rs b/benchmarks/deferred/crates/omnigraph-server/examples/bench_concurrent_http.rs.disabled similarity index 100% rename from crates/omnigraph-server/examples/bench_concurrent_http.rs rename to benchmarks/deferred/crates/omnigraph-server/examples/bench_concurrent_http.rs.disabled diff --git a/crates/omnigraph/benches/scenarios.rs b/benchmarks/deferred/crates/omnigraph/benches/scenarios.rs.disabled similarity index 100% rename from crates/omnigraph/benches/scenarios.rs rename to benchmarks/deferred/crates/omnigraph/benches/scenarios.rs.disabled diff --git a/crates/omnigraph/benches/scenarios/branch_control.rs b/benchmarks/deferred/crates/omnigraph/benches/scenarios/branch_control.rs.disabled similarity index 100% rename from crates/omnigraph/benches/scenarios/branch_control.rs rename to benchmarks/deferred/crates/omnigraph/benches/scenarios/branch_control.rs.disabled diff --git a/crates/omnigraph/benches/scenarios/child_protocol.rs b/benchmarks/deferred/crates/omnigraph/benches/scenarios/child_protocol.rs.disabled similarity index 100% rename from crates/omnigraph/benches/scenarios/child_protocol.rs rename to benchmarks/deferred/crates/omnigraph/benches/scenarios/child_protocol.rs.disabled diff --git a/crates/omnigraph/benches/scenarios/concurrent_writes.rs b/benchmarks/deferred/crates/omnigraph/benches/scenarios/concurrent_writes.rs.disabled similarity index 100% rename from crates/omnigraph/benches/scenarios/concurrent_writes.rs rename to benchmarks/deferred/crates/omnigraph/benches/scenarios/concurrent_writes.rs.disabled diff --git a/crates/omnigraph/benches/scenarios/fixture_controls.rs b/benchmarks/deferred/crates/omnigraph/benches/scenarios/fixture_controls.rs.disabled similarity index 100% rename from crates/omnigraph/benches/scenarios/fixture_controls.rs rename to benchmarks/deferred/crates/omnigraph/benches/scenarios/fixture_controls.rs.disabled diff --git a/crates/omnigraph/benches/scenarios/rfc023.rs b/benchmarks/deferred/crates/omnigraph/benches/scenarios/rfc023.rs.disabled similarity index 100% rename from crates/omnigraph/benches/scenarios/rfc023.rs rename to benchmarks/deferred/crates/omnigraph/benches/scenarios/rfc023.rs.disabled diff --git a/crates/omnigraph/benches/scenarios/rfc023_limits.rs b/benchmarks/deferred/crates/omnigraph/benches/scenarios/rfc023_limits.rs.disabled similarity index 100% rename from crates/omnigraph/benches/scenarios/rfc023_limits.rs rename to benchmarks/deferred/crates/omnigraph/benches/scenarios/rfc023_limits.rs.disabled diff --git a/crates/omnigraph/examples/bench_expand.rs b/benchmarks/deferred/crates/omnigraph/examples/bench_expand.rs.disabled similarity index 100% rename from crates/omnigraph/examples/bench_expand.rs rename to benchmarks/deferred/crates/omnigraph/examples/bench_expand.rs.disabled diff --git a/crates/omnigraph/tests/benchmark_scenario_contract.rs b/benchmarks/deferred/crates/omnigraph/tests/benchmark_scenario_contract.rs.disabled similarity index 100% rename from crates/omnigraph/tests/benchmark_scenario_contract.rs rename to benchmarks/deferred/crates/omnigraph/tests/benchmark_scenario_contract.rs.disabled diff --git a/crates/omnigraph/tests/compaction_memory.rs b/benchmarks/deferred/crates/omnigraph/tests/compaction_memory.rs.disabled similarity index 100% rename from crates/omnigraph/tests/compaction_memory.rs rename to benchmarks/deferred/crates/omnigraph/tests/compaction_memory.rs.disabled diff --git a/crates/omnigraph/tests/manifest_history_curve.rs b/benchmarks/deferred/crates/omnigraph/tests/manifest_history_curve.rs.disabled similarity index 100% rename from crates/omnigraph/tests/manifest_history_curve.rs rename to benchmarks/deferred/crates/omnigraph/tests/manifest_history_curve.rs.disabled diff --git a/crates/omnigraph/tests/manifest_row_bytes.rs b/benchmarks/deferred/crates/omnigraph/tests/manifest_row_bytes.rs.disabled similarity index 100% rename from crates/omnigraph/tests/manifest_row_bytes.rs rename to benchmarks/deferred/crates/omnigraph/tests/manifest_row_bytes.rs.disabled diff --git a/benchmarks/deferred/crates/omnigraph/tests/repro_issue_563.rs.disabled b/benchmarks/deferred/crates/omnigraph/tests/repro_issue_563.rs.disabled new file mode 100644 index 000000000..6c6d363b8 --- /dev/null +++ b/benchmarks/deferred/crates/omnigraph/tests/repro_issue_563.rs.disabled @@ -0,0 +1,251 @@ +// ModernRelay/omnigraph#563: an unbounded bm25-ranked read that also traverses +// an edge materializes the joined variable-width column for the whole matched +// corpus before `limit` prunes; past Arrow's i32 offset ceiling (2 GiB per +// Utf8 column) the query fails with an Offset overflow error. The BM25 scan +// cap bounds it; this test pins the fixed behavior at overflow scale. +// +// Geometry: 6,000 Chunk rows x ~200 KB text = ~1.2 GiB of matched text (under +// the 2 GiB ceiling, so the scan-side concat survives and the no-join shape +// returns), each chunk linked to 2 artifacts, so the join's take +// re-materializes ~2.4 GiB of text (over the ceiling). +// +// Expensive (loads ~1.2 GiB, builds an inverted index over it): run explicitly +// cargo test -p omnigraph-engine --test repro_issue_563 -- --ignored --nocapture +// +// This is the SYMPTOM tier: proof at overflow scale, run at explicit +// checkpoints. The always-on MECHANISM tier lives in tests/search.rs: the +// capped-scan tests (bm25 under-fill + aggregate exemption, 20-row corpus) +// and the rrf uncapped-arm pins (20- and 7-row corpora). +// +// A second #[ignore]d test below times the join-free ranked read over the +// same corpus geometry: the scan cap's cost is hydration count, so the +// timing scales with matched rows (measured 2026-08-29, warm debug builds: +// 119 ms median on the pre-fix parent commit vs 2 ms with the cap). + +mod helpers; + +use std::time::Instant; + +use arrow_array::StringArray; + +use omnigraph::db::Omnigraph; +use omnigraph::loader::LoadMode; + +use helpers::*; + +const CHUNKS: usize = 6_000; +const ARTIFACTS: usize = 750; +const FANOUT: usize = 2; // artifacts per chunk +const TEXT_BYTES: usize = 200 * 1024; +const LOAD_BATCH_ROWS: usize = 64; // 64 x ~200 KB stays under the 32 MiB write cap + +const SCHEMA: &str = r#" +node Chunk { + slug: String @key + text: String @index +} + +node Artifact { + slug: String @key + name: String +} + +edge ChunkOfArtifact: Chunk -> Artifact { + label: String +} +"#; + +const RANKED_JOIN_QUERY: &str = r#" +query recall_join($q: String) { + match { + $c: Chunk + $c chunkOfArtifact $a + search($c.text, $q) + } + return { $c.slug, $a.slug, $a.name } + order { bm25($c.text, $q) } + limit 20 +} + +query recall_no_join($q: String) { + match { + $c: Chunk + search($c.text, $q) + } + return { $c.slug } + order { bm25($c.text, $q) } + limit 20 +} +"#; + +fn filler_block() -> String { + // Tiny vocabulary of long tokens keeps the inverted-index term dictionary + // small while the stored column carries full byte weight. + let words = [ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "cccccccccccccccccccccccccccccccc", + "dddddddddddddddddddddddddddddddd", + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "ffffffffffffffffffffffffffffffff", + "gggggggggggggggggggggggggggggggg", + "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", + ]; + let unit = words.join(" ") + " "; + let mut out = String::with_capacity(TEXT_BYTES + unit.len()); + while out.len() < TEXT_BYTES { + out.push_str(&unit); + } + out +} + +#[tokio::test(flavor = "multi_thread")] +#[ignore = "expensive: ~1.2 GiB corpus + inverted index build"] +async fn ranked_read_with_join_returns_top_limit_issue_563() { + let filler = filler_block(); + let dir = tempfile::tempdir().unwrap(); + let uri = dir.path().to_str().unwrap(); + let db = helpers::session(Omnigraph::init(uri, SCHEMA).await.unwrap()); + + // Artifacts + edges first (small), then the chunk corpus in capped batches. + let mut head = String::new(); + for a in 0..ARTIFACTS { + head.push_str(&format!( + "{{\"type\":\"Artifact\",\"data\":{{\"slug\":\"art-{a:04}\",\"name\":\"Artifact {a}\"}}}}\n" + )); + } + db.load_jsonl(&head, LoadMode::Overwrite).await.unwrap(); + + let mut chunk_batch = String::new(); + for c in 0..CHUNKS { + chunk_batch.push_str(&format!( + "{{\"type\":\"Chunk\",\"data\":{{\"slug\":\"chunk-{c:05}\",\"text\":\"needle563 {filler}\"}}}}\n" + )); + if (c + 1) % LOAD_BATCH_ROWS == 0 || c + 1 == CHUNKS { + db.load_jsonl(&chunk_batch, LoadMode::Append).await.unwrap(); + chunk_batch.clear(); + } + } + + let mut edges = String::new(); + let mut edge_rows = 0usize; + for c in 0..CHUNKS { + for f in 0..FANOUT { + let a = (c * FANOUT + f) % ARTIFACTS; + edges.push_str(&format!( + "{{\"edge\":\"ChunkOfArtifact\",\"from\":\"chunk-{c:05}\",\"to\":\"art-{a:04}\",\"data\":{{\"id\":\"e-{c:05}-{f}\",\"label\":\"of\"}}}}\n" + )); + edge_rows += 1; + // 8,192-keyed-entity write cap: flush well under it. + if edge_rows == 4_000 { + db.load_jsonl(&edges, LoadMode::Append).await.unwrap(); + edges.clear(); + edge_rows = 0; + } + } + } + if edge_rows > 0 { + db.load_jsonl(&edges, LoadMode::Append).await.unwrap(); + } + + db.ensure_indices().await.unwrap(); + + // The ranked read without the join stays under the i32 offset ceiling. + let no_join = query_main( + &db, + RANKED_JOIN_QUERY, + "recall_no_join", + ¶ms(&[("$q", "needle563")]), + ) + .await + .unwrap(); + assert_eq!(no_join.num_rows(), 20); + + // The same ranked read with the join must also return the top-limit rows. + // Unbounded (issue #563, pre-cap), it materialized matched text x fanout + // through the join and failed with "Offset overflow error: 2147489268". + let joined = query_main( + &db, + RANKED_JOIN_QUERY, + "recall_join", + ¶ms(&[("$q", "needle563")]), + ) + .await + .unwrap(); + assert_eq!(joined.num_rows(), 20); + + let batch = joined.concat_batches().unwrap(); + let chunk_slugs = batch + .column(0) + .as_any() + .downcast_ref::() + .unwrap(); + let artifact_slugs = batch + .column(1) + .as_any() + .downcast_ref::() + .unwrap(); + for row in 0..batch.num_rows() { + let c: usize = chunk_slugs.value(row)["chunk-".len()..].parse().unwrap(); + let a: usize = artifact_slugs.value(row)["art-".len()..].parse().unwrap(); + assert!( + a == (c * FANOUT) % ARTIFACTS || a == (c * FANOUT + 1) % ARTIFACTS, + "row {row}: artifact art-{a:04} is not linked to chunk-{c:05}" + ); + } +} + +/// Timing instrument for the scan cap: the join-free ranked read over the same +/// corpus geometry (no edges loaded), one warm-up then five timed runs. Prints +/// per-run and median wall time; asserts correctness only, never a duration +/// (wall-time asserts flake in CI). Compare against the parent commit to see +/// the cap's effect; the cost is hydration count, so the gap grows with the +/// matched-corpus size. +#[tokio::test(flavor = "multi_thread")] +#[ignore = "expensive: ~1.2 GiB corpus + inverted index build; timing instrument"] +async fn times_join_free_ranked_read_issue_563() { + let filler = filler_block(); + let dir = tempfile::tempdir().unwrap(); + let uri = dir.path().to_str().unwrap(); + let db = helpers::session(Omnigraph::init(uri, SCHEMA).await.unwrap()); + + let mut chunk_batch = String::new(); + for c in 0..CHUNKS { + chunk_batch.push_str(&format!( + "{{\"type\":\"Chunk\",\"data\":{{\"slug\":\"chunk-{c:05}\",\"text\":\"needle563 {filler}\"}}}}\n" + )); + if (c + 1) % LOAD_BATCH_ROWS == 0 || c + 1 == CHUNKS { + db.load_jsonl(&chunk_batch, LoadMode::Append).await.unwrap(); + chunk_batch.clear(); + } + } + db.ensure_indices().await.unwrap(); + + let warmup = query_main( + &db, + RANKED_JOIN_QUERY, + "recall_no_join", + ¶ms(&[("$q", "needle563")]), + ) + .await + .unwrap(); + assert_eq!(warmup.num_rows(), 20); + + let mut millis: Vec = Vec::new(); + for _ in 0..5 { + let started = Instant::now(); + let result = query_main( + &db, + RANKED_JOIN_QUERY, + "recall_no_join", + ¶ms(&[("$q", "needle563")]), + ) + .await + .unwrap(); + let elapsed = started.elapsed().as_millis(); + assert_eq!(result.num_rows(), 20); + millis.push(elapsed); + } + millis.sort_unstable(); + println!("TIMING runs_ms={millis:?} median_ms={}", millis[2]); +} diff --git a/scripts/bench-branch-age.py b/benchmarks/deferred/scripts/bench-branch-age.py.disabled similarity index 100% rename from scripts/bench-branch-age.py rename to benchmarks/deferred/scripts/bench-branch-age.py.disabled diff --git a/benchmarks/deferred/sources.json b/benchmarks/deferred/sources.json new file mode 100644 index 000000000..5828b8b1c --- /dev/null +++ b/benchmarks/deferred/sources.json @@ -0,0 +1,118 @@ +{ + "version": 1, + "sources": [ + { + "original": "crates/omnigraph/benches/scenarios.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/benches/scenarios.rs.disabled", + "sha256": "0d5a57283ae028d1452cfd7cad8d4786130e05607a9f29995dd5aa3236ed3d10" + }, + { + "original": "crates/omnigraph/benches/scenarios/branch_control.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/benches/scenarios/branch_control.rs.disabled", + "sha256": "64c982363ffad6d9b22621d5e6aeb206bd8695211218d1b46028110c4f75eb6d" + }, + { + "original": "crates/omnigraph/benches/scenarios/child_protocol.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/benches/scenarios/child_protocol.rs.disabled", + "sha256": "d2eb780470b8041e0dd4cf8885095abf390791ae0a68f3e8f940b9b4b4106571" + }, + { + "original": "crates/omnigraph/benches/scenarios/concurrent_writes.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/benches/scenarios/concurrent_writes.rs.disabled", + "sha256": "c1287fc499601b76d4a5c680e024ce2afbac12faa13ffa374863de979f8a836f" + }, + { + "original": "crates/omnigraph/benches/scenarios/fixture_controls.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/benches/scenarios/fixture_controls.rs.disabled", + "sha256": "647424c8a7c945657ade2fb88619cd330abecc83ce7aa8ddb9691981120677b9" + }, + { + "original": "crates/omnigraph/benches/scenarios/rfc023.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/benches/scenarios/rfc023.rs.disabled", + "sha256": "69bf8c90d391c9e40ea3534ab2b020a63dc983722df1dc113f1e49bdd2533c3f" + }, + { + "original": "crates/omnigraph/benches/scenarios/rfc023_limits.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/benches/scenarios/rfc023_limits.rs.disabled", + "sha256": "c67e07a9d2d215f360ab5bc9701d3033312356ce8c1dc821de8a215a99a115eb" + }, + { + "original": "crates/omnigraph/tests/benchmark_scenario_contract.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/tests/benchmark_scenario_contract.rs.disabled", + "sha256": "77e27581ab16097758f8a14ce065a98c06941fa70cd40f6e2f4c4198b86246b8" + }, + { + "original": "crates/omnigraph/tests/compaction_memory.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/tests/compaction_memory.rs.disabled", + "sha256": "da0779b948e850ef2ff16bb84fec7190520779b1a599571894d1cef4992126cb" + }, + { + "original": "crates/omnigraph/tests/manifest_history_curve.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/tests/manifest_history_curve.rs.disabled", + "sha256": "6f4552d1efc11726021ca063a17730dc3fb22ab3acab1ccfafcc5ad087865d8a" + }, + { + "original": "crates/omnigraph/examples/bench_expand.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/examples/bench_expand.rs.disabled", + "sha256": "3bb763f7f11b478df7cf6e0d8ab4c63e879c53e197f4d796419b2ad9593e7ed3" + }, + { + "original": "crates/omnigraph-bench/examples/compare_engines.rs", + "preserved": "benchmarks/deferred/crates/omnigraph-bench/examples/compare_engines.rs.disabled", + "sha256": "058898de0dda03f0b7f27ac82ccc14cdc58e6a8d1ac06898244ac341de3c2f15" + }, + { + "original": "crates/omnigraph-bench/examples/issue_shapes.rs", + "preserved": "benchmarks/deferred/crates/omnigraph-bench/examples/issue_shapes.rs.disabled", + "sha256": "ba9de1e0701556a1f7d81a6c1e4e65b9678e5ff4a83f89a0756d7cefb38888d7" + }, + { + "original": "crates/omnigraph-server/examples/bench_concurrent_http.rs", + "preserved": "benchmarks/deferred/crates/omnigraph-server/examples/bench_concurrent_http.rs.disabled", + "sha256": "8d2a69efe6f692e3cd618dc8b8c241e9bc33b0893a6965eaff7e2e2d73574bda", + "source_revision": "b54f47096c000fd1db9474a9f7700406a6a80684" + }, + { + "original": "crates/omnigraph-server/examples/bench_actor_isolation.rs", + "preserved": "benchmarks/deferred/crates/omnigraph-server/examples/bench_actor_isolation.rs.disabled", + "sha256": "444927fa177c16bbedff4d31086dca6c363874739fe51d6d31404a025cbfe5f1", + "source_revision": "b54f47096c000fd1db9474a9f7700406a6a80684" + }, + { + "original": "crates/omnigraph-cli/tests/support/http_bench.rs", + "preserved": "benchmarks/deferred/crates/omnigraph-cli/tests/support/http_bench.rs.disabled", + "sha256": "777d8d2e501605ea251ae22006abfac40d277243998efcf5586da5c857ab7557" + }, + { + "original": "crates/omnigraph-cli/tests/support/http_retention.rs", + "preserved": "benchmarks/deferred/crates/omnigraph-cli/tests/support/http_retention.rs.disabled", + "sha256": "e55629847ea1c307801e68e4d949eed0727ebd5bb65d0a91d24de322eb738055" + }, + { + "original": "crates/omnigraph-cli/tests/support/http_soak.rs", + "preserved": "benchmarks/deferred/crates/omnigraph-cli/tests/support/http_soak.rs.disabled", + "sha256": "a7e2ba45fe0f7f4ed76276e0c4e53b3212becdb4a1a19b6cc88d3ddb51d0fe10" + }, + { + "original": "crates/omnigraph-cli/tests/support/http_perf_layout.rs", + "preserved": "benchmarks/deferred/crates/omnigraph-cli/tests/support/http_perf_layout.rs.disabled", + "sha256": "910ddd4ba106205ab10c9990a2ec6d2f7fc1093398c0dc175294c2591f3faa75" + }, + { + "original": "scripts/bench-branch-age.py", + "preserved": "benchmarks/deferred/scripts/bench-branch-age.py.disabled", + "sha256": "fc383889ac57adf5b12c0c4f28bc58e8e13b9c17e0ece226c2847a9b0170d9e3" + }, + { + "original": "crates/omnigraph/tests/manifest_row_bytes.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/tests/manifest_row_bytes.rs.disabled", + "sha256": "ac17cb1dfd6d887b7dbba5e6d7813bee1ef9b60904ce3ea4dae929d46dd0c2c4" + }, + { + "original": "crates/omnigraph/tests/repro_issue_563.rs", + "preserved": "benchmarks/deferred/crates/omnigraph/tests/repro_issue_563.rs.disabled", + "sha256": "6b20f86173b2dea6264ef37fb09a089e52434e83f578b52ca3466980334e22c0", + "retained_active": "Overflow-scale correctness test; timing test removed." + } + ] +} diff --git a/benchmarks/fixtures/branch_merge_d50.gqt b/benchmarks/fixtures/branch_merge_d50.gqt new file mode 100644 index 000000000..ef39e93f5 --- /dev/null +++ b/benchmarks/fixtures/branch_merge_d50.gqt @@ -0,0 +1,837 @@ +# issue: none +# notes: Deterministic keyed edge divergence with one publication per explicit load batch. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node BenchN000 { name: String @key cohort: String? val: I32? payload: String? } +node BenchN001 { name: String @key cohort: String? val: I32? payload: String? } +node BenchN002 { name: String @key cohort: String? val: I32? payload: String? } +node BenchN003 { name: String @key cohort: String? val: I32? payload: String? } +edge BenchE000: BenchN000 -> BenchN001 { cohort: String? val: I32? payload: String? } +edge BenchE001: BenchN001 -> BenchN002 { cohort: String? val: I32? payload: String? } +edge BenchE002: BenchN002 -> BenchN003 { cohort: String? val: I32? payload: String? } +edge BenchE003: BenchN003 -> BenchN000 { cohort: String? val: I32? payload: String? } + +--- seed generate: v1 seed: 0 +tables: + - kind: "node" + name: "BenchN000" + rows: 100000 + commits: 25 + batch_rows: 4096 + columns: + name: {"kind": "key", "prefix": "n000_r", "width": 7} + cohort: {"kind": "literal", "value": "keep"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "x", "count": 64} + - kind: "node" + name: "BenchN001" + rows: 100000 + commits: 25 + batch_rows: 4096 + columns: + name: {"kind": "key", "prefix": "n001_r", "width": 7} + cohort: {"kind": "literal", "value": "keep"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "x", "count": 64} + - kind: "node" + name: "BenchN002" + rows: 100000 + commits: 25 + batch_rows: 4096 + columns: + name: {"kind": "key", "prefix": "n002_r", "width": 7} + cohort: {"kind": "literal", "value": "keep"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "x", "count": 64} + - kind: "node" + name: "BenchN003" + rows: 100000 + commits: 25 + batch_rows: 4096 + columns: + name: {"kind": "key", "prefix": "n003_r", "width": 7} + cohort: {"kind": "literal", "value": "keep"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "x", "count": 64} + - kind: "edge" + name: "BenchE000" + rows: 100000 + commits: 25 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "e000_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "ranges", "ranges": [{"end": 5, "value": "d50_src_upd"}, {"end": 10, "value": "d50_src_del"}, {"end": 15, "value": "d50_tgt_upd"}, {"end": 20, "value": "d50_tgt_del"}], "fallback": "keep"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "x", "count": 64} + - kind: "edge" + name: "BenchE001" + rows: 100000 + commits: 25 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "e001_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "ranges", "ranges": [{"end": 4, "value": "d50_src_upd"}, {"end": 8, "value": "d50_src_del"}, {"end": 12, "value": "d50_tgt_upd"}, {"end": 16, "value": "d50_tgt_del"}], "fallback": "keep"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "x", "count": 64} + - kind: "edge" + name: "BenchE002" + rows: 100000 + commits: 25 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "e002_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "ranges", "ranges": [{"end": 4, "value": "d50_src_upd"}, {"end": 8, "value": "d50_src_del"}, {"end": 12, "value": "d50_tgt_upd"}, {"end": 16, "value": "d50_tgt_del"}], "fallback": "keep"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "x", "count": 64} + - kind: "edge" + name: "BenchE003" + rows: 100000 + commits: 25 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "e003_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "ranges", "ranges": [{"end": 4, "value": "d50_src_upd"}, {"end": 8, "value": "d50_src_del"}, {"end": 12, "value": "d50_tgt_upd"}, {"end": 16, "value": "d50_tgt_del"}], "fallback": "keep"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "x", "count": 64} + +--- mutate +branch create "bench-source" from main +--- expect ok + +--- mutate +branch create "bench-target" from main +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: bench-source +tables: + - kind: "edge" + name: "BenchE000" + rows: 5 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "e000_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "d50_src_upd"} + val: {"kind": "literal", "value": 2147483647} + payload: {"kind": "repeat", "text": "x", "count": 64} +--- expect ok + +--- mutate branch: bench-source +query delete_src_0($c: String) { delete BenchE000 where cohort = $c } +--- params +{"c": "d50_src_del"} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: bench-source +tables: + - kind: "edge" + name: "BenchE001" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "e001_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "d50_src_upd"} + val: {"kind": "literal", "value": 2147483647} + payload: {"kind": "repeat", "text": "x", "count": 64} +--- expect ok + +--- mutate branch: bench-source +query delete_src_1($c: String) { delete BenchE001 where cohort = $c } +--- params +{"c": "d50_src_del"} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: bench-source +tables: + - kind: "edge" + name: "BenchE002" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "e002_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "d50_src_upd"} + val: {"kind": "literal", "value": 2147483647} + payload: {"kind": "repeat", "text": "x", "count": 64} +--- expect ok + +--- mutate branch: bench-source +query delete_src_2($c: String) { delete BenchE002 where cohort = $c } +--- params +{"c": "d50_src_del"} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: bench-source +tables: + - kind: "edge" + name: "BenchE003" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "e003_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "d50_src_upd"} + val: {"kind": "literal", "value": 2147483647} + payload: {"kind": "repeat", "text": "x", "count": 64} +--- expect ok + +--- mutate branch: bench-source +query delete_src_3($c: String) { delete BenchE003 where cohort = $c } +--- params +{"c": "d50_src_del"} +--- expect ok + +--- load generate: v1 seed: 0 mode: append branch: bench-source +tables: + - kind: "edge" + name: "BenchE000" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "src_e000_n", "width": 7} + from: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "new"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "y", "count": 64} +--- expect ok + +--- load generate: v1 seed: 0 mode: append branch: bench-source +tables: + - kind: "edge" + name: "BenchE001" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "src_e001_n", "width": 7} + from: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "new"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "y", "count": 64} +--- expect ok + +--- load generate: v1 seed: 0 mode: append branch: bench-source +tables: + - kind: "edge" + name: "BenchE002" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "src_e002_n", "width": 7} + from: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "new"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "y", "count": 64} +--- expect ok + +--- load generate: v1 seed: 0 mode: append branch: bench-source +tables: + - kind: "edge" + name: "BenchE003" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "src_e003_n", "width": 7} + from: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "new"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "y", "count": 64} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: bench-target +tables: + - kind: "edge" + name: "BenchE000" + rows: 5 + commits: 1 + batch_rows: 4096 + start: 10 + id: {"kind": "key", "prefix": "e000_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "d50_tgt_upd"} + val: {"kind": "literal", "value": 2147483647} + payload: {"kind": "repeat", "text": "x", "count": 64} +--- expect ok + +--- mutate branch: bench-target +query delete_tgt_0($c: String) { delete BenchE000 where cohort = $c } +--- params +{"c": "d50_tgt_del"} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: bench-target +tables: + - kind: "edge" + name: "BenchE001" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 8 + id: {"kind": "key", "prefix": "e001_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "d50_tgt_upd"} + val: {"kind": "literal", "value": 2147483647} + payload: {"kind": "repeat", "text": "x", "count": 64} +--- expect ok + +--- mutate branch: bench-target +query delete_tgt_1($c: String) { delete BenchE001 where cohort = $c } +--- params +{"c": "d50_tgt_del"} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: bench-target +tables: + - kind: "edge" + name: "BenchE002" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 8 + id: {"kind": "key", "prefix": "e002_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "d50_tgt_upd"} + val: {"kind": "literal", "value": 2147483647} + payload: {"kind": "repeat", "text": "x", "count": 64} +--- expect ok + +--- mutate branch: bench-target +query delete_tgt_2($c: String) { delete BenchE002 where cohort = $c } +--- params +{"c": "d50_tgt_del"} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: bench-target +tables: + - kind: "edge" + name: "BenchE003" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 8 + id: {"kind": "key", "prefix": "e003_r", "width": 7} + from: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "d50_tgt_upd"} + val: {"kind": "literal", "value": 2147483647} + payload: {"kind": "repeat", "text": "x", "count": 64} +--- expect ok + +--- mutate branch: bench-target +query delete_tgt_3($c: String) { delete BenchE003 where cohort = $c } +--- params +{"c": "d50_tgt_del"} +--- expect ok + +--- load generate: v1 seed: 0 mode: append branch: bench-target +tables: + - kind: "edge" + name: "BenchE000" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "tgt_e000_n", "width": 7} + from: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "new"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "y", "count": 64} +--- expect ok + +--- load generate: v1 seed: 0 mode: append branch: bench-target +tables: + - kind: "edge" + name: "BenchE001" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "tgt_e001_n", "width": 7} + from: {"kind": "endpoint", "prefix": "n001_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "new"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "y", "count": 64} +--- expect ok + +--- load generate: v1 seed: 0 mode: append branch: bench-target +tables: + - kind: "edge" + name: "BenchE002" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "tgt_e002_n", "width": 7} + from: {"kind": "endpoint", "prefix": "n002_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "new"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "y", "count": 64} +--- expect ok + +--- load generate: v1 seed: 0 mode: append branch: bench-target +tables: + - kind: "edge" + name: "BenchE003" + rows: 4 + commits: 1 + batch_rows: 4096 + start: 0 + id: {"kind": "key", "prefix": "tgt_e003_n", "width": 7} + from: {"kind": "endpoint", "prefix": "n003_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + to: {"kind": "endpoint", "prefix": "n000_r", "width": 7, "population": 100000, "distribution": {"kind": "ordinal"}} + columns: + cohort: {"kind": "literal", "value": "new"} + val: {"kind": "ordinal", "start": 0, "step": 1} + payload: {"kind": "repeat", "text": "y", "count": 64} +--- expect ok + +--- query branch: main +query node_0_main() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_0_main() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":0,"hi":4} +{"cohort":"d50_src_del","n":5,"payloads":5,"lo":5,"hi":9} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":10,"hi":14} +{"cohort":"d50_tgt_del","n":5,"payloads":5,"lo":15,"hi":19} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_1_main() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_1_main() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_2_main() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_2_main() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_3_main() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_3_main() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_0_bench_source() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_0_bench_source() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":10,"hi":14} +{"cohort":"d50_tgt_del","n":5,"payloads":5,"lo":15,"hi":19} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_1_bench_source() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_1_bench_source() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_2_bench_source() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_2_bench_source() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_3_bench_source() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_3_bench_source() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_0_bench_target() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_0_bench_target() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":0,"hi":4} +{"cohort":"d50_src_del","n":5,"payloads":5,"lo":5,"hi":9} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_1_bench_target() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_1_bench_target() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_2_bench_target() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_2_bench_target() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_3_bench_target() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_3_bench_target() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? diff --git a/benchmarks/fixtures/e2e_branch_adopt_untouched.gqt b/benchmarks/fixtures/e2e_branch_adopt_untouched.gqt new file mode 100644 index 000000000..996446bcc --- /dev/null +++ b/benchmarks/fixtures/e2e_branch_adopt_untouched.gqt @@ -0,0 +1,700 @@ +# issue: none +# notes: 64 baseline vectors and three scalar tables; source descends from a never-written target. Checks assert logical branch contracts, not native table fork ownership. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { slug: String @key embedding: Vector(4) } +node Extra1 { slug: String @key } +node Extra2 { slug: String @key } +node Extra3 { slug: String @key } + +--- seed +{"type":"Chunk","data":{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]}} +{"type":"Extra1","data":{"slug":"base"}} +{"type":"Extra2","data":{"slug":"base"}} +{"type":"Extra3","data":{"slug":"base"}} + +--- mutate +branch create "target" from "main" +--- expect ok + +--- mutate +branch create "source" from "target" +--- expect ok + +--- mutate branch: source +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "source-only", embedding: $v } } +--- params +{"v":[1000.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- mutate +branch create "sibling1" from "main" +--- expect ok + +--- mutate +branch create "sibling2" from "main" +--- expect ok + +--- mutate +branch create "sibling3" from "main" +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/fixtures/e2e_branch_adopt_written.gqt b/benchmarks/fixtures/e2e_branch_adopt_written.gqt new file mode 100644 index 000000000..e0d2aa670 --- /dev/null +++ b/benchmarks/fixtures/e2e_branch_adopt_written.gqt @@ -0,0 +1,708 @@ +# issue: none +# notes: 64 baseline vectors and three scalar tables; source descends from a previously written target. Checks assert logical branch contracts, not native table fork ownership. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { slug: String @key embedding: Vector(4) } +node Extra1 { slug: String @key } +node Extra2 { slug: String @key } +node Extra3 { slug: String @key } + +--- seed +{"type":"Chunk","data":{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]}} +{"type":"Extra1","data":{"slug":"base"}} +{"type":"Extra2","data":{"slug":"base"}} +{"type":"Extra3","data":{"slug":"base"}} + +--- mutate +branch create "target" from "main" +--- expect ok + +--- mutate branch: target +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "owner-only", embedding: $v } } +--- params +{"v":[900.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- mutate +branch create "source" from "target" +--- expect ok + +--- mutate branch: source +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "source-only", embedding: $v } } +--- params +{"v":[1000.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- mutate +branch create "sibling1" from "main" +--- expect ok + +--- mutate +branch create "sibling2" from "main" +--- expect ok + +--- mutate +branch create "sibling3" from "main" +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"owner-only","embedding":[900.0,0.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"owner-only","embedding":[900.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/fixtures/e2e_branch_delete.gqt b/benchmarks/fixtures/e2e_branch_delete.gqt new file mode 100644 index 000000000..5506a1a51 --- /dev/null +++ b/benchmarks/fixtures/e2e_branch_delete.gqt @@ -0,0 +1,722 @@ +# issue: none +# notes: Victim writes all four populated tables; five surviving branches have explicit rows. No physical fork or reclamation claim. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { slug: String @key embedding: Vector(4) } +node Extra1 { slug: String @key } +node Extra2 { slug: String @key } +node Extra3 { slug: String @key } + +--- seed +{"type":"Chunk","data":{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]}} +{"type":"Extra1","data":{"slug":"base"}} +{"type":"Extra2","data":{"slug":"base"}} +{"type":"Extra3","data":{"slug":"base"}} + +--- mutate +branch create "source" from "main" +--- expect ok + +--- mutate branch: source +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "source-only", embedding: $v } } +--- params +{"v":[1000.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- mutate +branch create "sibling1" from "main" +--- expect ok + +--- mutate +branch create "sibling2" from "main" +--- expect ok + +--- mutate +branch create "sibling3" from "main" +--- expect ok + +--- mutate +branch create "victim" from "main" +--- expect ok + +--- mutate branch: victim +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "victim-only", embedding: $v } } +--- params +{"v":[1500.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- mutate branch: victim +query own_table() { insert Extra1 { slug: "victim-only" } } +--- expect affected: nodes=1 edges=0 + +--- mutate branch: victim +query own_table() { insert Extra2 { slug: "victim-only" } } +--- expect affected: nodes=1 edges=0 + +--- mutate branch: victim +query own_table() { insert Extra3 { slug: "victim-only" } } +--- expect affected: nodes=1 edges=0 + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"victim"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: victim +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"victim-only","embedding":[1500.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: victim +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +{"slug":"victim-only"} +--- expect shape +slug: String + +--- query branch: victim +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +{"slug":"victim-only"} +--- expect shape +slug: String + +--- query branch: victim +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +{"slug":"victim-only"} +--- expect shape +slug: String + diff --git a/benchmarks/fixtures/e2e_branch_first_write.gqt b/benchmarks/fixtures/e2e_branch_first_write.gqt new file mode 100644 index 000000000..1683d6e8e --- /dev/null +++ b/benchmarks/fixtures/e2e_branch_first_write.gqt @@ -0,0 +1,701 @@ +# issue: none +# notes: Target inherits source including its extra vector; 64 baseline Vector(4) rows, three untouched scalar tables and three unrelated siblings. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { slug: String @key embedding: Vector(4) } +node Extra1 { slug: String @key } +node Extra2 { slug: String @key } +node Extra3 { slug: String @key } + +--- seed +{"type":"Chunk","data":{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]}} +{"type":"Extra1","data":{"slug":"base"}} +{"type":"Extra2","data":{"slug":"base"}} +{"type":"Extra3","data":{"slug":"base"}} + +--- mutate +branch create "source" from "main" +--- expect ok + +--- mutate branch: source +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "source-only", embedding: $v } } +--- params +{"v":[1000.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- mutate +branch create "sibling1" from "main" +--- expect ok + +--- mutate +branch create "sibling2" from "main" +--- expect ok + +--- mutate +branch create "sibling3" from "main" +--- expect ok + +--- mutate +branch create "target" from "source" +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/fixtures/e2e_branch_registry.gqt b/benchmarks/fixtures/e2e_branch_registry.gqt new file mode 100644 index 000000000..6b534eb3a --- /dev/null +++ b/benchmarks/fixtures/e2e_branch_registry.gqt @@ -0,0 +1,599 @@ +# issue: none +# notes: 64 Vector(4) rows plus one row in each of three scalar tables; four existing branches beside main. Source has one extra vector. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { slug: String @key embedding: Vector(4) } +node Extra1 { slug: String @key } +node Extra2 { slug: String @key } +node Extra3 { slug: String @key } + +--- seed +{"type":"Chunk","data":{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]}} +{"type":"Extra1","data":{"slug":"base"}} +{"type":"Extra2","data":{"slug":"base"}} +{"type":"Extra3","data":{"slug":"base"}} + +--- mutate +branch create "source" from "main" +--- expect ok + +--- mutate branch: source +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "source-only", embedding: $v } } +--- params +{"v":[1000.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- mutate +branch create "sibling1" from "main" +--- expect ok + +--- mutate +branch create "sibling2" from "main" +--- expect ok + +--- mutate +branch create "sibling3" from "main" +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/fixtures/e2e_merge_all_changed.gqt b/benchmarks/fixtures/e2e_merge_all_changed.gqt new file mode 100644 index 000000000..5a89659ea --- /dev/null +++ b/benchmarks/fixtures/e2e_merge_all_changed.gqt @@ -0,0 +1,255 @@ +# issue: none +# notes: 64 Vector(4) rows, every source vector changed, one disjoint main insert. Bounded replacement for the Rust merge-all-changed experiment. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { slug: String @key embedding: Vector(4) } + +--- seed +{"type":"Chunk","data":{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]}} + +--- mutate +branch create "source" from "main" +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: source +tables: + - kind: node + name: Chunk + rows: 64 + commits: 1 + batch_rows: 64 + start: 0 + columns: + slug: {kind: key, prefix: base, width: 3} + embedding: {kind: literal, value: [-1.0,0.0,0.0,0.0]} +--- expect ok + +--- mutate branch: main +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "main-only", embedding: $v } } +--- params +{"v":[500.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"main-only","embedding":[500.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base017","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base018","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base019","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base020","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base021","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base022","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base023","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base024","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base025","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base026","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base027","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base028","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base029","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base030","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base031","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base032","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base033","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base034","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base035","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base036","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base037","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base038","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base039","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base040","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base041","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base042","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base043","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base044","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base045","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base046","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base047","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base048","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base049","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base050","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base051","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base052","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base053","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base054","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base055","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base056","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[-1.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + diff --git a/benchmarks/fixtures/e2e_merge_all_new.gqt b/benchmarks/fixtures/e2e_merge_all_new.gqt new file mode 100644 index 000000000..a0aa61add --- /dev/null +++ b/benchmarks/fixtures/e2e_merge_all_new.gqt @@ -0,0 +1,264 @@ +# issue: none +# notes: 64 baseline vectors and 16 new source keys; main is unchanged. Public merge replacement for fenced-adopt-all-new, without the direct Lance append comparator. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { slug: String @key embedding: Vector(4) } + +--- seed +{"type":"Chunk","data":{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]}} + +--- mutate +branch create "source" from "main" +--- expect ok + +--- load generate: v1 seed: 0 mode: append branch: source +tables: + - kind: node + name: Chunk + rows: 16 + commits: 1 + batch_rows: 16 + start: 0 + columns: + slug: {kind: key, prefix: new, width: 3} + embedding: {kind: literal, value: [100.0,0.0,0.0,0.0]} +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"new000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new015","embedding":[100.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + diff --git a/benchmarks/fixtures/e2e_merge_diverged_updates.gqt b/benchmarks/fixtures/e2e_merge_diverged_updates.gqt new file mode 100644 index 000000000..98b10f8c2 --- /dev/null +++ b/benchmarks/fixtures/e2e_merge_diverged_updates.gqt @@ -0,0 +1,261 @@ +# issue: none +# notes: 64 baseline vectors; source updates keys 0..15 and main updates disjoint keys 56..63. Bounded general-merge-updates replacement. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { slug: String @key embedding: Vector(4) } + +--- seed +{"type":"Chunk","data":{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]}} + +--- mutate +branch create "source" from "main" +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: source +tables: + - kind: node + name: Chunk + rows: 16 + commits: 1 + batch_rows: 16 + start: 0 + columns: + slug: {kind: key, prefix: base, width: 3} + embedding: {kind: literal, value: [100.0,0.0,0.0,0.0]} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge branch: main +tables: + - kind: node + name: Chunk + rows: 8 + commits: 1 + batch_rows: 8 + start: 56 + columns: + slug: {kind: key, prefix: base, width: 3} + embedding: {kind: literal, value: [200.0,0.0,0.0,0.0]} +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[200.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + diff --git a/benchmarks/fixtures/e2e_mixed_load.gqt b/benchmarks/fixtures/e2e_mixed_load.gqt new file mode 100644 index 000000000..aaf57603b --- /dev/null +++ b/benchmarks/fixtures/e2e_mixed_load.gqt @@ -0,0 +1,158 @@ +# issue: none +# notes: 64 explicit Vector(4) rows. No raw Lance MergeInsertBuilder or index-toggle baseline. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { slug: String @key embedding: Vector(4) } + +--- seed +{"type":"Chunk","data":{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]}} +{"type":"Chunk","data":{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]}} + +--- query +branch list + +--- expect unordered +{"name":"main"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + diff --git a/benchmarks/fixtures/e2e_nearest_nprobes_one.gqt b/benchmarks/fixtures/e2e_nearest_nprobes_one.gqt new file mode 100644 index 000000000..d7cc798aa --- /dev/null +++ b/benchmarks/fixtures/e2e_nearest_nprobes_one.gqt @@ -0,0 +1,96 @@ +# issue: none +# notes: 64 indexed docs on a line; eligibility n>3 makes d004,d005,d006 exact nearest winners from 2.3. This bounded one-partition setting case does not reproduce custom-centroid or multi-partition ANN probe-budget experiments. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Doc { slug: String @key n: I64 @index embedding: Vector(4) @index } + +--- seed +{"type":"Doc","data":{"slug":"d000","n":0,"embedding":[0.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d001","n":1,"embedding":[1.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d002","n":2,"embedding":[2.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d003","n":3,"embedding":[3.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d004","n":4,"embedding":[4.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d005","n":5,"embedding":[5.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d006","n":6,"embedding":[6.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d007","n":7,"embedding":[7.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d008","n":8,"embedding":[8.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d009","n":9,"embedding":[9.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d010","n":10,"embedding":[10.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d011","n":11,"embedding":[11.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d012","n":12,"embedding":[12.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d013","n":13,"embedding":[13.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d014","n":14,"embedding":[14.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d015","n":15,"embedding":[15.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d016","n":16,"embedding":[16.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d017","n":17,"embedding":[17.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d018","n":18,"embedding":[18.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d019","n":19,"embedding":[19.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d020","n":20,"embedding":[20.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d021","n":21,"embedding":[21.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d022","n":22,"embedding":[22.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d023","n":23,"embedding":[23.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d024","n":24,"embedding":[24.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d025","n":25,"embedding":[25.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d026","n":26,"embedding":[26.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d027","n":27,"embedding":[27.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d028","n":28,"embedding":[28.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d029","n":29,"embedding":[29.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d030","n":30,"embedding":[30.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d031","n":31,"embedding":[31.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d032","n":32,"embedding":[32.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d033","n":33,"embedding":[33.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d034","n":34,"embedding":[34.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d035","n":35,"embedding":[35.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d036","n":36,"embedding":[36.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d037","n":37,"embedding":[37.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d038","n":38,"embedding":[38.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d039","n":39,"embedding":[39.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d040","n":40,"embedding":[40.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d041","n":41,"embedding":[41.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d042","n":42,"embedding":[42.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d043","n":43,"embedding":[43.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d044","n":44,"embedding":[44.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d045","n":45,"embedding":[45.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d046","n":46,"embedding":[46.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d047","n":47,"embedding":[47.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d048","n":48,"embedding":[48.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d049","n":49,"embedding":[49.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d050","n":50,"embedding":[50.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d051","n":51,"embedding":[51.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d052","n":52,"embedding":[52.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d053","n":53,"embedding":[53.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d054","n":54,"embedding":[54.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d055","n":55,"embedding":[55.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d056","n":56,"embedding":[56.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d057","n":57,"embedding":[57.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d058","n":58,"embedding":[58.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d059","n":59,"embedding":[59.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d060","n":60,"embedding":[60.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d061","n":61,"embedding":[61.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d062","n":62,"embedding":[62.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d063","n":63,"embedding":[63.0,0.0,0.0,0.0]}} + +--- query +set ann_nprobes = 1; +query nearest_matching_rows($q: Vector(4)) { + match { $d: Doc $d.n > 3 } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 +} +--- params +{"q":[2.3,0.0,0.0,0.0]} + +--- expect ordered +{"d.slug":"d004"} +{"d.slug":"d005"} +{"d.slug":"d006"} +--- expect shape +d.slug: String + diff --git a/benchmarks/fixtures/e2e_nearest_prefilter.gqt b/benchmarks/fixtures/e2e_nearest_prefilter.gqt new file mode 100644 index 000000000..5f01ab9df --- /dev/null +++ b/benchmarks/fixtures/e2e_nearest_prefilter.gqt @@ -0,0 +1,95 @@ +# issue: none +# notes: 64 docs: 61 closer ineligible decoys and three eligible vectors at squared L2 distances 5, 8 and 13. The exact winners cannot come from post-filtering global top three. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Doc { slug: String @key status: String embedding: Vector(4) @index } + +--- seed +{"type":"Doc","data":{"slug":"miss000","status":"miss","embedding":[1.0,0.0,0.01,0.0]}} +{"type":"Doc","data":{"slug":"miss001","status":"miss","embedding":[1.0,0.0,0.02,0.0]}} +{"type":"Doc","data":{"slug":"miss002","status":"miss","embedding":[1.0,0.0,0.03,0.0]}} +{"type":"Doc","data":{"slug":"miss003","status":"miss","embedding":[1.0,0.0,0.04,0.0]}} +{"type":"Doc","data":{"slug":"miss004","status":"miss","embedding":[1.0,0.0,0.05,0.0]}} +{"type":"Doc","data":{"slug":"miss005","status":"miss","embedding":[1.0,0.0,0.06,0.0]}} +{"type":"Doc","data":{"slug":"miss006","status":"miss","embedding":[1.0,0.0,0.07,0.0]}} +{"type":"Doc","data":{"slug":"miss007","status":"miss","embedding":[1.0,0.0,0.08,0.0]}} +{"type":"Doc","data":{"slug":"miss008","status":"miss","embedding":[1.0,0.0,0.09,0.0]}} +{"type":"Doc","data":{"slug":"miss009","status":"miss","embedding":[1.0,0.0,0.1,0.0]}} +{"type":"Doc","data":{"slug":"miss010","status":"miss","embedding":[1.0,0.0,0.11,0.0]}} +{"type":"Doc","data":{"slug":"miss011","status":"miss","embedding":[1.0,0.0,0.12,0.0]}} +{"type":"Doc","data":{"slug":"miss012","status":"miss","embedding":[1.0,0.0,0.13,0.0]}} +{"type":"Doc","data":{"slug":"miss013","status":"miss","embedding":[1.0,0.0,0.14,0.0]}} +{"type":"Doc","data":{"slug":"miss014","status":"miss","embedding":[1.0,0.0,0.15,0.0]}} +{"type":"Doc","data":{"slug":"miss015","status":"miss","embedding":[1.0,0.0,0.16,0.0]}} +{"type":"Doc","data":{"slug":"miss016","status":"miss","embedding":[1.0,0.0,0.17,0.0]}} +{"type":"Doc","data":{"slug":"miss017","status":"miss","embedding":[1.0,0.0,0.18,0.0]}} +{"type":"Doc","data":{"slug":"miss018","status":"miss","embedding":[1.0,0.0,0.19,0.0]}} +{"type":"Doc","data":{"slug":"miss019","status":"miss","embedding":[1.0,0.0,0.2,0.0]}} +{"type":"Doc","data":{"slug":"miss020","status":"miss","embedding":[1.0,0.0,0.21,0.0]}} +{"type":"Doc","data":{"slug":"miss021","status":"miss","embedding":[1.0,0.0,0.22,0.0]}} +{"type":"Doc","data":{"slug":"miss022","status":"miss","embedding":[1.0,0.0,0.23,0.0]}} +{"type":"Doc","data":{"slug":"miss023","status":"miss","embedding":[1.0,0.0,0.24,0.0]}} +{"type":"Doc","data":{"slug":"miss024","status":"miss","embedding":[1.0,0.0,0.25,0.0]}} +{"type":"Doc","data":{"slug":"miss025","status":"miss","embedding":[1.0,0.0,0.26,0.0]}} +{"type":"Doc","data":{"slug":"miss026","status":"miss","embedding":[1.0,0.0,0.27,0.0]}} +{"type":"Doc","data":{"slug":"miss027","status":"miss","embedding":[1.0,0.0,0.28,0.0]}} +{"type":"Doc","data":{"slug":"miss028","status":"miss","embedding":[1.0,0.0,0.29,0.0]}} +{"type":"Doc","data":{"slug":"miss029","status":"miss","embedding":[1.0,0.0,0.3,0.0]}} +{"type":"Doc","data":{"slug":"miss030","status":"miss","embedding":[1.0,0.0,0.31,0.0]}} +{"type":"Doc","data":{"slug":"miss031","status":"miss","embedding":[1.0,0.0,0.32,0.0]}} +{"type":"Doc","data":{"slug":"miss032","status":"miss","embedding":[1.0,0.0,0.33,0.0]}} +{"type":"Doc","data":{"slug":"miss033","status":"miss","embedding":[1.0,0.0,0.34,0.0]}} +{"type":"Doc","data":{"slug":"miss034","status":"miss","embedding":[1.0,0.0,0.35,0.0]}} +{"type":"Doc","data":{"slug":"miss035","status":"miss","embedding":[1.0,0.0,0.36,0.0]}} +{"type":"Doc","data":{"slug":"miss036","status":"miss","embedding":[1.0,0.0,0.37,0.0]}} +{"type":"Doc","data":{"slug":"miss037","status":"miss","embedding":[1.0,0.0,0.38,0.0]}} +{"type":"Doc","data":{"slug":"miss038","status":"miss","embedding":[1.0,0.0,0.39,0.0]}} +{"type":"Doc","data":{"slug":"miss039","status":"miss","embedding":[1.0,0.0,0.4,0.0]}} +{"type":"Doc","data":{"slug":"miss040","status":"miss","embedding":[1.0,0.0,0.41,0.0]}} +{"type":"Doc","data":{"slug":"miss041","status":"miss","embedding":[1.0,0.0,0.42,0.0]}} +{"type":"Doc","data":{"slug":"miss042","status":"miss","embedding":[1.0,0.0,0.43,0.0]}} +{"type":"Doc","data":{"slug":"miss043","status":"miss","embedding":[1.0,0.0,0.44,0.0]}} +{"type":"Doc","data":{"slug":"miss044","status":"miss","embedding":[1.0,0.0,0.45,0.0]}} +{"type":"Doc","data":{"slug":"miss045","status":"miss","embedding":[1.0,0.0,0.46,0.0]}} +{"type":"Doc","data":{"slug":"miss046","status":"miss","embedding":[1.0,0.0,0.47,0.0]}} +{"type":"Doc","data":{"slug":"miss047","status":"miss","embedding":[1.0,0.0,0.48,0.0]}} +{"type":"Doc","data":{"slug":"miss048","status":"miss","embedding":[1.0,0.0,0.49,0.0]}} +{"type":"Doc","data":{"slug":"miss049","status":"miss","embedding":[1.0,0.0,0.5,0.0]}} +{"type":"Doc","data":{"slug":"miss050","status":"miss","embedding":[1.0,0.0,0.51,0.0]}} +{"type":"Doc","data":{"slug":"miss051","status":"miss","embedding":[1.0,0.0,0.52,0.0]}} +{"type":"Doc","data":{"slug":"miss052","status":"miss","embedding":[1.0,0.0,0.53,0.0]}} +{"type":"Doc","data":{"slug":"miss053","status":"miss","embedding":[1.0,0.0,0.54,0.0]}} +{"type":"Doc","data":{"slug":"miss054","status":"miss","embedding":[1.0,0.0,0.55,0.0]}} +{"type":"Doc","data":{"slug":"miss055","status":"miss","embedding":[1.0,0.0,0.56,0.0]}} +{"type":"Doc","data":{"slug":"miss056","status":"miss","embedding":[1.0,0.0,0.57,0.0]}} +{"type":"Doc","data":{"slug":"miss057","status":"miss","embedding":[1.0,0.0,0.58,0.0]}} +{"type":"Doc","data":{"slug":"miss058","status":"miss","embedding":[1.0,0.0,0.59,0.0]}} +{"type":"Doc","data":{"slug":"miss059","status":"miss","embedding":[1.0,0.0,0.6,0.0]}} +{"type":"Doc","data":{"slug":"miss060","status":"miss","embedding":[1.0,0.0,0.61,0.0]}} +{"type":"Doc","data":{"slug":"hit001","status":"hit","embedding":[-1.0,1.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"hit002","status":"hit","embedding":[-1.0,2.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"hit003","status":"hit","embedding":[-1.0,3.0,0.0,0.0]}} + +--- query +query filtered_nearest($q: Vector(4)) { + match { $d: Doc { status: "hit" } } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 +} +--- params +{"q":[1.0,0.0,0.0,0.0]} + +--- expect ordered +{"d.slug":"hit001"} +{"d.slug":"hit002"} +{"d.slug":"hit003"} +--- expect shape +d.slug: String + diff --git a/benchmarks/fixtures/e2e_query_issues.gqt b/benchmarks/fixtures/e2e_query_issues.gqt new file mode 100644 index 000000000..e2c09c899 --- /dev/null +++ b/benchmarks/fixtures/e2e_query_issues.gqt @@ -0,0 +1,74 @@ +# issue: none +# notes: Bounded issue-query representative: 20 people, two hubs with ten outgoing edges each, and 1024-dimensional generated vectors. Scale, vectors and publication batches differ from the former Rust workload; this has a new timing identity. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Person { + name: String @key + age: I64 + team: String + body: String @index + bio: String + embedding: Vector(1024) +} +edge Knows: Person -> Person + +--- seed generate: v1 seed: 42 +tables: + - kind: node + name: Person + rows: 20 + commits: 1 + batch_rows: 20 + columns: + name: {kind: key, prefix: p, width: 6} + age: {kind: modulo, modulus: 100} + team: {kind: key, prefix: g, width: 0, modulo: 10} + body: + kind: ranges + ranges: + - {end: 1, value: "plain filler words about a person and a team plain filler words about a person and a team plain filler words about a person and a team plain filler words about a person and a team needle"} + - {end: 10, value: "plain filler words about a person and a team plain filler words about a person and a team plain filler words about a person and a team plain filler words about a person and a team "} + - {end: 11, value: "plain filler words about a person and a team plain filler words about a person and a team plain filler words about a person and a team plain filler words about a person and a team needle"} + fallback: "plain filler words about a person and a team plain filler words about a person and a team plain filler words about a person and a team plain filler words about a person and a team " + bio: {kind: repeat, text: "synthetic person biography ", count: 40} + embedding: {kind: vector, dimensions: 1024} + - kind: edge + name: Knows + rows: 10 + commits: 1 + batch_rows: 10 + start: 0 + id: {kind: key, prefix: e, width: 3} + from: {kind: literal, value: p000000} + to: {kind: key, prefix: p, width: 6} + columns: {} + - kind: edge + name: Knows + rows: 10 + commits: 1 + batch_rows: 10 + start: 10 + id: {kind: key, prefix: e, width: 3} + from: {kind: literal, value: p000001} + to: {kind: key, prefix: p, width: 6} + columns: {} + +--- query +query fixture_people() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":20} +--- expect shape +n: I64 + +--- query +query fixture_edges() { match { $p: Person $p knows $q } return { count($q) as n } } +--- expect unordered +{"n":20} +--- expect shape +n: I64 diff --git a/benchmarks/fixtures/e2e_query_shapes.gqt b/benchmarks/fixtures/e2e_query_shapes.gqt new file mode 100644 index 000000000..642cbbc3d --- /dev/null +++ b/benchmarks/fixtures/e2e_query_shapes.gqt @@ -0,0 +1,162 @@ +# issue: none +# notes: Bounded query-shape representative: 100 people and 50 disjoint directed edges. Names start at p000500; generated vectors use the existing GQT seed recipe. Scale, vectors and publication batches differ from the former Rust workload; this has a new timing identity. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Person { + name: String @key + age: I64 + team: String + bio: String + embedding: Vector(32) +} +edge Knows: Person -> Person + +--- seed generate: v1 seed: 42 +tables: + - kind: node + name: Person + rows: 100 + commits: 1 + batch_rows: 100 + start: 500 + columns: + name: {kind: key, prefix: p, width: 6} + age: {kind: modulo, modulus: 100} + team: {kind: key, prefix: g, width: 0, modulo: 10} + bio: {kind: repeat, text: "synthetic person biography ", count: 40} + embedding: {kind: vector, dimensions: 32} + - kind: edge + name: Knows + rows: 50 + commits: 1 + batch_rows: 50 + id: {kind: key, prefix: e, width: 3} + from: + kind: ranges + ranges: + - {end: 1, value: "p000500"} + - {end: 2, value: "p000502"} + - {end: 3, value: "p000504"} + - {end: 4, value: "p000506"} + - {end: 5, value: "p000508"} + - {end: 6, value: "p000510"} + - {end: 7, value: "p000512"} + - {end: 8, value: "p000514"} + - {end: 9, value: "p000516"} + - {end: 10, value: "p000518"} + - {end: 11, value: "p000520"} + - {end: 12, value: "p000522"} + - {end: 13, value: "p000524"} + - {end: 14, value: "p000526"} + - {end: 15, value: "p000528"} + - {end: 16, value: "p000530"} + - {end: 17, value: "p000532"} + - {end: 18, value: "p000534"} + - {end: 19, value: "p000536"} + - {end: 20, value: "p000538"} + - {end: 21, value: "p000540"} + - {end: 22, value: "p000542"} + - {end: 23, value: "p000544"} + - {end: 24, value: "p000546"} + - {end: 25, value: "p000548"} + - {end: 26, value: "p000550"} + - {end: 27, value: "p000552"} + - {end: 28, value: "p000554"} + - {end: 29, value: "p000556"} + - {end: 30, value: "p000558"} + - {end: 31, value: "p000560"} + - {end: 32, value: "p000562"} + - {end: 33, value: "p000564"} + - {end: 34, value: "p000566"} + - {end: 35, value: "p000568"} + - {end: 36, value: "p000570"} + - {end: 37, value: "p000572"} + - {end: 38, value: "p000574"} + - {end: 39, value: "p000576"} + - {end: 40, value: "p000578"} + - {end: 41, value: "p000580"} + - {end: 42, value: "p000582"} + - {end: 43, value: "p000584"} + - {end: 44, value: "p000586"} + - {end: 45, value: "p000588"} + - {end: 46, value: "p000590"} + - {end: 47, value: "p000592"} + - {end: 48, value: "p000594"} + - {end: 49, value: "p000596"} + - {end: 50, value: "p000598"} + fallback: "p000598" + to: + kind: ranges + ranges: + - {end: 1, value: "p000501"} + - {end: 2, value: "p000503"} + - {end: 3, value: "p000505"} + - {end: 4, value: "p000507"} + - {end: 5, value: "p000509"} + - {end: 6, value: "p000511"} + - {end: 7, value: "p000513"} + - {end: 8, value: "p000515"} + - {end: 9, value: "p000517"} + - {end: 10, value: "p000519"} + - {end: 11, value: "p000521"} + - {end: 12, value: "p000523"} + - {end: 13, value: "p000525"} + - {end: 14, value: "p000527"} + - {end: 15, value: "p000529"} + - {end: 16, value: "p000531"} + - {end: 17, value: "p000533"} + - {end: 18, value: "p000535"} + - {end: 19, value: "p000537"} + - {end: 20, value: "p000539"} + - {end: 21, value: "p000541"} + - {end: 22, value: "p000543"} + - {end: 23, value: "p000545"} + - {end: 24, value: "p000547"} + - {end: 25, value: "p000549"} + - {end: 26, value: "p000551"} + - {end: 27, value: "p000553"} + - {end: 28, value: "p000555"} + - {end: 29, value: "p000557"} + - {end: 30, value: "p000559"} + - {end: 31, value: "p000561"} + - {end: 32, value: "p000563"} + - {end: 33, value: "p000565"} + - {end: 34, value: "p000567"} + - {end: 35, value: "p000569"} + - {end: 36, value: "p000571"} + - {end: 37, value: "p000573"} + - {end: 38, value: "p000575"} + - {end: 39, value: "p000577"} + - {end: 40, value: "p000579"} + - {end: 41, value: "p000581"} + - {end: 42, value: "p000583"} + - {end: 43, value: "p000585"} + - {end: 44, value: "p000587"} + - {end: 45, value: "p000589"} + - {end: 46, value: "p000591"} + - {end: 47, value: "p000593"} + - {end: 48, value: "p000595"} + - {end: 49, value: "p000597"} + - {end: 50, value: "p000599"} + fallback: "p000599" + columns: {} + +--- query +query fixture_people() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":100} +--- expect shape +n: I64 + +--- query +query fixture_edges() { match { $p: Person $p knows $q } return { count($q) as n } } +--- expect unordered +{"n":50} +--- expect shape +n: I64 diff --git a/benchmarks/fixtures/e2e_query_wide.gqt b/benchmarks/fixtures/e2e_query_wide.gqt new file mode 100644 index 000000000..88d76d8bb --- /dev/null +++ b/benchmarks/fixtures/e2e_query_wide.gqt @@ -0,0 +1,40 @@ +# issue: none +# notes: Bounded query-shape representative: 32 people. Names start at p000500; generated vectors use the existing GQT seed recipe. Scale, vectors and publication batches differ from the former Rust workload; this has a new timing identity. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Person { + name: String @key + age: I64 + team: String + bio: String + embedding: Vector(32) +} +edge Knows: Person -> Person + +--- seed generate: v1 seed: 42 +tables: + - kind: node + name: Person + rows: 32 + commits: 1 + batch_rows: 32 + start: 500 + columns: + name: {kind: key, prefix: p, width: 6} + age: {kind: modulo, modulus: 100} + team: {kind: key, prefix: g, width: 0, modulo: 10} + bio: {kind: repeat, text: "synthetic person biography ", count: 40} + embedding: {kind: vector, dimensions: 32} + +--- query +query fixture_people() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":32} +--- expect shape +n: I64 diff --git a/benchmarks/fixtures/e2e_rrf_traversal.gqt b/benchmarks/fixtures/e2e_rrf_traversal.gqt new file mode 100644 index 000000000..42a650183 --- /dev/null +++ b/benchmarks/fixtures/e2e_rrf_traversal.gqt @@ -0,0 +1,59 @@ +# issue: none +# notes: Seven text chunks, one artifact and three edges. Four high-ranked alpha decoys have no edge; complete BM25 rankings make x win. Auto RRF planning only; forced-plan process settings and isolated expression construction are not reproduced. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Chunk { + slug: String @key + text: String @index +} + +node Artifact { + slug: String @key +} + +edge ChunkOfArtifact: Chunk -> Artifact + +--- seed +{"type":"Artifact","data":{"slug":"art-0"}} +{"type":"Chunk","data":{"slug":"decoy-1","text":"alpha alpha alpha alpha alpha alpha alpha beta filler filler filler filler filler filler filler filler filler filler filler filler"}} +{"type":"Chunk","data":{"slug":"decoy-2","text":"alpha alpha alpha alpha alpha alpha beta beta filler filler filler filler filler filler filler filler filler filler filler filler"}} +{"type":"Chunk","data":{"slug":"decoy-3","text":"alpha alpha alpha alpha alpha beta beta beta filler filler filler filler filler filler filler filler filler filler filler filler"}} +{"type":"Chunk","data":{"slug":"decoy-4","text":"alpha alpha alpha alpha beta beta beta beta filler filler filler filler filler filler filler filler filler filler filler filler"}} +{"type":"Chunk","data":{"slug":"x","text":"alpha alpha alpha beta beta beta beta beta beta filler filler filler filler filler filler filler filler filler filler filler"}} +{"type":"Chunk","data":{"slug":"y","text":"alpha alpha beta beta beta beta beta filler filler filler filler filler filler filler filler filler filler filler filler filler"}} +{"type":"Chunk","data":{"slug":"n","text":"alpha beta beta beta beta beta beta beta filler filler filler filler filler filler filler filler filler filler filler filler"}} +{"edge":"ChunkOfArtifact","id":"e-x","from":"x","to":"art-0"} +{"edge":"ChunkOfArtifact","id":"e-y","from":"y","to":"art-0"} +{"edge":"ChunkOfArtifact","id":"e-n","from":"n","to":"art-0"} + +--- query +query recall_two_terms($q1: String, $q2: String) { + match { + $c: Chunk + $a: Artifact + $c chunkOfArtifact $a + search($c.text, $q1) + } + return { $c.slug } + order { rrf(bm25($c.text, $q1), bm25($c.text, $q2)) } + limit 1 +} + +--- params +{"q1":"alpha","q2":"beta"} + +--- expect unordered +{"c.slug":"x"} + +--- expect shape +c.slug: String + +--- expect plan +expand $c $a: selection named [ChunkOfArtifact out] +rank fuse row tiebreak [$a.@id] diff --git a/benchmarks/fixtures/e2e_traversal.gqt b/benchmarks/fixtures/e2e_traversal.gqt new file mode 100644 index 000000000..c5bfd329c --- /dev/null +++ b/benchmarks/fixtures/e2e_traversal.gqt @@ -0,0 +1,116 @@ +# issue: none +# notes: Bounded traversal representative: 16 people with directed ring and four-step chord edges (32 total). This deterministic topology, scale and publication batching differ from the former random Rust graph and have a new timing identity. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Person { name: String @key age: I32? } +edge Knows: Person -> Person + +--- seed generate: v1 seed: 42 +tables: + - kind: node + name: Person + rows: 16 + commits: 1 + batch_rows: 16 + columns: + name: {kind: key, prefix: p, width: 0} + age: {kind: ordinal, start: 18, step: 1} + - kind: edge + name: Knows + rows: 32 + commits: 1 + batch_rows: 32 + id: {kind: key, prefix: e, width: 3} + from: + kind: ranges + ranges: + - {end: 1, value: "p0"} + - {end: 2, value: "p0"} + - {end: 3, value: "p1"} + - {end: 4, value: "p1"} + - {end: 5, value: "p2"} + - {end: 6, value: "p2"} + - {end: 7, value: "p3"} + - {end: 8, value: "p3"} + - {end: 9, value: "p4"} + - {end: 10, value: "p4"} + - {end: 11, value: "p5"} + - {end: 12, value: "p5"} + - {end: 13, value: "p6"} + - {end: 14, value: "p6"} + - {end: 15, value: "p7"} + - {end: 16, value: "p7"} + - {end: 17, value: "p8"} + - {end: 18, value: "p8"} + - {end: 19, value: "p9"} + - {end: 20, value: "p9"} + - {end: 21, value: "p10"} + - {end: 22, value: "p10"} + - {end: 23, value: "p11"} + - {end: 24, value: "p11"} + - {end: 25, value: "p12"} + - {end: 26, value: "p12"} + - {end: 27, value: "p13"} + - {end: 28, value: "p13"} + - {end: 29, value: "p14"} + - {end: 30, value: "p14"} + - {end: 31, value: "p15"} + - {end: 32, value: "p15"} + fallback: "p15" + to: + kind: ranges + ranges: + - {end: 1, value: "p1"} + - {end: 2, value: "p4"} + - {end: 3, value: "p2"} + - {end: 4, value: "p5"} + - {end: 5, value: "p3"} + - {end: 6, value: "p6"} + - {end: 7, value: "p4"} + - {end: 8, value: "p7"} + - {end: 9, value: "p5"} + - {end: 10, value: "p8"} + - {end: 11, value: "p6"} + - {end: 12, value: "p9"} + - {end: 13, value: "p7"} + - {end: 14, value: "p10"} + - {end: 15, value: "p8"} + - {end: 16, value: "p11"} + - {end: 17, value: "p9"} + - {end: 18, value: "p12"} + - {end: 19, value: "p10"} + - {end: 20, value: "p13"} + - {end: 21, value: "p11"} + - {end: 22, value: "p14"} + - {end: 23, value: "p12"} + - {end: 24, value: "p15"} + - {end: 25, value: "p13"} + - {end: 26, value: "p0"} + - {end: 27, value: "p14"} + - {end: 28, value: "p1"} + - {end: 29, value: "p15"} + - {end: 30, value: "p2"} + - {end: 31, value: "p0"} + - {end: 32, value: "p3"} + fallback: "p3" + columns: {} + +--- query +query fixture_people() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":16} +--- expect shape +n: I64 + +--- query +query fixture_edges() { match { $p: Person $p knows $q } return { count($q) as n } } +--- expect unordered +{"n":32} +--- expect shape +n: I64 diff --git a/benchmarks/fixtures/equal_current_narrow_one_batch.gqt b/benchmarks/fixtures/equal_current_narrow_one_batch.gqt new file mode 100644 index 000000000..06de107ab --- /dev/null +++ b/benchmarks/fixtures/equal_current_narrow_one_batch.gqt @@ -0,0 +1,58 @@ +# issue: none +# notes: Eight past/restore cycles with payload 8 bytes and 1 publication(s) per load; equal final rows, deliberate retained-history difference. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node HistoryRow { key: String @key value: I64 payload: String } + +--- seed +{"type":"HistoryRow","data":{"key":"row-0","value":0,"payload":"final"}} +{"type":"HistoryRow","data":{"key":"row-1","value":0,"payload":"final"}} +{"type":"HistoryRow","data":{"key":"row-2","value":0,"payload":"final"}} +{"type":"HistoryRow","data":{"key":"row-3","value":0,"payload":"final"}} + +--- loop $cycle 0 8 +--- load generate: v1 seed: 0 mode: merge +tables: + - kind: node + name: HistoryRow + rows: 4 + commits: 1 + batch_rows: 4 + columns: + key: {kind: key, prefix: row-, width: 1} + value: {kind: literal, value: 0} + payload: {kind: repeat, text: x, count: 8} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge +tables: + - kind: node + name: HistoryRow + rows: 4 + commits: 1 + batch_rows: 4 + columns: + key: {kind: key, prefix: row-, width: 1} + value: {kind: literal, value: 0} + payload: {kind: literal, value: final} +--- expect ok + +--- endloop + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"row-0","value":0,"payload":"final"} +{"key":"row-1","value":0,"payload":"final"} +{"key":"row-2","value":0,"payload":"final"} +{"key":"row-3","value":0,"payload":"final"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/fixtures/equal_current_wide_four_batches.gqt b/benchmarks/fixtures/equal_current_wide_four_batches.gqt new file mode 100644 index 000000000..4aea6abbf --- /dev/null +++ b/benchmarks/fixtures/equal_current_wide_four_batches.gqt @@ -0,0 +1,58 @@ +# issue: none +# notes: Eight past/restore cycles with payload 4096 bytes and 4 publication(s) per load; equal final rows, deliberate retained-history difference. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node HistoryRow { key: String @key value: I64 payload: String } + +--- seed +{"type":"HistoryRow","data":{"key":"row-0","value":0,"payload":"final"}} +{"type":"HistoryRow","data":{"key":"row-1","value":0,"payload":"final"}} +{"type":"HistoryRow","data":{"key":"row-2","value":0,"payload":"final"}} +{"type":"HistoryRow","data":{"key":"row-3","value":0,"payload":"final"}} + +--- loop $cycle 0 8 +--- load generate: v1 seed: 0 mode: merge +tables: + - kind: node + name: HistoryRow + rows: 4 + commits: 4 + batch_rows: 1 + columns: + key: {kind: key, prefix: row-, width: 1} + value: {kind: literal, value: 0} + payload: {kind: repeat, text: x, count: 4096} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge +tables: + - kind: node + name: HistoryRow + rows: 4 + commits: 4 + batch_rows: 1 + columns: + key: {kind: key, prefix: row-, width: 1} + value: {kind: literal, value: 0} + payload: {kind: literal, value: final} +--- expect ok + +--- endloop + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"row-0","value":0,"payload":"final"} +{"key":"row-1","value":0,"payload":"final"} +{"key":"row-2","value":0,"payload":"final"} +{"key":"row-3","value":0,"payload":"final"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/fixtures/equal_current_wide_one_batch.gqt b/benchmarks/fixtures/equal_current_wide_one_batch.gqt new file mode 100644 index 000000000..6a4b120e1 --- /dev/null +++ b/benchmarks/fixtures/equal_current_wide_one_batch.gqt @@ -0,0 +1,58 @@ +# issue: none +# notes: Eight past/restore cycles with payload 4096 bytes and 1 publication(s) per load; equal final rows, deliberate retained-history difference. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node HistoryRow { key: String @key value: I64 payload: String } + +--- seed +{"type":"HistoryRow","data":{"key":"row-0","value":0,"payload":"final"}} +{"type":"HistoryRow","data":{"key":"row-1","value":0,"payload":"final"}} +{"type":"HistoryRow","data":{"key":"row-2","value":0,"payload":"final"}} +{"type":"HistoryRow","data":{"key":"row-3","value":0,"payload":"final"}} + +--- loop $cycle 0 8 +--- load generate: v1 seed: 0 mode: merge +tables: + - kind: node + name: HistoryRow + rows: 4 + commits: 1 + batch_rows: 4 + columns: + key: {kind: key, prefix: row-, width: 1} + value: {kind: literal, value: 0} + payload: {kind: repeat, text: x, count: 4096} +--- expect ok + +--- load generate: v1 seed: 0 mode: merge +tables: + - kind: node + name: HistoryRow + rows: 4 + commits: 1 + batch_rows: 4 + columns: + key: {kind: key, prefix: row-, width: 1} + value: {kind: literal, value: 0} + payload: {kind: literal, value: final} +--- expect ok + +--- endloop + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"row-0","value":0,"payload":"final"} +{"key":"row-1","value":0,"payload":"final"} +{"key":"row-2","value":0,"payload":"final"} +{"key":"row-3","value":0,"payload":"final"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/fixtures/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml b/benchmarks/fixtures/finbench/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml similarity index 100% rename from benchmarks/fixtures/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml rename to benchmarks/fixtures/finbench/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml diff --git a/benchmarks/fixtures/finbench/finbench_disjoint.gqt b/benchmarks/fixtures/finbench/finbench_disjoint.gqt new file mode 100644 index 000000000..85e625014 --- /dev/null +++ b/benchmarks/fixtures/finbench/finbench_disjoint.gqt @@ -0,0 +1,249 @@ +# issue: none +# notes: FinBench disjoint inserts; generated transfer IDs use logical-equivalence identity. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query branch: main +query reserved_accounts() { + match { $a: Account + $a.accountId starts_with "omnigraph-bench-fin-v1-" } + return { $a.accountId as account, $a.createTime as created, $a.isBlocked as blocked, $a.accountType as kind, $a.freqLoginType as login, $a.accountLevel as level, $a.nickname as nickname, $a.phonenum as phonenum, $a.email as email, $a.lastLoginTime as last_login } +} +--- expect unordered +--- expect shape +account: String +created: DateTime +blocked: Bool +kind: String +login: String +level: String +nickname: String? +phonenum: String? +email: String? +last_login: DateTime? + +--- query branch: main +query reserved_transfers() { + match { $a: Account + $a $e:accounttransferaccount $b + $e.orderNum starts_with "omnigraph-bench-fin-v1-" } + return { $e.@src as src, $e.@dst as dst, $e.amount as amount, $e.createTime as created, $e.orderNum as order_num, $e.payType as pay, $e.goodsType as goods, $e.comment as comment } +} +--- expect unordered +--- expect shape +src: String +dst: String +amount: F64 +created: DateTime +order_num: String +pay: String +goods: String +comment: String? + +--- mutate +branch create "bench-source" from main +--- expect ok + +--- mutate branch: bench-source +query prepare_src() { + insert Account { accountId: "omnigraph-bench-fin-v1-src-a", createTime: datetime("2020-01-01T00:00:00Z"), isBlocked: false, accountType: "internet_account", freqLoginType: "ipv4", accountLevel: "basic" } + insert Account { accountId: "omnigraph-bench-fin-v1-src-b", createTime: datetime("2020-01-01T00:00:00Z"), isBlocked: false, accountType: "internet_account", freqLoginType: "ipv4", accountLevel: "basic" } + insert AccountTransferAccount { from: "omnigraph-bench-fin-v1-src-a", to: "omnigraph-bench-fin-v1-src-b", amount: 1.25, createTime: datetime("2020-01-01T00:00:00Z"), orderNum: "omnigraph-bench-fin-v1-src-order", payType: "bank_transfer", goodsType: "bank_transfer" } +} +--- expect affected: nodes=2 edges=1 + +--- query branch: bench-source +query reserved_accounts() { + match { $a: Account + $a.accountId starts_with "omnigraph-bench-fin-v1-" } + return { $a.accountId as account, $a.createTime as created, $a.isBlocked as blocked, $a.accountType as kind, $a.freqLoginType as login, $a.accountLevel as level, $a.nickname as nickname, $a.phonenum as phonenum, $a.email as email, $a.lastLoginTime as last_login } +} +--- expect unordered +{"account":"omnigraph-bench-fin-v1-src-a","created":"2020-01-01T00:00:00","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +{"account":"omnigraph-bench-fin-v1-src-b","created":"2020-01-01T00:00:00","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +--- expect shape +account: String +created: DateTime +blocked: Bool +kind: String +login: String +level: String +nickname: String? +phonenum: String? +email: String? +last_login: DateTime? + +--- query branch: bench-source +query reserved_transfers() { + match { $a: Account + $a $e:accounttransferaccount $b + $e.orderNum starts_with "omnigraph-bench-fin-v1-" } + return { $e.@src as src, $e.@dst as dst, $e.amount as amount, $e.createTime as created, $e.orderNum as order_num, $e.payType as pay, $e.goodsType as goods, $e.comment as comment } +} +--- expect unordered +{"src":"omnigraph-bench-fin-v1-src-a","dst":"omnigraph-bench-fin-v1-src-b","amount":1.25,"created":"2020-01-01T00:00:00","order_num":"omnigraph-bench-fin-v1-src-order","pay":"bank_transfer","goods":"bank_transfer"} +--- expect shape +src: String +dst: String +amount: F64 +created: DateTime +order_num: String +pay: String +goods: String +comment: String? + +--- query branch: bench-source +query account_count() { + match { $a: Account } + return { count($a) as n } +} +--- expect unordered +{"n":1534182} +--- expect shape +n: I64 + +--- query branch: bench-source +query transfer_count() { + match { $a: Account + $a $e:accounttransferaccount $b } + return { count($e) as n } +} +--- expect unordered +{"n":6219882} +--- expect shape +n: I64 + +--- mutate +branch create "bench-target" from main +--- expect ok + +--- mutate branch: bench-target +query prepare_tgt() { + insert Account { accountId: "omnigraph-bench-fin-v1-tgt-a", createTime: datetime("2020-01-01T00:00:01Z"), isBlocked: false, accountType: "internet_account", freqLoginType: "ipv4", accountLevel: "basic" } + insert Account { accountId: "omnigraph-bench-fin-v1-tgt-b", createTime: datetime("2020-01-01T00:00:01Z"), isBlocked: false, accountType: "internet_account", freqLoginType: "ipv4", accountLevel: "basic" } + insert AccountTransferAccount { from: "omnigraph-bench-fin-v1-tgt-a", to: "omnigraph-bench-fin-v1-tgt-b", amount: 2.5, createTime: datetime("2020-01-01T00:00:01Z"), orderNum: "omnigraph-bench-fin-v1-tgt-order", payType: "bank_transfer", goodsType: "bank_transfer" } +} +--- expect affected: nodes=2 edges=1 + +--- query branch: bench-target +query reserved_accounts() { + match { $a: Account + $a.accountId starts_with "omnigraph-bench-fin-v1-" } + return { $a.accountId as account, $a.createTime as created, $a.isBlocked as blocked, $a.accountType as kind, $a.freqLoginType as login, $a.accountLevel as level, $a.nickname as nickname, $a.phonenum as phonenum, $a.email as email, $a.lastLoginTime as last_login } +} +--- expect unordered +{"account":"omnigraph-bench-fin-v1-tgt-a","created":"2020-01-01T00:00:01","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +{"account":"omnigraph-bench-fin-v1-tgt-b","created":"2020-01-01T00:00:01","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +--- expect shape +account: String +created: DateTime +blocked: Bool +kind: String +login: String +level: String +nickname: String? +phonenum: String? +email: String? +last_login: DateTime? + +--- query branch: bench-target +query reserved_transfers() { + match { $a: Account + $a $e:accounttransferaccount $b + $e.orderNum starts_with "omnigraph-bench-fin-v1-" } + return { $e.@src as src, $e.@dst as dst, $e.amount as amount, $e.createTime as created, $e.orderNum as order_num, $e.payType as pay, $e.goodsType as goods, $e.comment as comment } +} +--- expect unordered +{"src":"omnigraph-bench-fin-v1-tgt-a","dst":"omnigraph-bench-fin-v1-tgt-b","amount":2.5,"created":"2020-01-01T00:00:01","order_num":"omnigraph-bench-fin-v1-tgt-order","pay":"bank_transfer","goods":"bank_transfer"} +--- expect shape +src: String +dst: String +amount: F64 +created: DateTime +order_num: String +pay: String +goods: String +comment: String? + +--- query branch: bench-target +query account_count() { + match { $a: Account } + return { count($a) as n } +} +--- expect unordered +{"n":1534182} +--- expect shape +n: I64 + +--- query branch: bench-target +query transfer_count() { + match { $a: Account + $a $e:accounttransferaccount $b } + return { count($e) as n } +} +--- expect unordered +{"n":6219882} +--- expect shape +n: I64 + +--- query branch: main +query reserved_accounts() { + match { $a: Account + $a.accountId starts_with "omnigraph-bench-fin-v1-" } + return { $a.accountId as account, $a.createTime as created, $a.isBlocked as blocked, $a.accountType as kind, $a.freqLoginType as login, $a.accountLevel as level, $a.nickname as nickname, $a.phonenum as phonenum, $a.email as email, $a.lastLoginTime as last_login } +} +--- expect unordered +--- expect shape +account: String +created: DateTime +blocked: Bool +kind: String +login: String +level: String +nickname: String? +phonenum: String? +email: String? +last_login: DateTime? + +--- query branch: main +query reserved_transfers() { + match { $a: Account + $a $e:accounttransferaccount $b + $e.orderNum starts_with "omnigraph-bench-fin-v1-" } + return { $e.@src as src, $e.@dst as dst, $e.amount as amount, $e.createTime as created, $e.orderNum as order_num, $e.payType as pay, $e.goodsType as goods, $e.comment as comment } +} +--- expect unordered +--- expect shape +src: String +dst: String +amount: F64 +created: DateTime +order_num: String +pay: String +goods: String +comment: String? + +--- query branch: main +query account_count() { + match { $a: Account } + return { count($a) as n } +} +--- expect unordered +{"n":1534180} +--- expect shape +n: I64 + +--- query branch: main +query transfer_count() { + match { $a: Account + $a $e:accounttransferaccount $b } + return { count($e) as n } +} +--- expect unordered +{"n":6219881} +--- expect shape +n: I64 diff --git a/benchmarks/fixtures/hot_table_idle_base.gqt b/benchmarks/fixtures/hot_table_idle_base.gqt new file mode 100644 index 000000000..db5a5d8ec --- /dev/null +++ b/benchmarks/fixtures/hot_table_idle_base.gqt @@ -0,0 +1,29 @@ +# issue: none +# notes: Hot row stays fixed while idle table, branch and unrelated-history axes are isolated: base. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Hot { key: String @key value: I64 } + +--- seed +{"type":"Hot","data":{"key":"hot","value":0}} + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String diff --git a/benchmarks/fixtures/hot_table_idle_branches_4.gqt b/benchmarks/fixtures/hot_table_idle_branches_4.gqt new file mode 100644 index 000000000..aa7d59dbd --- /dev/null +++ b/benchmarks/fixtures/hot_table_idle_branches_4.gqt @@ -0,0 +1,81 @@ +# issue: none +# notes: Hot row stays fixed while idle table, branch and unrelated-history axes are isolated: branches-4. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Hot { key: String @key value: I64 } + +--- seed +{"type":"Hot","data":{"key":"hot","value":0}} + +--- mutate +branch create "idle0" from main +--- expect ok + +--- mutate +branch create "idle1" from main +--- expect ok + +--- mutate +branch create "idle2" from main +--- expect ok + +--- mutate +branch create "idle3" from main +--- expect ok + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle0 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle1 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle2 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle3 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"idle0"} +{"name":"idle1"} +{"name":"idle2"} +{"name":"idle3"} +--- expect shape +name: String diff --git a/benchmarks/fixtures/hot_table_idle_branches_4_aged.gqt b/benchmarks/fixtures/hot_table_idle_branches_4_aged.gqt new file mode 100644 index 000000000..4fce52d43 --- /dev/null +++ b/benchmarks/fixtures/hot_table_idle_branches_4_aged.gqt @@ -0,0 +1,92 @@ +# issue: none +# notes: Hot row stays fixed while idle table, branch and unrelated-history axes are isolated: branches-4-aged. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Hot { key: String @key value: I64 } + +--- seed +{"type":"Hot","data":{"key":"hot","value":0}} + +--- mutate +branch create "idle0" from main +--- expect ok + +--- mutate +branch create "idle1" from main +--- expect ok + +--- mutate +branch create "idle2" from main +--- expect ok + +--- mutate +branch create "idle3" from main +--- expect ok + +--- loop $cycle 0 4 +--- mutate branch: idle0 +query unrelated_one() { update Hot set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- mutate branch: idle0 +query unrelated_zero() { update Hot set { value: 0 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle0 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle1 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle2 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle3 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"idle0"} +{"name":"idle1"} +{"name":"idle2"} +{"name":"idle3"} +--- expect shape +name: String diff --git a/benchmarks/fixtures/hot_table_idle_tables_4.gqt b/benchmarks/fixtures/hot_table_idle_tables_4.gqt new file mode 100644 index 000000000..1b3b4ba0e --- /dev/null +++ b/benchmarks/fixtures/hot_table_idle_tables_4.gqt @@ -0,0 +1,69 @@ +# issue: none +# notes: Hot row stays fixed while idle table, branch and unrelated-history axes are isolated: tables-4. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Hot { key: String @key value: I64 } +node Idle0 { key: String @key value: I64 } +node Idle1 { key: String @key value: I64 } +node Idle2 { key: String @key value: I64 } +node Idle3 { key: String @key value: I64 } + +--- seed +{"type":"Hot","data":{"key":"hot","value":0}} +{"type":"Idle0","data":{"key":"sentinel","value":0}} +{"type":"Idle1","data":{"key":"sentinel","value":0}} +{"type":"Idle2","data":{"key":"sentinel","value":0}} +{"type":"Idle3","data":{"key":"sentinel","value":0}} + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String diff --git a/benchmarks/fixtures/identity_lifecycle.gqt b/benchmarks/fixtures/identity_lifecycle.gqt new file mode 100644 index 000000000..ec53f1531 --- /dev/null +++ b/benchmarks/fixtures/identity_lifecycle.gqt @@ -0,0 +1,74 @@ +# issue: none +# notes: Sequential branch-name reuse with a live child retaining the old lifetime; no table-schema lifecycle or held-snapshot claim. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Item { key: String @key value: I64 } + +--- seed +{"type":"Item","data":{"key":"alice","value":0}} + +--- mutate +branch create "feature" from main +--- expect ok + +--- mutate branch: feature +query old_write() { insert Item { key: "old_only", value: 10 } } +--- expect affected: nodes=1 edges=0 + +--- mutate +branch create "old_child" from "feature" +--- expect ok + +--- mutate +branch delete "feature" +--- expect ok + +--- mutate +query main_write() { insert Item { key: "new_main", value: 20 } } +--- expect affected: nodes=1 edges=0 + +--- mutate +branch create "feature" from main +--- expect ok + +--- query branch: main +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"alice","value":0} +{"key":"new_main","value":20} +--- expect shape +key: String +value: I64 + +--- query branch: feature +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"alice","value":0} +{"key":"new_main","value":20} +--- expect shape +key: String +value: I64 + +--- query branch: old_child +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"alice","value":0} +{"key":"old_only","value":10} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"feature"} +{"name":"old_child"} +--- expect shape +name: String diff --git a/benchmarks/fixtures/nearest_ranks_updated_embedding.gqt b/benchmarks/fixtures/nearest_ranks_updated_embedding.gqt new file mode 100644 index 000000000..4ef68e1c7 --- /dev/null +++ b/benchmarks/fixtures/nearest_ranks_updated_embedding.gqt @@ -0,0 +1,34 @@ +# issue: none +# notes: Move d004 from 4.0 to -1.0 after indexing. It must rank second from -0.3. +# notes: Limit 6 exceeds the five live rows, so the old vector must not appear as a duplicate. + +--- runner +timeout_ms: 10000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Doc { + slug: String @key + n: I64 @index + name: String @index + embedding: Vector(4) @index +} + +--- seed +{"type":"Doc","data":{"slug":"d000","n":0,"name":"doc-000","embedding":[0.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d001","n":1,"name":"doc-001","embedding":[1.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d002","n":2,"name":"doc-002","embedding":[2.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d003","n":3,"name":"doc-003","embedding":[3.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d004","n":4,"name":"doc-004","embedding":[4.0,0.0,0.0,0.0]}} + +--- mutate +query move_embedding($s: String, $e: Vector(4)) { + update Doc set { embedding: $e } where slug = $s +} + +--- params +{"s": "d004", "e": [-1.0, 0.0, 0.0, 0.0]} + +--- expect affected: nodes=1 edges=0 diff --git a/benchmarks/fixtures/nearest_skips_deleted_rows_and_fills_limit.gqt b/benchmarks/fixtures/nearest_skips_deleted_rows_and_fills_limit.gqt new file mode 100644 index 000000000..ec50b38f3 --- /dev/null +++ b/benchmarks/fixtures/nearest_skips_deleted_rows_and_fills_limit.gqt @@ -0,0 +1,56 @@ +# issue: none +# notes: Delete the first three neighbors after indexing. Limit 3 must fill from the five survivors. + +--- runner +timeout_ms: 10000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Doc { + slug: String @key + n: I64 @index + name: String @index + embedding: Vector(4) @index +} + +--- seed +{"type":"Doc","data":{"slug":"d000","n":0,"name":"doc-000","embedding":[0.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d001","n":1,"name":"doc-001","embedding":[1.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d002","n":2,"name":"doc-002","embedding":[2.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d003","n":3,"name":"doc-003","embedding":[3.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d004","n":4,"name":"doc-004","embedding":[4.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d005","n":5,"name":"doc-005","embedding":[5.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d006","n":6,"name":"doc-006","embedding":[6.0,0.0,0.0,0.0]}} +{"type":"Doc","data":{"slug":"d007","n":7,"name":"doc-007","embedding":[7.0,0.0,0.0,0.0]}} + +--- mutate +query delete_doc($s: String) { + delete Doc where slug = $s +} + +--- params +{"s": "d000"} + +--- expect affected: nodes=1 edges=0 + +--- mutate +query delete_doc($s: String) { + delete Doc where slug = $s +} + +--- params +{"s": "d001"} + +--- expect affected: nodes=1 edges=0 + +--- mutate +query delete_doc($s: String) { + delete Doc where slug = $s +} + +--- params +{"s": "d002"} + +--- expect affected: nodes=1 edges=0 diff --git a/benchmarks/fixtures/parallel_tables.gqt b/benchmarks/fixtures/parallel_tables.gqt new file mode 100644 index 000000000..6bde41bae --- /dev/null +++ b/benchmarks/fixtures/parallel_tables.gqt @@ -0,0 +1,52 @@ +# issue: none +# notes: Four fixed registered tables; touched-table count is the independent query axis. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node T0 { key: String @key value: I64 } +node T1 { key: String @key value: I64 } +node T2 { key: String @key value: I64 } +node T3 { key: String @key value: I64 } + +--- seed +{"type":"T0","data":{"key":"row","value":0}} +{"type":"T1","data":{"key":"row","value":0}} +{"type":"T2","data":{"key":"row","value":0}} +{"type":"T3","data":{"key":"row","value":0}} + +--- query branch: main +query current_rows() { match { $r: T0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 diff --git a/benchmarks/fixtures/repeated_deletion_recreation_branches.gqt b/benchmarks/fixtures/repeated_deletion_recreation_branches.gqt new file mode 100644 index 000000000..eab99cf91 --- /dev/null +++ b/benchmarks/fixtures/repeated_deletion_recreation_branches.gqt @@ -0,0 +1,55 @@ +# issue: none +# notes: Four sequential branches deletion/recreation cycles; live population stays bounded; no cleanup or thousand-cycle evidence. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Item { key: String @key value: I64 } + +--- seed +{"type":"Item","data":{"key":"baseline","value":0}} + +--- loop $cycle 0 4 +--- mutate +branch create "recycled" from main +--- expect ok + +--- mutate branch: recycled +query add_temporary($v: I64) { insert Item { key: "temporary", value: $v } } +--- params +{"v": ${cycle}} +--- expect affected: nodes=1 edges=0 + +--- query branch: recycled +query cycle_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +{"key":"temporary","value":${cycle}} +--- expect shape +key: String +value: I64 + +--- mutate +branch delete "recycled" +--- expect ok + +--- query branch: main +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +--- expect shape +key: String +value: I64 + +--- endloop + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String diff --git a/benchmarks/fixtures/repeated_deletion_recreation_rows.gqt b/benchmarks/fixtures/repeated_deletion_recreation_rows.gqt new file mode 100644 index 000000000..ffbe54d3b --- /dev/null +++ b/benchmarks/fixtures/repeated_deletion_recreation_rows.gqt @@ -0,0 +1,51 @@ +# issue: none +# notes: Four sequential rows deletion/recreation cycles; live population stays bounded; no cleanup or thousand-cycle evidence. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Item { key: String @key value: I64 } + +--- seed +{"type":"Item","data":{"key":"baseline","value":0}} + +--- loop $cycle 0 4 +--- mutate +query add_temporary($v: I64) { insert Item { key: "temporary", value: $v } } +--- params +{"v": ${cycle}} +--- expect affected: nodes=1 edges=0 + +--- query +query cycle_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +{"key":"temporary","value":${cycle}} +--- expect shape +key: String +value: I64 + +--- mutate +query delete_temporary() { delete Item where key = "temporary" } +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +--- expect shape +key: String +value: I64 + +--- endloop + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String diff --git a/benchmarks/fixtures/threshold_crossings_after.gqt b/benchmarks/fixtures/threshold_crossings_after.gqt new file mode 100644 index 000000000..f3affa5e0 --- /dev/null +++ b/benchmarks/fixtures/threshold_crossings_after.gqt @@ -0,0 +1,50 @@ +# issue: none +# notes: Configured history-release shape after at budget 2048 bytes; row assertions do not claim a release counter. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Person { name: String @key age: I32 } + +--- seed +{"type":"Person","data":{"name":"alice","age":0}} +{"type":"Person","data":{"name":"bob","age":0}} + +--- mutate +set history_release_bytes = 2048; +--- expect ok + +--- mutate +branch create "b" from main +--- expect ok + +--- loop $i 1 5 +--- mutate branch: b +query bump($n: I32) { update Person set { age: $n } where name = "alice" } +--- params +{"n": ${i}} +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":4} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 diff --git a/benchmarks/fixtures/threshold_crossings_at.gqt b/benchmarks/fixtures/threshold_crossings_at.gqt new file mode 100644 index 000000000..1cc514827 --- /dev/null +++ b/benchmarks/fixtures/threshold_crossings_at.gqt @@ -0,0 +1,50 @@ +# issue: none +# notes: Configured history-release shape at at budget 2048 bytes; row assertions do not claim a release counter. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Person { name: String @key age: I32 } + +--- seed +{"type":"Person","data":{"name":"alice","age":0}} +{"type":"Person","data":{"name":"bob","age":0}} + +--- mutate +set history_release_bytes = 2048; +--- expect ok + +--- mutate +branch create "b" from main +--- expect ok + +--- loop $i 1 4 +--- mutate branch: b +query bump($n: I32) { update Person set { age: $n } where name = "alice" } +--- params +{"n": ${i}} +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":3} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 diff --git a/benchmarks/fixtures/threshold_crossings_before.gqt b/benchmarks/fixtures/threshold_crossings_before.gqt new file mode 100644 index 000000000..85d643710 --- /dev/null +++ b/benchmarks/fixtures/threshold_crossings_before.gqt @@ -0,0 +1,50 @@ +# issue: none +# notes: Configured history-release shape before at budget 2048 bytes; row assertions do not claim a release counter. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Person { name: String @key age: I32 } + +--- seed +{"type":"Person","data":{"name":"alice","age":0}} +{"type":"Person","data":{"name":"bob","age":0}} + +--- mutate +set history_release_bytes = 2048; +--- expect ok + +--- mutate +branch create "b" from main +--- expect ok + +--- loop $i 1 3 +--- mutate branch: b +query bump($n: I32) { update Person set { age: $n } where name = "alice" } +--- params +{"n": ${i}} +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":2} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 diff --git a/benchmarks/fixtures/threshold_crossings_production_control.gqt b/benchmarks/fixtures/threshold_crossings_production_control.gqt new file mode 100644 index 000000000..db6c5dc21 --- /dev/null +++ b/benchmarks/fixtures/threshold_crossings_production_control.gqt @@ -0,0 +1,50 @@ +# issue: none +# notes: Configured history-release shape production-control at budget 262144 bytes; row assertions do not claim a release counter. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Person { name: String @key age: I32 } + +--- seed +{"type":"Person","data":{"name":"alice","age":0}} +{"type":"Person","data":{"name":"bob","age":0}} + +--- mutate +set history_release_bytes = 262144; +--- expect ok + +--- mutate +branch create "b" from main +--- expect ok + +--- loop $i 1 4 +--- mutate branch: b +query bump($n: I32) { update Person set { age: $n } where name = "alice" } +--- params +{"n": ${i}} +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":3} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 diff --git a/benchmarks/fixtures/tiny_graph.gqt b/benchmarks/fixtures/tiny_graph.gqt new file mode 100644 index 000000000..18ae92a5d --- /dev/null +++ b/benchmarks/fixtures/tiny_graph.gqt @@ -0,0 +1,15 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node Item { key: String @key val: I64 } + +--- seed +{"type":"Item","data":{"key":"a","val":1}} +{"type":"Item","data":{"key":"b","val":2}} diff --git a/benchmarks/fixtures/very_long_history_1000.gqt b/benchmarks/fixtures/very_long_history_1000.gqt new file mode 100644 index 000000000..c4d378e7c --- /dev/null +++ b/benchmarks/fixtures/very_long_history_1000.gqt @@ -0,0 +1,34 @@ +# issue: none +# notes: 1000 real paired updates, one live fixed-size row; 1002 reachable commits including genesis and seed. Extended checkpoints are opt-in. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node HistoryRow { key: String @key value: I64 payload: String } + +--- seed +{"type":"HistoryRow","data":{"key":"hot","value":0,"payload":"fixed"}} + +--- loop $cycle 0 500 +--- mutate +query set_one() { update HistoryRow set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- mutate +query restore_zero() { update HistoryRow set { value: 0 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":0,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/fixtures/very_long_history_10000.gqt b/benchmarks/fixtures/very_long_history_10000.gqt new file mode 100644 index 000000000..08debac4f --- /dev/null +++ b/benchmarks/fixtures/very_long_history_10000.gqt @@ -0,0 +1,34 @@ +# issue: none +# notes: 10000 real paired updates, one live fixed-size row; 10002 reachable commits including genesis and seed. Extended checkpoints are opt-in. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node HistoryRow { key: String @key value: I64 payload: String } + +--- seed +{"type":"HistoryRow","data":{"key":"hot","value":0,"payload":"fixed"}} + +--- loop $cycle 0 5000 +--- mutate +query set_one() { update HistoryRow set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- mutate +query restore_zero() { update HistoryRow set { value: 0 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":0,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/fixtures/very_long_history_100000.gqt b/benchmarks/fixtures/very_long_history_100000.gqt new file mode 100644 index 000000000..4a82cbf24 --- /dev/null +++ b/benchmarks/fixtures/very_long_history_100000.gqt @@ -0,0 +1,78 @@ +# issue: none +# notes: 100000 real paired updates, one live fixed-size row; 100002 reachable commits including genesis and seed. Extended checkpoints are opt-in. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node HistoryRow { key: String @key value: I64 payload: String } + +--- seed +{"type":"HistoryRow","data":{"key":"hot","value":0,"payload":"fixed"}} + +--- loop $cycle 0 10000 +--- mutate +query set_one() { update HistoryRow set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- mutate +query restore_zero() { update HistoryRow set { value: 0 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- loop $cycle 0 10000 +--- mutate +query set_one() { update HistoryRow set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- mutate +query restore_zero() { update HistoryRow set { value: 0 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- loop $cycle 0 10000 +--- mutate +query set_one() { update HistoryRow set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- mutate +query restore_zero() { update HistoryRow set { value: 0 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- loop $cycle 0 10000 +--- mutate +query set_one() { update HistoryRow set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- mutate +query restore_zero() { update HistoryRow set { value: 0 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- loop $cycle 0 10000 +--- mutate +query set_one() { update HistoryRow set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- mutate +query restore_zero() { update HistoryRow set { value: 0 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":0,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/fixtures/very_long_history_32.gqt b/benchmarks/fixtures/very_long_history_32.gqt new file mode 100644 index 000000000..81c4beeae --- /dev/null +++ b/benchmarks/fixtures/very_long_history_32.gqt @@ -0,0 +1,34 @@ +# issue: none +# notes: 32 real paired updates, one live fixed-size row; 34 reachable commits including genesis and seed. Extended checkpoints are opt-in. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- schema +node HistoryRow { key: String @key value: I64 payload: String } + +--- seed +{"type":"HistoryRow","data":{"key":"hot","value":0,"payload":"fixed"}} + +--- loop $cycle 0 16 +--- mutate +query set_one() { update HistoryRow set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- mutate +query restore_zero() { update HistoryRow set { value: 0 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- endloop + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":0,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/suites/aws-xfs-process-cold.suite-v1.yaml b/benchmarks/suites/aws-xfs-process-cold.suite-v1.yaml deleted file mode 100644 index 2f2925133..000000000 --- a/benchmarks/suites/aws-xfs-process-cold.suite-v1.yaml +++ /dev/null @@ -1,6 +0,0 @@ -version: 1 -name: aws-xfs-process-cold - -runs: - - case: ../cases/branch-merge-d50-process-cold-xfs.case-v1.yaml - repetitions: 5 diff --git a/benchmarks/suites/local-smoke.suite-v1.yaml b/benchmarks/suites/local-smoke.suite-v1.yaml deleted file mode 100644 index 2f142a502..000000000 --- a/benchmarks/suites/local-smoke.suite-v1.yaml +++ /dev/null @@ -1,6 +0,0 @@ -version: 1 -name: local-smoke - -runs: - - case: ../cases/branch-merge-d50-warm.case-v1.yaml - repetitions: 5 diff --git a/benchmarks/workloads/branch_merge_d50_cold.gqt b/benchmarks/workloads/branch_merge_d50_cold.gqt new file mode 100644 index 000000000..716409bd8 --- /dev/null +++ b/benchmarks/workloads/branch_merge_d50_cold.gqt @@ -0,0 +1,404 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch merge "bench-source" into "bench-target" +--- expect outcome: merged + +--- query branch: main +query node_0_main() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_0_main() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":0,"hi":4} +{"cohort":"d50_src_del","n":5,"payloads":5,"lo":5,"hi":9} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":10,"hi":14} +{"cohort":"d50_tgt_del","n":5,"payloads":5,"lo":15,"hi":19} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_1_main() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_1_main() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_2_main() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_2_main() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_3_main() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_3_main() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_0_bench_source() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_0_bench_source() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":10,"hi":14} +{"cohort":"d50_tgt_del","n":5,"payloads":5,"lo":15,"hi":19} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_1_bench_source() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_1_bench_source() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_2_bench_source() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_2_bench_source() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_3_bench_source() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_3_bench_source() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_0_bench_target() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_0_bench_target() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +{"cohort":"new","n":8,"payloads":8,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_1_bench_target() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_1_bench_target() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":8,"payloads":8,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_2_bench_target() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_2_bench_target() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":8,"payloads":8,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_3_bench_target() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_3_bench_target() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":8,"payloads":8,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? diff --git a/benchmarks/workloads/branch_merge_d50_warm.gqt b/benchmarks/workloads/branch_merge_d50_warm.gqt new file mode 100644 index 000000000..01c092ab8 --- /dev/null +++ b/benchmarks/workloads/branch_merge_d50_warm.gqt @@ -0,0 +1,800 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query branch: main +query node_0_main() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_0_main() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":0,"hi":4} +{"cohort":"d50_src_del","n":5,"payloads":5,"lo":5,"hi":9} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":10,"hi":14} +{"cohort":"d50_tgt_del","n":5,"payloads":5,"lo":15,"hi":19} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_1_main() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_1_main() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_2_main() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_2_main() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_3_main() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_3_main() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_0_bench_source() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_0_bench_source() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":10,"hi":14} +{"cohort":"d50_tgt_del","n":5,"payloads":5,"lo":15,"hi":19} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_1_bench_source() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_1_bench_source() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_2_bench_source() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_2_bench_source() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_3_bench_source() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_3_bench_source() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_0_bench_target() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_0_bench_target() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":0,"hi":4} +{"cohort":"d50_src_del","n":5,"payloads":5,"lo":5,"hi":9} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_1_bench_target() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_1_bench_target() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_2_bench_target() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_2_bench_target() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_3_bench_target() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_3_bench_target() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- mutate +branch merge "bench-source" into "bench-target" +--- expect outcome: merged + +--- query branch: main +query node_0_main() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_0_main() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":0,"hi":4} +{"cohort":"d50_src_del","n":5,"payloads":5,"lo":5,"hi":9} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":10,"hi":14} +{"cohort":"d50_tgt_del","n":5,"payloads":5,"lo":15,"hi":19} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_1_main() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_1_main() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_2_main() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_2_main() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query node_3_main() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: main +query edge_3_main() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":0,"hi":3} +{"cohort":"d50_src_del","n":4,"payloads":4,"lo":4,"hi":7} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_0_bench_source() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_0_bench_source() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":10,"hi":14} +{"cohort":"d50_tgt_del","n":5,"payloads":5,"lo":15,"hi":19} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_1_bench_source() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_1_bench_source() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_2_bench_source() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_2_bench_source() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query node_3_bench_source() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-source +query edge_3_bench_source() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":8,"hi":11} +{"cohort":"d50_tgt_del","n":4,"payloads":4,"lo":12,"hi":15} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":4,"payloads":4,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_0_bench_target() { + match { $n: BenchN000 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_0_bench_target() { + match { $a: BenchN000 + $a $e:benche000 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":5,"payloads":5,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99980,"payloads":99980,"lo":20,"hi":99999} +{"cohort":"new","n":8,"payloads":8,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_1_bench_target() { + match { $n: BenchN001 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_1_bench_target() { + match { $a: BenchN001 + $a $e:benche001 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":8,"payloads":8,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_2_bench_target() { + match { $n: BenchN002 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_2_bench_target() { + match { $a: BenchN002 + $a $e:benche002 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":8,"payloads":8,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query node_3_bench_target() { + match { $n: BenchN003 } + return { $n.cohort as cohort, count($n.name) as n, count($n.payload) as payloads, min($n.val) as lo, max($n.val) as hi } +} +--- expect unordered +{"cohort":"keep","n":100000,"payloads":100000,"lo":0,"hi":99999} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? + +--- query branch: bench-target +query edge_3_bench_target() { + match { $a: BenchN003 + $a $e:benche003 $b } + return { $e.cohort as cohort, count($e.val) as n, count($e.payload) as payloads, min($e.val) as lo, max($e.val) as hi } +} +--- expect unordered +{"cohort":"d50_src_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"d50_tgt_upd","n":4,"payloads":4,"lo":2147483647,"hi":2147483647} +{"cohort":"keep","n":99984,"payloads":99984,"lo":16,"hi":99999} +{"cohort":"new","n":8,"payloads":8,"lo":0,"hi":3} +--- expect shape +cohort: String? +n: I64 +payloads: I64 +lo: I32? +hi: I32? diff --git a/benchmarks/workloads/e2e_branch_adopt_untouched.gqt b/benchmarks/workloads/e2e_branch_adopt_untouched.gqt new file mode 100644 index 000000000..bedcd9599 --- /dev/null +++ b/benchmarks/workloads/e2e_branch_adopt_untouched.gqt @@ -0,0 +1,1796 @@ +# issue: none +# notes: Fast-forward a descendant source; a later untimed target write must remain isolated from source, main and siblings. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch merge "source" into "target" +--- expect outcome: fast_forward + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- mutate branch: target +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "target-only", embedding: $v } } +--- params +{"v":[2000.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +{"slug":"target-only","embedding":[2000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +{"slug":"target-only","embedding":[2000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/workloads/e2e_branch_adopt_written.gqt b/benchmarks/workloads/e2e_branch_adopt_written.gqt new file mode 100644 index 000000000..db771b5bd --- /dev/null +++ b/benchmarks/workloads/e2e_branch_adopt_written.gqt @@ -0,0 +1,1802 @@ +# issue: none +# notes: Fast-forward a descendant source; a later untimed target write must remain isolated from source, main and siblings. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch merge "source" into "target" +--- expect outcome: fast_forward + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"owner-only","embedding":[900.0,0.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"owner-only","embedding":[900.0,0.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- mutate branch: target +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "target-only", embedding: $v } } +--- params +{"v":[2000.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"owner-only","embedding":[900.0,0.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"owner-only","embedding":[900.0,0.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +{"slug":"target-only","embedding":[2000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"owner-only","embedding":[900.0,0.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"owner-only","embedding":[900.0,0.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +{"slug":"target-only","embedding":[2000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/workloads/e2e_branch_create.gqt b/benchmarks/workloads/e2e_branch_create.gqt new file mode 100644 index 000000000..62c4b584d --- /dev/null +++ b/benchmarks/workloads/e2e_branch_create.gqt @@ -0,0 +1,1195 @@ +# issue: none +# notes: Create child from main; complete rows of all tables and all existing branches remain exact. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch create "child" from "main" +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"child"} +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: child +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"child"} +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: child +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/workloads/e2e_branch_create_from.gqt b/benchmarks/workloads/e2e_branch_create_from.gqt new file mode 100644 index 000000000..4edacc3fa --- /dev/null +++ b/benchmarks/workloads/e2e_branch_create_from.gqt @@ -0,0 +1,1197 @@ +# issue: none +# notes: Create child from source; complete rows of all tables and all existing branches remain exact. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch create "child" from "source" +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"child"} +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: child +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"child"} +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: child +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: child +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/workloads/e2e_branch_delete.gqt b/benchmarks/workloads/e2e_branch_delete.gqt new file mode 100644 index 000000000..4f853f7ef --- /dev/null +++ b/benchmarks/workloads/e2e_branch_delete.gqt @@ -0,0 +1,1001 @@ +# issue: none +# notes: Delete the branch that wrote every table; surviving registry and complete rows remain unchanged. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch delete "victim" +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/workloads/e2e_branch_first_write.gqt b/benchmarks/workloads/e2e_branch_first_write.gqt new file mode 100644 index 000000000..78b1bd936 --- /dev/null +++ b/benchmarks/workloads/e2e_branch_first_write.gqt @@ -0,0 +1,1201 @@ +# issue: none +# notes: First target write appends one vector; inherited rows, other tables and all source/sibling views remain exact. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate branch: target +query insert_chunk($v: Vector(4)) { insert Chunk { slug: "target-only", embedding: $v } } +--- params +{"v":[2000.0,0.0,0.0,0.0]} +--- expect affected: nodes=1 edges=0 + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +{"slug":"target-only","embedding":[2000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +{"name":"target"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +{"slug":"target-only","embedding":[2000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: target +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: target +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/workloads/e2e_branch_list.gqt b/benchmarks/workloads/e2e_branch_list.gqt new file mode 100644 index 000000000..7ea3d1e30 --- /dev/null +++ b/benchmarks/workloads/e2e_branch_list.gqt @@ -0,0 +1,1009 @@ +# issue: none +# notes: List five branches, then check every branch table before and after reopening. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"sibling1"} +{"name":"sibling2"} +{"name":"sibling3"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: main +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: main +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"source-only","embedding":[1000.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: source +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling1 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling2 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra1 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra2 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + +--- query branch: sibling3 +query extra_rows() { match { $e: Extra3 } return { $e.slug as slug } } + +--- expect unordered +{"slug":"base"} +--- expect shape +slug: String + diff --git a/benchmarks/workloads/e2e_merge_all_changed.gqt b/benchmarks/workloads/e2e_merge_all_changed.gqt new file mode 100644 index 000000000..9b60c721e --- /dev/null +++ b/benchmarks/workloads/e2e_merge_all_changed.gqt @@ -0,0 +1,323 @@ +# issue: none +# notes: Merge all 64 changed vectors into a diverged target; exact rows on both branches, including the unrelated target insert. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch merge "source" into "main" +--- expect outcome: merged + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base017","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base018","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base019","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base020","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base021","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base022","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base023","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base024","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base025","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base026","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base027","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base028","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base029","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base030","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base031","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base032","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base033","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base034","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base035","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base036","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base037","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base038","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base039","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base040","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base041","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base042","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base043","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base044","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base045","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base046","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base047","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base048","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base049","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base050","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base051","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base052","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base053","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base054","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base055","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base056","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"main-only","embedding":[500.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base017","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base018","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base019","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base020","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base021","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base022","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base023","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base024","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base025","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base026","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base027","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base028","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base029","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base030","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base031","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base032","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base033","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base034","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base035","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base036","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base037","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base038","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base039","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base040","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base041","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base042","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base043","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base044","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base045","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base046","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base047","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base048","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base049","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base050","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base051","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base052","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base053","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base054","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base055","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base056","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[-1.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base017","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base018","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base019","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base020","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base021","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base022","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base023","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base024","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base025","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base026","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base027","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base028","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base029","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base030","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base031","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base032","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base033","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base034","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base035","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base036","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base037","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base038","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base039","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base040","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base041","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base042","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base043","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base044","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base045","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base046","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base047","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base048","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base049","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base050","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base051","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base052","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base053","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base054","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base055","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base056","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"main-only","embedding":[500.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base017","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base018","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base019","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base020","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base021","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base022","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base023","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base024","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base025","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base026","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base027","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base028","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base029","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base030","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base031","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base032","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base033","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base034","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base035","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base036","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base037","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base038","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base039","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base040","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base041","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base042","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base043","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base044","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base045","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base046","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base047","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base048","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base049","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base050","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base051","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base052","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base053","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base054","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base055","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base056","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[-1.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[-1.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + diff --git a/benchmarks/workloads/e2e_merge_all_new.gqt b/benchmarks/workloads/e2e_merge_all_new.gqt new file mode 100644 index 000000000..efcfc05bc --- /dev/null +++ b/benchmarks/workloads/e2e_merge_all_new.gqt @@ -0,0 +1,385 @@ +# issue: none +# notes: Fast-forward 16 new keys; exact 80-row union and unchanged source. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch merge "source" into "main" +--- expect outcome: fast_forward + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"new000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new015","embedding":[100.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"new000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new015","embedding":[100.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"new000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new015","embedding":[100.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +{"slug":"new000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"new015","embedding":[100.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + diff --git a/benchmarks/workloads/e2e_merge_diverged_updates.gqt b/benchmarks/workloads/e2e_merge_diverged_updates.gqt new file mode 100644 index 000000000..92d738613 --- /dev/null +++ b/benchmarks/workloads/e2e_merge_diverged_updates.gqt @@ -0,0 +1,321 @@ +# issue: none +# notes: Merge 16 source updates with eight disjoint target updates; all 64 vectors and source isolation are explicit. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch merge "source" into "main" +--- expect outcome: merged + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[200.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"main"} +{"name":"source"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[200.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[200.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- query branch: source +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base001","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base002","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base003","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base004","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base005","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base006","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base007","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base008","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base009","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base010","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base011","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base012","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base013","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base014","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base015","embedding":[100.0,0.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[48.0,1.0,0.0,0.0]} +{"slug":"base049","embedding":[49.0,1.0,0.0,0.0]} +{"slug":"base050","embedding":[50.0,1.0,0.0,0.0]} +{"slug":"base051","embedding":[51.0,1.0,0.0,0.0]} +{"slug":"base052","embedding":[52.0,1.0,0.0,0.0]} +{"slug":"base053","embedding":[53.0,1.0,0.0,0.0]} +{"slug":"base054","embedding":[54.0,1.0,0.0,0.0]} +{"slug":"base055","embedding":[55.0,1.0,0.0,0.0]} +{"slug":"base056","embedding":[56.0,1.0,0.0,0.0]} +{"slug":"base057","embedding":[57.0,1.0,0.0,0.0]} +{"slug":"base058","embedding":[58.0,1.0,0.0,0.0]} +{"slug":"base059","embedding":[59.0,1.0,0.0,0.0]} +{"slug":"base060","embedding":[60.0,1.0,0.0,0.0]} +{"slug":"base061","embedding":[61.0,1.0,0.0,0.0]} +{"slug":"base062","embedding":[62.0,1.0,0.0,0.0]} +{"slug":"base063","embedding":[63.0,1.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + diff --git a/benchmarks/workloads/e2e_mixed_load.gqt b/benchmarks/workloads/e2e_mixed_load.gqt new file mode 100644 index 000000000..6a981dad4 --- /dev/null +++ b/benchmarks/workloads/e2e_mixed_load.gqt @@ -0,0 +1,216 @@ +# issue: none +# notes: One public loader call updates 16 existing keys and inserts 16 new keys; exact 80-row result. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- load generate: v1 seed: 0 mode: merge branch: main +tables: + - kind: node + name: Chunk + rows: 32 + commits: 1 + batch_rows: 32 + start: 48 + columns: + slug: {kind: key, prefix: base, width: 3} + embedding: {kind: literal, value: [300.0,0.0,0.0,0.0]} +--- expect ok + +--- query +branch list + +--- expect unordered +{"name":"main"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base049","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base050","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base051","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base052","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base053","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base054","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base055","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base056","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base064","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base065","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base066","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base067","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base068","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base069","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base070","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base071","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base072","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base073","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base074","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base075","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base076","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base077","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base078","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base079","embedding":[300.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + +--- restart + +--- query +branch list + +--- expect unordered +{"name":"main"} +--- expect shape +name: String + +--- query branch: main +query chunk_rows() { match { $c: Chunk } return { $c.slug as slug, $c.embedding as embedding } } + +--- expect unordered +{"slug":"base000","embedding":[0.0,1.0,0.0,0.0]} +{"slug":"base001","embedding":[1.0,1.0,0.0,0.0]} +{"slug":"base002","embedding":[2.0,1.0,0.0,0.0]} +{"slug":"base003","embedding":[3.0,1.0,0.0,0.0]} +{"slug":"base004","embedding":[4.0,1.0,0.0,0.0]} +{"slug":"base005","embedding":[5.0,1.0,0.0,0.0]} +{"slug":"base006","embedding":[6.0,1.0,0.0,0.0]} +{"slug":"base007","embedding":[7.0,1.0,0.0,0.0]} +{"slug":"base008","embedding":[8.0,1.0,0.0,0.0]} +{"slug":"base009","embedding":[9.0,1.0,0.0,0.0]} +{"slug":"base010","embedding":[10.0,1.0,0.0,0.0]} +{"slug":"base011","embedding":[11.0,1.0,0.0,0.0]} +{"slug":"base012","embedding":[12.0,1.0,0.0,0.0]} +{"slug":"base013","embedding":[13.0,1.0,0.0,0.0]} +{"slug":"base014","embedding":[14.0,1.0,0.0,0.0]} +{"slug":"base015","embedding":[15.0,1.0,0.0,0.0]} +{"slug":"base016","embedding":[16.0,1.0,0.0,0.0]} +{"slug":"base017","embedding":[17.0,1.0,0.0,0.0]} +{"slug":"base018","embedding":[18.0,1.0,0.0,0.0]} +{"slug":"base019","embedding":[19.0,1.0,0.0,0.0]} +{"slug":"base020","embedding":[20.0,1.0,0.0,0.0]} +{"slug":"base021","embedding":[21.0,1.0,0.0,0.0]} +{"slug":"base022","embedding":[22.0,1.0,0.0,0.0]} +{"slug":"base023","embedding":[23.0,1.0,0.0,0.0]} +{"slug":"base024","embedding":[24.0,1.0,0.0,0.0]} +{"slug":"base025","embedding":[25.0,1.0,0.0,0.0]} +{"slug":"base026","embedding":[26.0,1.0,0.0,0.0]} +{"slug":"base027","embedding":[27.0,1.0,0.0,0.0]} +{"slug":"base028","embedding":[28.0,1.0,0.0,0.0]} +{"slug":"base029","embedding":[29.0,1.0,0.0,0.0]} +{"slug":"base030","embedding":[30.0,1.0,0.0,0.0]} +{"slug":"base031","embedding":[31.0,1.0,0.0,0.0]} +{"slug":"base032","embedding":[32.0,1.0,0.0,0.0]} +{"slug":"base033","embedding":[33.0,1.0,0.0,0.0]} +{"slug":"base034","embedding":[34.0,1.0,0.0,0.0]} +{"slug":"base035","embedding":[35.0,1.0,0.0,0.0]} +{"slug":"base036","embedding":[36.0,1.0,0.0,0.0]} +{"slug":"base037","embedding":[37.0,1.0,0.0,0.0]} +{"slug":"base038","embedding":[38.0,1.0,0.0,0.0]} +{"slug":"base039","embedding":[39.0,1.0,0.0,0.0]} +{"slug":"base040","embedding":[40.0,1.0,0.0,0.0]} +{"slug":"base041","embedding":[41.0,1.0,0.0,0.0]} +{"slug":"base042","embedding":[42.0,1.0,0.0,0.0]} +{"slug":"base043","embedding":[43.0,1.0,0.0,0.0]} +{"slug":"base044","embedding":[44.0,1.0,0.0,0.0]} +{"slug":"base045","embedding":[45.0,1.0,0.0,0.0]} +{"slug":"base046","embedding":[46.0,1.0,0.0,0.0]} +{"slug":"base047","embedding":[47.0,1.0,0.0,0.0]} +{"slug":"base048","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base049","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base050","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base051","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base052","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base053","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base054","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base055","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base056","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base057","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base058","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base059","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base060","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base061","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base062","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base063","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base064","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base065","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base066","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base067","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base068","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base069","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base070","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base071","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base072","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base073","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base074","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base075","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base076","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base077","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base078","embedding":[300.0,0.0,0.0,0.0]} +{"slug":"base079","embedding":[300.0,0.0,0.0,0.0]} +--- expect shape +slug: String +embedding: Vector(4) + diff --git a/benchmarks/workloads/e2e_nearest_nprobes_one.gqt b/benchmarks/workloads/e2e_nearest_nprobes_one.gqt new file mode 100644 index 000000000..123dd1045 --- /dev/null +++ b/benchmarks/workloads/e2e_nearest_nprobes_one.gqt @@ -0,0 +1,47 @@ +# issue: none +# notes: Full nearest query with public ann_nprobes=1; one-partition setting coverage, not a historical ANN recall/timing comparison. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +set ann_nprobes = 1; +query nearest_matching_rows($q: Vector(4)) { + match { $d: Doc $d.n > 3 } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 +} +--- params +{"q":[2.3,0.0,0.0,0.0]} + +--- expect ordered +{"d.slug":"d004"} +{"d.slug":"d005"} +{"d.slug":"d006"} +--- expect shape +d.slug: String + +--- restart + +--- query +set ann_nprobes = 1; +query nearest_matching_rows($q: Vector(4)) { + match { $d: Doc $d.n > 3 } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 +} +--- params +{"q":[2.3,0.0,0.0,0.0]} + +--- expect ordered +{"d.slug":"d004"} +{"d.slug":"d005"} +{"d.slug":"d006"} +--- expect shape +d.slug: String + diff --git a/benchmarks/workloads/e2e_nearest_prefilter.gqt b/benchmarks/workloads/e2e_nearest_prefilter.gqt new file mode 100644 index 000000000..0613be684 --- /dev/null +++ b/benchmarks/workloads/e2e_nearest_prefilter.gqt @@ -0,0 +1,45 @@ +# issue: none +# notes: Full filtered nearest query over 64 docs; exact distance order survives reopening. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query filtered_nearest($q: Vector(4)) { + match { $d: Doc { status: "hit" } } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 +} +--- params +{"q":[1.0,0.0,0.0,0.0]} + +--- expect ordered +{"d.slug":"hit001"} +{"d.slug":"hit002"} +{"d.slug":"hit003"} +--- expect shape +d.slug: String + +--- restart + +--- query +query filtered_nearest($q: Vector(4)) { + match { $d: Doc { status: "hit" } } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 +} +--- params +{"q":[1.0,0.0,0.0,0.0]} + +--- expect ordered +{"d.slug":"hit001"} +{"d.slug":"hit002"} +{"d.slug":"hit003"} +--- expect shape +d.slug: String + diff --git a/benchmarks/workloads/e2e_query_count.gqt b/benchmarks/workloads/e2e_query_count.gqt new file mode 100644 index 000000000..79c998859 --- /dev/null +++ b/benchmarks/workloads/e2e_query_count.gqt @@ -0,0 +1,31 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query count_all() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":100} +--- expect shape +n: I64 + +--- query +query count_all() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":100} +--- expect shape +n: I64 + +--- restart + +--- query +query count_all() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":100} +--- expect shape +n: I64 diff --git a/benchmarks/workloads/e2e_query_count_bare.gqt b/benchmarks/workloads/e2e_query_count_bare.gqt new file mode 100644 index 000000000..0ef78e051 --- /dev/null +++ b/benchmarks/workloads/e2e_query_count_bare.gqt @@ -0,0 +1,31 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query count_bare() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":20} +--- expect shape +n: I64 + +--- query +query count_bare() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":20} +--- expect shape +n: I64 + +--- restart + +--- query +query count_bare() { match { $p: Person } return { count($p) as n } } +--- expect unordered +{"n":20} +--- expect shape +n: I64 diff --git a/benchmarks/workloads/e2e_query_destination_projection.gqt b/benchmarks/workloads/e2e_query_destination_projection.gqt new file mode 100644 index 000000000..8e6923c5f --- /dev/null +++ b/benchmarks/workloads/e2e_query_destination_projection.gqt @@ -0,0 +1,88 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query destination_projection() { match { $p: Person $p knows $q } return { $q.name } } +--- expect unordered +{"q.name":"p000000"} +{"q.name":"p000001"} +{"q.name":"p000002"} +{"q.name":"p000003"} +{"q.name":"p000004"} +{"q.name":"p000005"} +{"q.name":"p000006"} +{"q.name":"p000007"} +{"q.name":"p000008"} +{"q.name":"p000009"} +{"q.name":"p000010"} +{"q.name":"p000011"} +{"q.name":"p000012"} +{"q.name":"p000013"} +{"q.name":"p000014"} +{"q.name":"p000015"} +{"q.name":"p000016"} +{"q.name":"p000017"} +{"q.name":"p000018"} +{"q.name":"p000019"} +--- expect shape +q.name: String + +--- query +query destination_projection() { match { $p: Person $p knows $q } return { $q.name } } +--- expect unordered +{"q.name":"p000000"} +{"q.name":"p000001"} +{"q.name":"p000002"} +{"q.name":"p000003"} +{"q.name":"p000004"} +{"q.name":"p000005"} +{"q.name":"p000006"} +{"q.name":"p000007"} +{"q.name":"p000008"} +{"q.name":"p000009"} +{"q.name":"p000010"} +{"q.name":"p000011"} +{"q.name":"p000012"} +{"q.name":"p000013"} +{"q.name":"p000014"} +{"q.name":"p000015"} +{"q.name":"p000016"} +{"q.name":"p000017"} +{"q.name":"p000018"} +{"q.name":"p000019"} +--- expect shape +q.name: String + +--- restart + +--- query +query destination_projection() { match { $p: Person $p knows $q } return { $q.name } } +--- expect unordered +{"q.name":"p000000"} +{"q.name":"p000001"} +{"q.name":"p000002"} +{"q.name":"p000003"} +{"q.name":"p000004"} +{"q.name":"p000005"} +{"q.name":"p000006"} +{"q.name":"p000007"} +{"q.name":"p000008"} +{"q.name":"p000009"} +{"q.name":"p000010"} +{"q.name":"p000011"} +{"q.name":"p000012"} +{"q.name":"p000013"} +{"q.name":"p000014"} +{"q.name":"p000015"} +{"q.name":"p000016"} +{"q.name":"p000017"} +{"q.name":"p000018"} +{"q.name":"p000019"} +--- expect shape +q.name: String diff --git a/benchmarks/workloads/e2e_query_destination_search.gqt b/benchmarks/workloads/e2e_query_destination_search.gqt new file mode 100644 index 000000000..1eb61764f --- /dev/null +++ b/benchmarks/workloads/e2e_query_destination_search.gqt @@ -0,0 +1,43 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query destination_search() { + match { $p: Person $p knows $q search($q.body, "needle") } + return { $q.name } +} +--- expect unordered +{"q.name":"p000000"} +{"q.name":"p000010"} +--- expect shape +q.name: String + +--- query +query destination_search() { + match { $p: Person $p knows $q search($q.body, "needle") } + return { $q.name } +} +--- expect unordered +{"q.name":"p000000"} +{"q.name":"p000010"} +--- expect shape +q.name: String + +--- restart + +--- query +query destination_search() { + match { $p: Person $p knows $q search($q.body, "needle") } + return { $q.name } +} +--- expect unordered +{"q.name":"p000000"} +{"q.name":"p000010"} +--- expect shape +q.name: String diff --git a/benchmarks/workloads/e2e_query_filter.gqt b/benchmarks/workloads/e2e_query_filter.gqt new file mode 100644 index 000000000..d0397d4e0 --- /dev/null +++ b/benchmarks/workloads/e2e_query_filter.gqt @@ -0,0 +1,61 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query filter() { match { $p: Person $p.age >= 90 } return { $p.name, $p.age } } +--- expect unordered +{"p.name":"p000590","p.age":90} +{"p.name":"p000591","p.age":91} +{"p.name":"p000592","p.age":92} +{"p.name":"p000593","p.age":93} +{"p.name":"p000594","p.age":94} +{"p.name":"p000595","p.age":95} +{"p.name":"p000596","p.age":96} +{"p.name":"p000597","p.age":97} +{"p.name":"p000598","p.age":98} +{"p.name":"p000599","p.age":99} +--- expect shape +p.name: String +p.age: I64 + +--- query +query filter() { match { $p: Person $p.age >= 90 } return { $p.name, $p.age } } +--- expect unordered +{"p.name":"p000590","p.age":90} +{"p.name":"p000591","p.age":91} +{"p.name":"p000592","p.age":92} +{"p.name":"p000593","p.age":93} +{"p.name":"p000594","p.age":94} +{"p.name":"p000595","p.age":95} +{"p.name":"p000596","p.age":96} +{"p.name":"p000597","p.age":97} +{"p.name":"p000598","p.age":98} +{"p.name":"p000599","p.age":99} +--- expect shape +p.name: String +p.age: I64 + +--- restart + +--- query +query filter() { match { $p: Person $p.age >= 90 } return { $p.name, $p.age } } +--- expect unordered +{"p.name":"p000590","p.age":90} +{"p.name":"p000591","p.age":91} +{"p.name":"p000592","p.age":92} +{"p.name":"p000593","p.age":93} +{"p.name":"p000594","p.age":94} +{"p.name":"p000595","p.age":95} +{"p.name":"p000596","p.age":96} +{"p.name":"p000597","p.age":97} +{"p.name":"p000598","p.age":98} +{"p.name":"p000599","p.age":99} +--- expect shape +p.name: String +p.age: I64 diff --git a/benchmarks/workloads/e2e_query_filtered_friends.gqt b/benchmarks/workloads/e2e_query_filtered_friends.gqt new file mode 100644 index 000000000..8f23893b5 --- /dev/null +++ b/benchmarks/workloads/e2e_query_filtered_friends.gqt @@ -0,0 +1,55 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query filtered_friends() { + match { $p: Person $p.age >= 90 $p knows $q } + return { $p.name, $q.name } +} +--- expect unordered +{"p.name":"p000590","q.name":"p000591"} +{"p.name":"p000592","q.name":"p000593"} +{"p.name":"p000594","q.name":"p000595"} +{"p.name":"p000596","q.name":"p000597"} +{"p.name":"p000598","q.name":"p000599"} +--- expect shape +p.name: String +q.name: String + +--- query +query filtered_friends() { + match { $p: Person $p.age >= 90 $p knows $q } + return { $p.name, $q.name } +} +--- expect unordered +{"p.name":"p000590","q.name":"p000591"} +{"p.name":"p000592","q.name":"p000593"} +{"p.name":"p000594","q.name":"p000595"} +{"p.name":"p000596","q.name":"p000597"} +{"p.name":"p000598","q.name":"p000599"} +--- expect shape +p.name: String +q.name: String + +--- restart + +--- query +query filtered_friends() { + match { $p: Person $p.age >= 90 $p knows $q } + return { $p.name, $q.name } +} +--- expect unordered +{"p.name":"p000590","q.name":"p000591"} +{"p.name":"p000592","q.name":"p000593"} +{"p.name":"p000594","q.name":"p000595"} +{"p.name":"p000596","q.name":"p000597"} +{"p.name":"p000598","q.name":"p000599"} +--- expect shape +p.name: String +q.name: String diff --git a/benchmarks/workloads/e2e_query_friends.gqt b/benchmarks/workloads/e2e_query_friends.gqt new file mode 100644 index 000000000..e4bf3a7d0 --- /dev/null +++ b/benchmarks/workloads/e2e_query_friends.gqt @@ -0,0 +1,181 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query friends() { match { $p: Person $p knows $q } return { $p.name, $q.name } } +--- expect unordered +{"p.name":"p000500","q.name":"p000501"} +{"p.name":"p000502","q.name":"p000503"} +{"p.name":"p000504","q.name":"p000505"} +{"p.name":"p000506","q.name":"p000507"} +{"p.name":"p000508","q.name":"p000509"} +{"p.name":"p000510","q.name":"p000511"} +{"p.name":"p000512","q.name":"p000513"} +{"p.name":"p000514","q.name":"p000515"} +{"p.name":"p000516","q.name":"p000517"} +{"p.name":"p000518","q.name":"p000519"} +{"p.name":"p000520","q.name":"p000521"} +{"p.name":"p000522","q.name":"p000523"} +{"p.name":"p000524","q.name":"p000525"} +{"p.name":"p000526","q.name":"p000527"} +{"p.name":"p000528","q.name":"p000529"} +{"p.name":"p000530","q.name":"p000531"} +{"p.name":"p000532","q.name":"p000533"} +{"p.name":"p000534","q.name":"p000535"} +{"p.name":"p000536","q.name":"p000537"} +{"p.name":"p000538","q.name":"p000539"} +{"p.name":"p000540","q.name":"p000541"} +{"p.name":"p000542","q.name":"p000543"} +{"p.name":"p000544","q.name":"p000545"} +{"p.name":"p000546","q.name":"p000547"} +{"p.name":"p000548","q.name":"p000549"} +{"p.name":"p000550","q.name":"p000551"} +{"p.name":"p000552","q.name":"p000553"} +{"p.name":"p000554","q.name":"p000555"} +{"p.name":"p000556","q.name":"p000557"} +{"p.name":"p000558","q.name":"p000559"} +{"p.name":"p000560","q.name":"p000561"} +{"p.name":"p000562","q.name":"p000563"} +{"p.name":"p000564","q.name":"p000565"} +{"p.name":"p000566","q.name":"p000567"} +{"p.name":"p000568","q.name":"p000569"} +{"p.name":"p000570","q.name":"p000571"} +{"p.name":"p000572","q.name":"p000573"} +{"p.name":"p000574","q.name":"p000575"} +{"p.name":"p000576","q.name":"p000577"} +{"p.name":"p000578","q.name":"p000579"} +{"p.name":"p000580","q.name":"p000581"} +{"p.name":"p000582","q.name":"p000583"} +{"p.name":"p000584","q.name":"p000585"} +{"p.name":"p000586","q.name":"p000587"} +{"p.name":"p000588","q.name":"p000589"} +{"p.name":"p000590","q.name":"p000591"} +{"p.name":"p000592","q.name":"p000593"} +{"p.name":"p000594","q.name":"p000595"} +{"p.name":"p000596","q.name":"p000597"} +{"p.name":"p000598","q.name":"p000599"} +--- expect shape +p.name: String +q.name: String + +--- query +query friends() { match { $p: Person $p knows $q } return { $p.name, $q.name } } +--- expect unordered +{"p.name":"p000500","q.name":"p000501"} +{"p.name":"p000502","q.name":"p000503"} +{"p.name":"p000504","q.name":"p000505"} +{"p.name":"p000506","q.name":"p000507"} +{"p.name":"p000508","q.name":"p000509"} +{"p.name":"p000510","q.name":"p000511"} +{"p.name":"p000512","q.name":"p000513"} +{"p.name":"p000514","q.name":"p000515"} +{"p.name":"p000516","q.name":"p000517"} +{"p.name":"p000518","q.name":"p000519"} +{"p.name":"p000520","q.name":"p000521"} +{"p.name":"p000522","q.name":"p000523"} +{"p.name":"p000524","q.name":"p000525"} +{"p.name":"p000526","q.name":"p000527"} +{"p.name":"p000528","q.name":"p000529"} +{"p.name":"p000530","q.name":"p000531"} +{"p.name":"p000532","q.name":"p000533"} +{"p.name":"p000534","q.name":"p000535"} +{"p.name":"p000536","q.name":"p000537"} +{"p.name":"p000538","q.name":"p000539"} +{"p.name":"p000540","q.name":"p000541"} +{"p.name":"p000542","q.name":"p000543"} +{"p.name":"p000544","q.name":"p000545"} +{"p.name":"p000546","q.name":"p000547"} +{"p.name":"p000548","q.name":"p000549"} +{"p.name":"p000550","q.name":"p000551"} +{"p.name":"p000552","q.name":"p000553"} +{"p.name":"p000554","q.name":"p000555"} +{"p.name":"p000556","q.name":"p000557"} +{"p.name":"p000558","q.name":"p000559"} +{"p.name":"p000560","q.name":"p000561"} +{"p.name":"p000562","q.name":"p000563"} +{"p.name":"p000564","q.name":"p000565"} +{"p.name":"p000566","q.name":"p000567"} +{"p.name":"p000568","q.name":"p000569"} +{"p.name":"p000570","q.name":"p000571"} +{"p.name":"p000572","q.name":"p000573"} +{"p.name":"p000574","q.name":"p000575"} +{"p.name":"p000576","q.name":"p000577"} +{"p.name":"p000578","q.name":"p000579"} +{"p.name":"p000580","q.name":"p000581"} +{"p.name":"p000582","q.name":"p000583"} +{"p.name":"p000584","q.name":"p000585"} +{"p.name":"p000586","q.name":"p000587"} +{"p.name":"p000588","q.name":"p000589"} +{"p.name":"p000590","q.name":"p000591"} +{"p.name":"p000592","q.name":"p000593"} +{"p.name":"p000594","q.name":"p000595"} +{"p.name":"p000596","q.name":"p000597"} +{"p.name":"p000598","q.name":"p000599"} +--- expect shape +p.name: String +q.name: String + +--- restart + +--- query +query friends() { match { $p: Person $p knows $q } return { $p.name, $q.name } } +--- expect unordered +{"p.name":"p000500","q.name":"p000501"} +{"p.name":"p000502","q.name":"p000503"} +{"p.name":"p000504","q.name":"p000505"} +{"p.name":"p000506","q.name":"p000507"} +{"p.name":"p000508","q.name":"p000509"} +{"p.name":"p000510","q.name":"p000511"} +{"p.name":"p000512","q.name":"p000513"} +{"p.name":"p000514","q.name":"p000515"} +{"p.name":"p000516","q.name":"p000517"} +{"p.name":"p000518","q.name":"p000519"} +{"p.name":"p000520","q.name":"p000521"} +{"p.name":"p000522","q.name":"p000523"} +{"p.name":"p000524","q.name":"p000525"} +{"p.name":"p000526","q.name":"p000527"} +{"p.name":"p000528","q.name":"p000529"} +{"p.name":"p000530","q.name":"p000531"} +{"p.name":"p000532","q.name":"p000533"} +{"p.name":"p000534","q.name":"p000535"} +{"p.name":"p000536","q.name":"p000537"} +{"p.name":"p000538","q.name":"p000539"} +{"p.name":"p000540","q.name":"p000541"} +{"p.name":"p000542","q.name":"p000543"} +{"p.name":"p000544","q.name":"p000545"} +{"p.name":"p000546","q.name":"p000547"} +{"p.name":"p000548","q.name":"p000549"} +{"p.name":"p000550","q.name":"p000551"} +{"p.name":"p000552","q.name":"p000553"} +{"p.name":"p000554","q.name":"p000555"} +{"p.name":"p000556","q.name":"p000557"} +{"p.name":"p000558","q.name":"p000559"} +{"p.name":"p000560","q.name":"p000561"} +{"p.name":"p000562","q.name":"p000563"} +{"p.name":"p000564","q.name":"p000565"} +{"p.name":"p000566","q.name":"p000567"} +{"p.name":"p000568","q.name":"p000569"} +{"p.name":"p000570","q.name":"p000571"} +{"p.name":"p000572","q.name":"p000573"} +{"p.name":"p000574","q.name":"p000575"} +{"p.name":"p000576","q.name":"p000577"} +{"p.name":"p000578","q.name":"p000579"} +{"p.name":"p000580","q.name":"p000581"} +{"p.name":"p000582","q.name":"p000583"} +{"p.name":"p000584","q.name":"p000585"} +{"p.name":"p000586","q.name":"p000587"} +{"p.name":"p000588","q.name":"p000589"} +{"p.name":"p000590","q.name":"p000591"} +{"p.name":"p000592","q.name":"p000593"} +{"p.name":"p000594","q.name":"p000595"} +{"p.name":"p000596","q.name":"p000597"} +{"p.name":"p000598","q.name":"p000599"} +--- expect shape +p.name: String +q.name: String diff --git a/benchmarks/workloads/e2e_query_grouped.gqt b/benchmarks/workloads/e2e_query_grouped.gqt new file mode 100644 index 000000000..9b70e207a --- /dev/null +++ b/benchmarks/workloads/e2e_query_grouped.gqt @@ -0,0 +1,76 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query grouped() { + match { $p: Person } + return { $p.team, sum($p.age) as total, avg($p.age) as mean, count($p) as n } +} +--- expect unordered +{"p.team":"g0","total":450,"mean":45.0,"n":10} +{"p.team":"g1","total":460,"mean":46.0,"n":10} +{"p.team":"g2","total":470,"mean":47.0,"n":10} +{"p.team":"g3","total":480,"mean":48.0,"n":10} +{"p.team":"g4","total":490,"mean":49.0,"n":10} +{"p.team":"g5","total":500,"mean":50.0,"n":10} +{"p.team":"g6","total":510,"mean":51.0,"n":10} +{"p.team":"g7","total":520,"mean":52.0,"n":10} +{"p.team":"g8","total":530,"mean":53.0,"n":10} +{"p.team":"g9","total":540,"mean":54.0,"n":10} +--- expect shape +p.team: String +total: F64 +mean: F64 +n: I64 + +--- query +query grouped() { + match { $p: Person } + return { $p.team, sum($p.age) as total, avg($p.age) as mean, count($p) as n } +} +--- expect unordered +{"p.team":"g0","total":450,"mean":45.0,"n":10} +{"p.team":"g1","total":460,"mean":46.0,"n":10} +{"p.team":"g2","total":470,"mean":47.0,"n":10} +{"p.team":"g3","total":480,"mean":48.0,"n":10} +{"p.team":"g4","total":490,"mean":49.0,"n":10} +{"p.team":"g5","total":500,"mean":50.0,"n":10} +{"p.team":"g6","total":510,"mean":51.0,"n":10} +{"p.team":"g7","total":520,"mean":52.0,"n":10} +{"p.team":"g8","total":530,"mean":53.0,"n":10} +{"p.team":"g9","total":540,"mean":54.0,"n":10} +--- expect shape +p.team: String +total: F64 +mean: F64 +n: I64 + +--- restart + +--- query +query grouped() { + match { $p: Person } + return { $p.team, sum($p.age) as total, avg($p.age) as mean, count($p) as n } +} +--- expect unordered +{"p.team":"g0","total":450,"mean":45.0,"n":10} +{"p.team":"g1","total":460,"mean":46.0,"n":10} +{"p.team":"g2","total":470,"mean":47.0,"n":10} +{"p.team":"g3","total":480,"mean":48.0,"n":10} +{"p.team":"g4","total":490,"mean":49.0,"n":10} +{"p.team":"g5","total":500,"mean":50.0,"n":10} +{"p.team":"g6","total":510,"mean":51.0,"n":10} +{"p.team":"g7","total":520,"mean":52.0,"n":10} +{"p.team":"g8","total":530,"mean":53.0,"n":10} +{"p.team":"g9","total":540,"mean":54.0,"n":10} +--- expect shape +p.team: String +total: F64 +mean: F64 +n: I64 diff --git a/benchmarks/workloads/e2e_query_grouped_fanout.gqt b/benchmarks/workloads/e2e_query_grouped_fanout.gqt new file mode 100644 index 000000000..41f4e610c --- /dev/null +++ b/benchmarks/workloads/e2e_query_grouped_fanout.gqt @@ -0,0 +1,46 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query grouped_fanout() { + match { $p: Person $p knows $q } + return { $p.team, count($q) as n } +} +--- expect unordered +{"p.team":"g0","n":10} +{"p.team":"g1","n":10} +--- expect shape +p.team: String +n: I64 + +--- query +query grouped_fanout() { + match { $p: Person $p knows $q } + return { $p.team, count($q) as n } +} +--- expect unordered +{"p.team":"g0","n":10} +{"p.team":"g1","n":10} +--- expect shape +p.team: String +n: I64 + +--- restart + +--- query +query grouped_fanout() { + match { $p: Person $p knows $q } + return { $p.team, count($q) as n } +} +--- expect unordered +{"p.team":"g0","n":10} +{"p.team":"g1","n":10} +--- expect shape +p.team: String +n: I64 diff --git a/benchmarks/workloads/e2e_query_lookup.gqt b/benchmarks/workloads/e2e_query_lookup.gqt new file mode 100644 index 000000000..80abb08fe --- /dev/null +++ b/benchmarks/workloads/e2e_query_lookup.gqt @@ -0,0 +1,34 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query lookup() { match { $p: Person { name: "p000500" } } return { $p.name, $p.age } } +--- expect unordered +{"p.name":"p000500","p.age":0} +--- expect shape +p.name: String +p.age: I64 + +--- query +query lookup() { match { $p: Person { name: "p000500" } } return { $p.name, $p.age } } +--- expect unordered +{"p.name":"p000500","p.age":0} +--- expect shape +p.name: String +p.age: I64 + +--- restart + +--- query +query lookup() { match { $p: Person { name: "p000500" } } return { $p.name, $p.age } } +--- expect unordered +{"p.name":"p000500","p.age":0} +--- expect shape +p.name: String +p.age: I64 diff --git a/benchmarks/workloads/e2e_query_no_friends.gqt b/benchmarks/workloads/e2e_query_no_friends.gqt new file mode 100644 index 000000000..a79bb234e --- /dev/null +++ b/benchmarks/workloads/e2e_query_no_friends.gqt @@ -0,0 +1,178 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query no_friends() { match { $p: Person not { $p knows $q } } return { $p.name } } +--- expect unordered +{"p.name":"p000501"} +{"p.name":"p000503"} +{"p.name":"p000505"} +{"p.name":"p000507"} +{"p.name":"p000509"} +{"p.name":"p000511"} +{"p.name":"p000513"} +{"p.name":"p000515"} +{"p.name":"p000517"} +{"p.name":"p000519"} +{"p.name":"p000521"} +{"p.name":"p000523"} +{"p.name":"p000525"} +{"p.name":"p000527"} +{"p.name":"p000529"} +{"p.name":"p000531"} +{"p.name":"p000533"} +{"p.name":"p000535"} +{"p.name":"p000537"} +{"p.name":"p000539"} +{"p.name":"p000541"} +{"p.name":"p000543"} +{"p.name":"p000545"} +{"p.name":"p000547"} +{"p.name":"p000549"} +{"p.name":"p000551"} +{"p.name":"p000553"} +{"p.name":"p000555"} +{"p.name":"p000557"} +{"p.name":"p000559"} +{"p.name":"p000561"} +{"p.name":"p000563"} +{"p.name":"p000565"} +{"p.name":"p000567"} +{"p.name":"p000569"} +{"p.name":"p000571"} +{"p.name":"p000573"} +{"p.name":"p000575"} +{"p.name":"p000577"} +{"p.name":"p000579"} +{"p.name":"p000581"} +{"p.name":"p000583"} +{"p.name":"p000585"} +{"p.name":"p000587"} +{"p.name":"p000589"} +{"p.name":"p000591"} +{"p.name":"p000593"} +{"p.name":"p000595"} +{"p.name":"p000597"} +{"p.name":"p000599"} +--- expect shape +p.name: String + +--- query +query no_friends() { match { $p: Person not { $p knows $q } } return { $p.name } } +--- expect unordered +{"p.name":"p000501"} +{"p.name":"p000503"} +{"p.name":"p000505"} +{"p.name":"p000507"} +{"p.name":"p000509"} +{"p.name":"p000511"} +{"p.name":"p000513"} +{"p.name":"p000515"} +{"p.name":"p000517"} +{"p.name":"p000519"} +{"p.name":"p000521"} +{"p.name":"p000523"} +{"p.name":"p000525"} +{"p.name":"p000527"} +{"p.name":"p000529"} +{"p.name":"p000531"} +{"p.name":"p000533"} +{"p.name":"p000535"} +{"p.name":"p000537"} +{"p.name":"p000539"} +{"p.name":"p000541"} +{"p.name":"p000543"} +{"p.name":"p000545"} +{"p.name":"p000547"} +{"p.name":"p000549"} +{"p.name":"p000551"} +{"p.name":"p000553"} +{"p.name":"p000555"} +{"p.name":"p000557"} +{"p.name":"p000559"} +{"p.name":"p000561"} +{"p.name":"p000563"} +{"p.name":"p000565"} +{"p.name":"p000567"} +{"p.name":"p000569"} +{"p.name":"p000571"} +{"p.name":"p000573"} +{"p.name":"p000575"} +{"p.name":"p000577"} +{"p.name":"p000579"} +{"p.name":"p000581"} +{"p.name":"p000583"} +{"p.name":"p000585"} +{"p.name":"p000587"} +{"p.name":"p000589"} +{"p.name":"p000591"} +{"p.name":"p000593"} +{"p.name":"p000595"} +{"p.name":"p000597"} +{"p.name":"p000599"} +--- expect shape +p.name: String + +--- restart + +--- query +query no_friends() { match { $p: Person not { $p knows $q } } return { $p.name } } +--- expect unordered +{"p.name":"p000501"} +{"p.name":"p000503"} +{"p.name":"p000505"} +{"p.name":"p000507"} +{"p.name":"p000509"} +{"p.name":"p000511"} +{"p.name":"p000513"} +{"p.name":"p000515"} +{"p.name":"p000517"} +{"p.name":"p000519"} +{"p.name":"p000521"} +{"p.name":"p000523"} +{"p.name":"p000525"} +{"p.name":"p000527"} +{"p.name":"p000529"} +{"p.name":"p000531"} +{"p.name":"p000533"} +{"p.name":"p000535"} +{"p.name":"p000537"} +{"p.name":"p000539"} +{"p.name":"p000541"} +{"p.name":"p000543"} +{"p.name":"p000545"} +{"p.name":"p000547"} +{"p.name":"p000549"} +{"p.name":"p000551"} +{"p.name":"p000553"} +{"p.name":"p000555"} +{"p.name":"p000557"} +{"p.name":"p000559"} +{"p.name":"p000561"} +{"p.name":"p000563"} +{"p.name":"p000565"} +{"p.name":"p000567"} +{"p.name":"p000569"} +{"p.name":"p000571"} +{"p.name":"p000573"} +{"p.name":"p000575"} +{"p.name":"p000577"} +{"p.name":"p000579"} +{"p.name":"p000581"} +{"p.name":"p000583"} +{"p.name":"p000585"} +{"p.name":"p000587"} +{"p.name":"p000589"} +{"p.name":"p000591"} +{"p.name":"p000593"} +{"p.name":"p000595"} +{"p.name":"p000597"} +{"p.name":"p000599"} +--- expect shape +p.name: String diff --git a/benchmarks/workloads/e2e_query_scan.gqt b/benchmarks/workloads/e2e_query_scan.gqt new file mode 100644 index 000000000..994101075 --- /dev/null +++ b/benchmarks/workloads/e2e_query_scan.gqt @@ -0,0 +1,328 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query scan() { match { $p: Person } return { $p.name } } +--- expect unordered +{"p.name":"p000500"} +{"p.name":"p000501"} +{"p.name":"p000502"} +{"p.name":"p000503"} +{"p.name":"p000504"} +{"p.name":"p000505"} +{"p.name":"p000506"} +{"p.name":"p000507"} +{"p.name":"p000508"} +{"p.name":"p000509"} +{"p.name":"p000510"} +{"p.name":"p000511"} +{"p.name":"p000512"} +{"p.name":"p000513"} +{"p.name":"p000514"} +{"p.name":"p000515"} +{"p.name":"p000516"} +{"p.name":"p000517"} +{"p.name":"p000518"} +{"p.name":"p000519"} +{"p.name":"p000520"} +{"p.name":"p000521"} +{"p.name":"p000522"} +{"p.name":"p000523"} +{"p.name":"p000524"} +{"p.name":"p000525"} +{"p.name":"p000526"} +{"p.name":"p000527"} +{"p.name":"p000528"} +{"p.name":"p000529"} +{"p.name":"p000530"} +{"p.name":"p000531"} +{"p.name":"p000532"} +{"p.name":"p000533"} +{"p.name":"p000534"} +{"p.name":"p000535"} +{"p.name":"p000536"} +{"p.name":"p000537"} +{"p.name":"p000538"} +{"p.name":"p000539"} +{"p.name":"p000540"} +{"p.name":"p000541"} +{"p.name":"p000542"} +{"p.name":"p000543"} +{"p.name":"p000544"} +{"p.name":"p000545"} +{"p.name":"p000546"} +{"p.name":"p000547"} +{"p.name":"p000548"} +{"p.name":"p000549"} +{"p.name":"p000550"} +{"p.name":"p000551"} +{"p.name":"p000552"} +{"p.name":"p000553"} +{"p.name":"p000554"} +{"p.name":"p000555"} +{"p.name":"p000556"} +{"p.name":"p000557"} +{"p.name":"p000558"} +{"p.name":"p000559"} +{"p.name":"p000560"} +{"p.name":"p000561"} +{"p.name":"p000562"} +{"p.name":"p000563"} +{"p.name":"p000564"} +{"p.name":"p000565"} +{"p.name":"p000566"} +{"p.name":"p000567"} +{"p.name":"p000568"} +{"p.name":"p000569"} +{"p.name":"p000570"} +{"p.name":"p000571"} +{"p.name":"p000572"} +{"p.name":"p000573"} +{"p.name":"p000574"} +{"p.name":"p000575"} +{"p.name":"p000576"} +{"p.name":"p000577"} +{"p.name":"p000578"} +{"p.name":"p000579"} +{"p.name":"p000580"} +{"p.name":"p000581"} +{"p.name":"p000582"} +{"p.name":"p000583"} +{"p.name":"p000584"} +{"p.name":"p000585"} +{"p.name":"p000586"} +{"p.name":"p000587"} +{"p.name":"p000588"} +{"p.name":"p000589"} +{"p.name":"p000590"} +{"p.name":"p000591"} +{"p.name":"p000592"} +{"p.name":"p000593"} +{"p.name":"p000594"} +{"p.name":"p000595"} +{"p.name":"p000596"} +{"p.name":"p000597"} +{"p.name":"p000598"} +{"p.name":"p000599"} +--- expect shape +p.name: String + +--- query +query scan() { match { $p: Person } return { $p.name } } +--- expect unordered +{"p.name":"p000500"} +{"p.name":"p000501"} +{"p.name":"p000502"} +{"p.name":"p000503"} +{"p.name":"p000504"} +{"p.name":"p000505"} +{"p.name":"p000506"} +{"p.name":"p000507"} +{"p.name":"p000508"} +{"p.name":"p000509"} +{"p.name":"p000510"} +{"p.name":"p000511"} +{"p.name":"p000512"} +{"p.name":"p000513"} +{"p.name":"p000514"} +{"p.name":"p000515"} +{"p.name":"p000516"} +{"p.name":"p000517"} +{"p.name":"p000518"} +{"p.name":"p000519"} +{"p.name":"p000520"} +{"p.name":"p000521"} +{"p.name":"p000522"} +{"p.name":"p000523"} +{"p.name":"p000524"} +{"p.name":"p000525"} +{"p.name":"p000526"} +{"p.name":"p000527"} +{"p.name":"p000528"} +{"p.name":"p000529"} +{"p.name":"p000530"} +{"p.name":"p000531"} +{"p.name":"p000532"} +{"p.name":"p000533"} +{"p.name":"p000534"} +{"p.name":"p000535"} +{"p.name":"p000536"} +{"p.name":"p000537"} +{"p.name":"p000538"} +{"p.name":"p000539"} +{"p.name":"p000540"} +{"p.name":"p000541"} +{"p.name":"p000542"} +{"p.name":"p000543"} +{"p.name":"p000544"} +{"p.name":"p000545"} +{"p.name":"p000546"} +{"p.name":"p000547"} +{"p.name":"p000548"} +{"p.name":"p000549"} +{"p.name":"p000550"} +{"p.name":"p000551"} +{"p.name":"p000552"} +{"p.name":"p000553"} +{"p.name":"p000554"} +{"p.name":"p000555"} +{"p.name":"p000556"} +{"p.name":"p000557"} +{"p.name":"p000558"} +{"p.name":"p000559"} +{"p.name":"p000560"} +{"p.name":"p000561"} +{"p.name":"p000562"} +{"p.name":"p000563"} +{"p.name":"p000564"} +{"p.name":"p000565"} +{"p.name":"p000566"} +{"p.name":"p000567"} +{"p.name":"p000568"} +{"p.name":"p000569"} +{"p.name":"p000570"} +{"p.name":"p000571"} +{"p.name":"p000572"} +{"p.name":"p000573"} +{"p.name":"p000574"} +{"p.name":"p000575"} +{"p.name":"p000576"} +{"p.name":"p000577"} +{"p.name":"p000578"} +{"p.name":"p000579"} +{"p.name":"p000580"} +{"p.name":"p000581"} +{"p.name":"p000582"} +{"p.name":"p000583"} +{"p.name":"p000584"} +{"p.name":"p000585"} +{"p.name":"p000586"} +{"p.name":"p000587"} +{"p.name":"p000588"} +{"p.name":"p000589"} +{"p.name":"p000590"} +{"p.name":"p000591"} +{"p.name":"p000592"} +{"p.name":"p000593"} +{"p.name":"p000594"} +{"p.name":"p000595"} +{"p.name":"p000596"} +{"p.name":"p000597"} +{"p.name":"p000598"} +{"p.name":"p000599"} +--- expect shape +p.name: String + +--- restart + +--- query +query scan() { match { $p: Person } return { $p.name } } +--- expect unordered +{"p.name":"p000500"} +{"p.name":"p000501"} +{"p.name":"p000502"} +{"p.name":"p000503"} +{"p.name":"p000504"} +{"p.name":"p000505"} +{"p.name":"p000506"} +{"p.name":"p000507"} +{"p.name":"p000508"} +{"p.name":"p000509"} +{"p.name":"p000510"} +{"p.name":"p000511"} +{"p.name":"p000512"} +{"p.name":"p000513"} +{"p.name":"p000514"} +{"p.name":"p000515"} +{"p.name":"p000516"} +{"p.name":"p000517"} +{"p.name":"p000518"} +{"p.name":"p000519"} +{"p.name":"p000520"} +{"p.name":"p000521"} +{"p.name":"p000522"} +{"p.name":"p000523"} +{"p.name":"p000524"} +{"p.name":"p000525"} +{"p.name":"p000526"} +{"p.name":"p000527"} +{"p.name":"p000528"} +{"p.name":"p000529"} +{"p.name":"p000530"} +{"p.name":"p000531"} +{"p.name":"p000532"} +{"p.name":"p000533"} +{"p.name":"p000534"} +{"p.name":"p000535"} +{"p.name":"p000536"} +{"p.name":"p000537"} +{"p.name":"p000538"} +{"p.name":"p000539"} +{"p.name":"p000540"} +{"p.name":"p000541"} +{"p.name":"p000542"} +{"p.name":"p000543"} +{"p.name":"p000544"} +{"p.name":"p000545"} +{"p.name":"p000546"} +{"p.name":"p000547"} +{"p.name":"p000548"} +{"p.name":"p000549"} +{"p.name":"p000550"} +{"p.name":"p000551"} +{"p.name":"p000552"} +{"p.name":"p000553"} +{"p.name":"p000554"} +{"p.name":"p000555"} +{"p.name":"p000556"} +{"p.name":"p000557"} +{"p.name":"p000558"} +{"p.name":"p000559"} +{"p.name":"p000560"} +{"p.name":"p000561"} +{"p.name":"p000562"} +{"p.name":"p000563"} +{"p.name":"p000564"} +{"p.name":"p000565"} +{"p.name":"p000566"} +{"p.name":"p000567"} +{"p.name":"p000568"} +{"p.name":"p000569"} +{"p.name":"p000570"} +{"p.name":"p000571"} +{"p.name":"p000572"} +{"p.name":"p000573"} +{"p.name":"p000574"} +{"p.name":"p000575"} +{"p.name":"p000576"} +{"p.name":"p000577"} +{"p.name":"p000578"} +{"p.name":"p000579"} +{"p.name":"p000580"} +{"p.name":"p000581"} +{"p.name":"p000582"} +{"p.name":"p000583"} +{"p.name":"p000584"} +{"p.name":"p000585"} +{"p.name":"p000586"} +{"p.name":"p000587"} +{"p.name":"p000588"} +{"p.name":"p000589"} +{"p.name":"p000590"} +{"p.name":"p000591"} +{"p.name":"p000592"} +{"p.name":"p000593"} +{"p.name":"p000594"} +{"p.name":"p000595"} +{"p.name":"p000596"} +{"p.name":"p000597"} +{"p.name":"p000598"} +{"p.name":"p000599"} +--- expect shape +p.name: String diff --git a/benchmarks/workloads/e2e_query_top_people.gqt b/benchmarks/workloads/e2e_query_top_people.gqt new file mode 100644 index 000000000..2cb5d6036 --- /dev/null +++ b/benchmarks/workloads/e2e_query_top_people.gqt @@ -0,0 +1,106 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query top_people() { + match { $p: Person } + return { $p.name, $p.age } + order { $p.age desc, $p.name asc } + limit 20 +} +--- expect ordered +{"p.name":"p000599","p.age":99} +{"p.name":"p000598","p.age":98} +{"p.name":"p000597","p.age":97} +{"p.name":"p000596","p.age":96} +{"p.name":"p000595","p.age":95} +{"p.name":"p000594","p.age":94} +{"p.name":"p000593","p.age":93} +{"p.name":"p000592","p.age":92} +{"p.name":"p000591","p.age":91} +{"p.name":"p000590","p.age":90} +{"p.name":"p000589","p.age":89} +{"p.name":"p000588","p.age":88} +{"p.name":"p000587","p.age":87} +{"p.name":"p000586","p.age":86} +{"p.name":"p000585","p.age":85} +{"p.name":"p000584","p.age":84} +{"p.name":"p000583","p.age":83} +{"p.name":"p000582","p.age":82} +{"p.name":"p000581","p.age":81} +{"p.name":"p000580","p.age":80} +--- expect shape +p.name: String +p.age: I64 + +--- query +query top_people() { + match { $p: Person } + return { $p.name, $p.age } + order { $p.age desc, $p.name asc } + limit 20 +} +--- expect ordered +{"p.name":"p000599","p.age":99} +{"p.name":"p000598","p.age":98} +{"p.name":"p000597","p.age":97} +{"p.name":"p000596","p.age":96} +{"p.name":"p000595","p.age":95} +{"p.name":"p000594","p.age":94} +{"p.name":"p000593","p.age":93} +{"p.name":"p000592","p.age":92} +{"p.name":"p000591","p.age":91} +{"p.name":"p000590","p.age":90} +{"p.name":"p000589","p.age":89} +{"p.name":"p000588","p.age":88} +{"p.name":"p000587","p.age":87} +{"p.name":"p000586","p.age":86} +{"p.name":"p000585","p.age":85} +{"p.name":"p000584","p.age":84} +{"p.name":"p000583","p.age":83} +{"p.name":"p000582","p.age":82} +{"p.name":"p000581","p.age":81} +{"p.name":"p000580","p.age":80} +--- expect shape +p.name: String +p.age: I64 + +--- restart + +--- query +query top_people() { + match { $p: Person } + return { $p.name, $p.age } + order { $p.age desc, $p.name asc } + limit 20 +} +--- expect ordered +{"p.name":"p000599","p.age":99} +{"p.name":"p000598","p.age":98} +{"p.name":"p000597","p.age":97} +{"p.name":"p000596","p.age":96} +{"p.name":"p000595","p.age":95} +{"p.name":"p000594","p.age":94} +{"p.name":"p000593","p.age":93} +{"p.name":"p000592","p.age":92} +{"p.name":"p000591","p.age":91} +{"p.name":"p000590","p.age":90} +{"p.name":"p000589","p.age":89} +{"p.name":"p000588","p.age":88} +{"p.name":"p000587","p.age":87} +{"p.name":"p000586","p.age":86} +{"p.name":"p000585","p.age":85} +{"p.name":"p000584","p.age":84} +{"p.name":"p000583","p.age":83} +{"p.name":"p000582","p.age":82} +{"p.name":"p000581","p.age":81} +{"p.name":"p000580","p.age":80} +--- expect shape +p.name: String +p.age: I64 diff --git a/benchmarks/workloads/e2e_query_wide_scan.gqt b/benchmarks/workloads/e2e_query_wide_scan.gqt new file mode 100644 index 000000000..c8aa6d960 --- /dev/null +++ b/benchmarks/workloads/e2e_query_wide_scan.gqt @@ -0,0 +1,124 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query wide_scan() { match { $p: Person } return { $p } } +--- expect unordered +{"p":{"@id":"p000500","name":"p000500","age":0,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000501","name":"p000501","age":1,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000502","name":"p000502","age":2,"team":"g2","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000503","name":"p000503","age":3,"team":"g3","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000504","name":"p000504","age":4,"team":"g4","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000505","name":"p000505","age":5,"team":"g5","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000506","name":"p000506","age":6,"team":"g6","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000507","name":"p000507","age":7,"team":"g7","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000508","name":"p000508","age":8,"team":"g8","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000509","name":"p000509","age":9,"team":"g9","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000510","name":"p000510","age":10,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000511","name":"p000511","age":11,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000512","name":"p000512","age":12,"team":"g2","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000513","name":"p000513","age":13,"team":"g3","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000514","name":"p000514","age":14,"team":"g4","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000515","name":"p000515","age":15,"team":"g5","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000516","name":"p000516","age":16,"team":"g6","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000517","name":"p000517","age":17,"team":"g7","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000518","name":"p000518","age":18,"team":"g8","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000519","name":"p000519","age":19,"team":"g9","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000520","name":"p000520","age":20,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000521","name":"p000521","age":21,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000522","name":"p000522","age":22,"team":"g2","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000523","name":"p000523","age":23,"team":"g3","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000524","name":"p000524","age":24,"team":"g4","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000525","name":"p000525","age":25,"team":"g5","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000526","name":"p000526","age":26,"team":"g6","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000527","name":"p000527","age":27,"team":"g7","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000528","name":"p000528","age":28,"team":"g8","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000529","name":"p000529","age":29,"team":"g9","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000530","name":"p000530","age":30,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000531","name":"p000531","age":31,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +--- expect shape +p: Person + +--- query +query wide_scan() { match { $p: Person } return { $p } } +--- expect unordered +{"p":{"@id":"p000500","name":"p000500","age":0,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000501","name":"p000501","age":1,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000502","name":"p000502","age":2,"team":"g2","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000503","name":"p000503","age":3,"team":"g3","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000504","name":"p000504","age":4,"team":"g4","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000505","name":"p000505","age":5,"team":"g5","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000506","name":"p000506","age":6,"team":"g6","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000507","name":"p000507","age":7,"team":"g7","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000508","name":"p000508","age":8,"team":"g8","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000509","name":"p000509","age":9,"team":"g9","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000510","name":"p000510","age":10,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000511","name":"p000511","age":11,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000512","name":"p000512","age":12,"team":"g2","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000513","name":"p000513","age":13,"team":"g3","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000514","name":"p000514","age":14,"team":"g4","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000515","name":"p000515","age":15,"team":"g5","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000516","name":"p000516","age":16,"team":"g6","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000517","name":"p000517","age":17,"team":"g7","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000518","name":"p000518","age":18,"team":"g8","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000519","name":"p000519","age":19,"team":"g9","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000520","name":"p000520","age":20,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000521","name":"p000521","age":21,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000522","name":"p000522","age":22,"team":"g2","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000523","name":"p000523","age":23,"team":"g3","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000524","name":"p000524","age":24,"team":"g4","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000525","name":"p000525","age":25,"team":"g5","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000526","name":"p000526","age":26,"team":"g6","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000527","name":"p000527","age":27,"team":"g7","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000528","name":"p000528","age":28,"team":"g8","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000529","name":"p000529","age":29,"team":"g9","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000530","name":"p000530","age":30,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000531","name":"p000531","age":31,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +--- expect shape +p: Person + +--- restart + +--- query +query wide_scan() { match { $p: Person } return { $p } } +--- expect unordered +{"p":{"@id":"p000500","name":"p000500","age":0,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000501","name":"p000501","age":1,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000502","name":"p000502","age":2,"team":"g2","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000503","name":"p000503","age":3,"team":"g3","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000504","name":"p000504","age":4,"team":"g4","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000505","name":"p000505","age":5,"team":"g5","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000506","name":"p000506","age":6,"team":"g6","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000507","name":"p000507","age":7,"team":"g7","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000508","name":"p000508","age":8,"team":"g8","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000509","name":"p000509","age":9,"team":"g9","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000510","name":"p000510","age":10,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000511","name":"p000511","age":11,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000512","name":"p000512","age":12,"team":"g2","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000513","name":"p000513","age":13,"team":"g3","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000514","name":"p000514","age":14,"team":"g4","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000515","name":"p000515","age":15,"team":"g5","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000516","name":"p000516","age":16,"team":"g6","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000517","name":"p000517","age":17,"team":"g7","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000518","name":"p000518","age":18,"team":"g8","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000519","name":"p000519","age":19,"team":"g9","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000520","name":"p000520","age":20,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000521","name":"p000521","age":21,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000522","name":"p000522","age":22,"team":"g2","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000523","name":"p000523","age":23,"team":"g3","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000524","name":"p000524","age":24,"team":"g4","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000525","name":"p000525","age":25,"team":"g5","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000526","name":"p000526","age":26,"team":"g6","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000527","name":"p000527","age":27,"team":"g7","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000528","name":"p000528","age":28,"team":"g8","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000529","name":"p000529","age":29,"team":"g9","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000530","name":"p000530","age":30,"team":"g0","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +{"p":{"@id":"p000531","name":"p000531","age":31,"team":"g1","bio":"synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography synthetic person biography "}} +--- expect shape +p: Person diff --git a/benchmarks/workloads/e2e_rrf_traversal.gqt b/benchmarks/workloads/e2e_rrf_traversal.gqt new file mode 100644 index 000000000..7b9a9a41b --- /dev/null +++ b/benchmarks/workloads/e2e_rrf_traversal.gqt @@ -0,0 +1,62 @@ +# issue: none +# notes: Complete auto-planned BM25/BM25 RRF query with traversal and exact winner x; bounded replacement for the rrf-gate engine read. One operation on a fresh handle is timed; checks and restart are outside the timer. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query recall_two_terms($q1: String, $q2: String) { + match { + $c: Chunk + $a: Artifact + $c chunkOfArtifact $a + search($c.text, $q1) + } + return { $c.slug } + order { rrf(bm25($c.text, $q1), bm25($c.text, $q2)) } + limit 1 +} + +--- params +{"q1":"alpha","q2":"beta"} + +--- expect unordered +{"c.slug":"x"} + +--- expect shape +c.slug: String + +--- expect plan +expand $c $a: selection named [ChunkOfArtifact out] +rank fuse row tiebreak [$a.@id] + +--- restart + +--- query +query recall_two_terms($q1: String, $q2: String) { + match { + $c: Chunk + $a: Artifact + $c chunkOfArtifact $a + search($c.text, $q1) + } + return { $c.slug } + order { rrf(bm25($c.text, $q1), bm25($c.text, $q2)) } + limit 1 +} + +--- params +{"q1":"alpha","q2":"beta"} + +--- expect unordered +{"c.slug":"x"} + +--- expect shape +c.slug: String + +--- expect plan +expand $c $a: selection named [ChunkOfArtifact out] +rank fuse row tiebreak [$a.@id] diff --git a/benchmarks/workloads/e2e_traversal_hop1.gqt b/benchmarks/workloads/e2e_traversal_hop1.gqt new file mode 100644 index 000000000..b647dc127 --- /dev/null +++ b/benchmarks/workloads/e2e_traversal_hop1.gqt @@ -0,0 +1,148 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query hop1() { + match { + $a: Person + $b: Person + $a knows $b + } + return { $a.name, $b.name } +} +--- expect unordered +{"a.name":"p0","b.name":"p1"} +{"a.name":"p0","b.name":"p4"} +{"a.name":"p1","b.name":"p2"} +{"a.name":"p1","b.name":"p5"} +{"a.name":"p2","b.name":"p3"} +{"a.name":"p2","b.name":"p6"} +{"a.name":"p3","b.name":"p4"} +{"a.name":"p3","b.name":"p7"} +{"a.name":"p4","b.name":"p5"} +{"a.name":"p4","b.name":"p8"} +{"a.name":"p5","b.name":"p6"} +{"a.name":"p5","b.name":"p9"} +{"a.name":"p6","b.name":"p7"} +{"a.name":"p6","b.name":"p10"} +{"a.name":"p7","b.name":"p8"} +{"a.name":"p7","b.name":"p11"} +{"a.name":"p8","b.name":"p9"} +{"a.name":"p8","b.name":"p12"} +{"a.name":"p9","b.name":"p10"} +{"a.name":"p9","b.name":"p13"} +{"a.name":"p10","b.name":"p11"} +{"a.name":"p10","b.name":"p14"} +{"a.name":"p11","b.name":"p12"} +{"a.name":"p11","b.name":"p15"} +{"a.name":"p12","b.name":"p13"} +{"a.name":"p12","b.name":"p0"} +{"a.name":"p13","b.name":"p14"} +{"a.name":"p13","b.name":"p1"} +{"a.name":"p14","b.name":"p15"} +{"a.name":"p14","b.name":"p2"} +{"a.name":"p15","b.name":"p0"} +{"a.name":"p15","b.name":"p3"} +--- expect shape +a.name: String +b.name: String + +--- query +query hop1() { + match { + $a: Person + $b: Person + $a knows $b + } + return { $a.name, $b.name } +} +--- expect unordered +{"a.name":"p0","b.name":"p1"} +{"a.name":"p0","b.name":"p4"} +{"a.name":"p1","b.name":"p2"} +{"a.name":"p1","b.name":"p5"} +{"a.name":"p2","b.name":"p3"} +{"a.name":"p2","b.name":"p6"} +{"a.name":"p3","b.name":"p4"} +{"a.name":"p3","b.name":"p7"} +{"a.name":"p4","b.name":"p5"} +{"a.name":"p4","b.name":"p8"} +{"a.name":"p5","b.name":"p6"} +{"a.name":"p5","b.name":"p9"} +{"a.name":"p6","b.name":"p7"} +{"a.name":"p6","b.name":"p10"} +{"a.name":"p7","b.name":"p8"} +{"a.name":"p7","b.name":"p11"} +{"a.name":"p8","b.name":"p9"} +{"a.name":"p8","b.name":"p12"} +{"a.name":"p9","b.name":"p10"} +{"a.name":"p9","b.name":"p13"} +{"a.name":"p10","b.name":"p11"} +{"a.name":"p10","b.name":"p14"} +{"a.name":"p11","b.name":"p12"} +{"a.name":"p11","b.name":"p15"} +{"a.name":"p12","b.name":"p13"} +{"a.name":"p12","b.name":"p0"} +{"a.name":"p13","b.name":"p14"} +{"a.name":"p13","b.name":"p1"} +{"a.name":"p14","b.name":"p15"} +{"a.name":"p14","b.name":"p2"} +{"a.name":"p15","b.name":"p0"} +{"a.name":"p15","b.name":"p3"} +--- expect shape +a.name: String +b.name: String + +--- restart + +--- query +query hop1() { + match { + $a: Person + $b: Person + $a knows $b + } + return { $a.name, $b.name } +} +--- expect unordered +{"a.name":"p0","b.name":"p1"} +{"a.name":"p0","b.name":"p4"} +{"a.name":"p1","b.name":"p2"} +{"a.name":"p1","b.name":"p5"} +{"a.name":"p2","b.name":"p3"} +{"a.name":"p2","b.name":"p6"} +{"a.name":"p3","b.name":"p4"} +{"a.name":"p3","b.name":"p7"} +{"a.name":"p4","b.name":"p5"} +{"a.name":"p4","b.name":"p8"} +{"a.name":"p5","b.name":"p6"} +{"a.name":"p5","b.name":"p9"} +{"a.name":"p6","b.name":"p7"} +{"a.name":"p6","b.name":"p10"} +{"a.name":"p7","b.name":"p8"} +{"a.name":"p7","b.name":"p11"} +{"a.name":"p8","b.name":"p9"} +{"a.name":"p8","b.name":"p12"} +{"a.name":"p9","b.name":"p10"} +{"a.name":"p9","b.name":"p13"} +{"a.name":"p10","b.name":"p11"} +{"a.name":"p10","b.name":"p14"} +{"a.name":"p11","b.name":"p12"} +{"a.name":"p11","b.name":"p15"} +{"a.name":"p12","b.name":"p13"} +{"a.name":"p12","b.name":"p0"} +{"a.name":"p13","b.name":"p14"} +{"a.name":"p13","b.name":"p1"} +{"a.name":"p14","b.name":"p15"} +{"a.name":"p14","b.name":"p2"} +{"a.name":"p15","b.name":"p0"} +{"a.name":"p15","b.name":"p3"} +--- expect shape +a.name: String +b.name: String diff --git a/benchmarks/workloads/e2e_traversal_hop2.gqt b/benchmarks/workloads/e2e_traversal_hop2.gqt new file mode 100644 index 000000000..0c9051e95 --- /dev/null +++ b/benchmarks/workloads/e2e_traversal_hop2.gqt @@ -0,0 +1,250 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query hop2() { + match { + $a: Person + $b: Person + $c: Person + $a knows $b + $b knows $c + } + return { $a.name, $c.name } +} +--- expect unordered +{"a.name":"p0","c.name":"p2"} +{"a.name":"p0","c.name":"p5"} +{"a.name":"p0","c.name":"p5"} +{"a.name":"p0","c.name":"p8"} +{"a.name":"p1","c.name":"p3"} +{"a.name":"p1","c.name":"p6"} +{"a.name":"p1","c.name":"p6"} +{"a.name":"p1","c.name":"p9"} +{"a.name":"p2","c.name":"p4"} +{"a.name":"p2","c.name":"p7"} +{"a.name":"p2","c.name":"p7"} +{"a.name":"p2","c.name":"p10"} +{"a.name":"p3","c.name":"p5"} +{"a.name":"p3","c.name":"p8"} +{"a.name":"p3","c.name":"p8"} +{"a.name":"p3","c.name":"p11"} +{"a.name":"p4","c.name":"p6"} +{"a.name":"p4","c.name":"p9"} +{"a.name":"p4","c.name":"p9"} +{"a.name":"p4","c.name":"p12"} +{"a.name":"p5","c.name":"p7"} +{"a.name":"p5","c.name":"p10"} +{"a.name":"p5","c.name":"p10"} +{"a.name":"p5","c.name":"p13"} +{"a.name":"p6","c.name":"p8"} +{"a.name":"p6","c.name":"p11"} +{"a.name":"p6","c.name":"p11"} +{"a.name":"p6","c.name":"p14"} +{"a.name":"p7","c.name":"p9"} +{"a.name":"p7","c.name":"p12"} +{"a.name":"p7","c.name":"p12"} +{"a.name":"p7","c.name":"p15"} +{"a.name":"p8","c.name":"p10"} +{"a.name":"p8","c.name":"p13"} +{"a.name":"p8","c.name":"p13"} +{"a.name":"p8","c.name":"p0"} +{"a.name":"p9","c.name":"p11"} +{"a.name":"p9","c.name":"p14"} +{"a.name":"p9","c.name":"p14"} +{"a.name":"p9","c.name":"p1"} +{"a.name":"p10","c.name":"p12"} +{"a.name":"p10","c.name":"p15"} +{"a.name":"p10","c.name":"p15"} +{"a.name":"p10","c.name":"p2"} +{"a.name":"p11","c.name":"p13"} +{"a.name":"p11","c.name":"p0"} +{"a.name":"p11","c.name":"p0"} +{"a.name":"p11","c.name":"p3"} +{"a.name":"p12","c.name":"p14"} +{"a.name":"p12","c.name":"p1"} +{"a.name":"p12","c.name":"p1"} +{"a.name":"p12","c.name":"p4"} +{"a.name":"p13","c.name":"p15"} +{"a.name":"p13","c.name":"p2"} +{"a.name":"p13","c.name":"p2"} +{"a.name":"p13","c.name":"p5"} +{"a.name":"p14","c.name":"p0"} +{"a.name":"p14","c.name":"p3"} +{"a.name":"p14","c.name":"p3"} +{"a.name":"p14","c.name":"p6"} +{"a.name":"p15","c.name":"p1"} +{"a.name":"p15","c.name":"p4"} +{"a.name":"p15","c.name":"p4"} +{"a.name":"p15","c.name":"p7"} +--- expect shape +a.name: String +c.name: String + +--- query +query hop2() { + match { + $a: Person + $b: Person + $c: Person + $a knows $b + $b knows $c + } + return { $a.name, $c.name } +} +--- expect unordered +{"a.name":"p0","c.name":"p2"} +{"a.name":"p0","c.name":"p5"} +{"a.name":"p0","c.name":"p5"} +{"a.name":"p0","c.name":"p8"} +{"a.name":"p1","c.name":"p3"} +{"a.name":"p1","c.name":"p6"} +{"a.name":"p1","c.name":"p6"} +{"a.name":"p1","c.name":"p9"} +{"a.name":"p2","c.name":"p4"} +{"a.name":"p2","c.name":"p7"} +{"a.name":"p2","c.name":"p7"} +{"a.name":"p2","c.name":"p10"} +{"a.name":"p3","c.name":"p5"} +{"a.name":"p3","c.name":"p8"} +{"a.name":"p3","c.name":"p8"} +{"a.name":"p3","c.name":"p11"} +{"a.name":"p4","c.name":"p6"} +{"a.name":"p4","c.name":"p9"} +{"a.name":"p4","c.name":"p9"} +{"a.name":"p4","c.name":"p12"} +{"a.name":"p5","c.name":"p7"} +{"a.name":"p5","c.name":"p10"} +{"a.name":"p5","c.name":"p10"} +{"a.name":"p5","c.name":"p13"} +{"a.name":"p6","c.name":"p8"} +{"a.name":"p6","c.name":"p11"} +{"a.name":"p6","c.name":"p11"} +{"a.name":"p6","c.name":"p14"} +{"a.name":"p7","c.name":"p9"} +{"a.name":"p7","c.name":"p12"} +{"a.name":"p7","c.name":"p12"} +{"a.name":"p7","c.name":"p15"} +{"a.name":"p8","c.name":"p10"} +{"a.name":"p8","c.name":"p13"} +{"a.name":"p8","c.name":"p13"} +{"a.name":"p8","c.name":"p0"} +{"a.name":"p9","c.name":"p11"} +{"a.name":"p9","c.name":"p14"} +{"a.name":"p9","c.name":"p14"} +{"a.name":"p9","c.name":"p1"} +{"a.name":"p10","c.name":"p12"} +{"a.name":"p10","c.name":"p15"} +{"a.name":"p10","c.name":"p15"} +{"a.name":"p10","c.name":"p2"} +{"a.name":"p11","c.name":"p13"} +{"a.name":"p11","c.name":"p0"} +{"a.name":"p11","c.name":"p0"} +{"a.name":"p11","c.name":"p3"} +{"a.name":"p12","c.name":"p14"} +{"a.name":"p12","c.name":"p1"} +{"a.name":"p12","c.name":"p1"} +{"a.name":"p12","c.name":"p4"} +{"a.name":"p13","c.name":"p15"} +{"a.name":"p13","c.name":"p2"} +{"a.name":"p13","c.name":"p2"} +{"a.name":"p13","c.name":"p5"} +{"a.name":"p14","c.name":"p0"} +{"a.name":"p14","c.name":"p3"} +{"a.name":"p14","c.name":"p3"} +{"a.name":"p14","c.name":"p6"} +{"a.name":"p15","c.name":"p1"} +{"a.name":"p15","c.name":"p4"} +{"a.name":"p15","c.name":"p4"} +{"a.name":"p15","c.name":"p7"} +--- expect shape +a.name: String +c.name: String + +--- restart + +--- query +query hop2() { + match { + $a: Person + $b: Person + $c: Person + $a knows $b + $b knows $c + } + return { $a.name, $c.name } +} +--- expect unordered +{"a.name":"p0","c.name":"p2"} +{"a.name":"p0","c.name":"p5"} +{"a.name":"p0","c.name":"p5"} +{"a.name":"p0","c.name":"p8"} +{"a.name":"p1","c.name":"p3"} +{"a.name":"p1","c.name":"p6"} +{"a.name":"p1","c.name":"p6"} +{"a.name":"p1","c.name":"p9"} +{"a.name":"p2","c.name":"p4"} +{"a.name":"p2","c.name":"p7"} +{"a.name":"p2","c.name":"p7"} +{"a.name":"p2","c.name":"p10"} +{"a.name":"p3","c.name":"p5"} +{"a.name":"p3","c.name":"p8"} +{"a.name":"p3","c.name":"p8"} +{"a.name":"p3","c.name":"p11"} +{"a.name":"p4","c.name":"p6"} +{"a.name":"p4","c.name":"p9"} +{"a.name":"p4","c.name":"p9"} +{"a.name":"p4","c.name":"p12"} +{"a.name":"p5","c.name":"p7"} +{"a.name":"p5","c.name":"p10"} +{"a.name":"p5","c.name":"p10"} +{"a.name":"p5","c.name":"p13"} +{"a.name":"p6","c.name":"p8"} +{"a.name":"p6","c.name":"p11"} +{"a.name":"p6","c.name":"p11"} +{"a.name":"p6","c.name":"p14"} +{"a.name":"p7","c.name":"p9"} +{"a.name":"p7","c.name":"p12"} +{"a.name":"p7","c.name":"p12"} +{"a.name":"p7","c.name":"p15"} +{"a.name":"p8","c.name":"p10"} +{"a.name":"p8","c.name":"p13"} +{"a.name":"p8","c.name":"p13"} +{"a.name":"p8","c.name":"p0"} +{"a.name":"p9","c.name":"p11"} +{"a.name":"p9","c.name":"p14"} +{"a.name":"p9","c.name":"p14"} +{"a.name":"p9","c.name":"p1"} +{"a.name":"p10","c.name":"p12"} +{"a.name":"p10","c.name":"p15"} +{"a.name":"p10","c.name":"p15"} +{"a.name":"p10","c.name":"p2"} +{"a.name":"p11","c.name":"p13"} +{"a.name":"p11","c.name":"p0"} +{"a.name":"p11","c.name":"p0"} +{"a.name":"p11","c.name":"p3"} +{"a.name":"p12","c.name":"p14"} +{"a.name":"p12","c.name":"p1"} +{"a.name":"p12","c.name":"p1"} +{"a.name":"p12","c.name":"p4"} +{"a.name":"p13","c.name":"p15"} +{"a.name":"p13","c.name":"p2"} +{"a.name":"p13","c.name":"p2"} +{"a.name":"p13","c.name":"p5"} +{"a.name":"p14","c.name":"p0"} +{"a.name":"p14","c.name":"p3"} +{"a.name":"p14","c.name":"p3"} +{"a.name":"p14","c.name":"p6"} +{"a.name":"p15","c.name":"p1"} +{"a.name":"p15","c.name":"p4"} +{"a.name":"p15","c.name":"p4"} +{"a.name":"p15","c.name":"p7"} +--- expect shape +a.name: String +c.name: String diff --git a/benchmarks/workloads/e2e_traversal_hop3.gqt b/benchmarks/workloads/e2e_traversal_hop3.gqt new file mode 100644 index 000000000..a3ebaec29 --- /dev/null +++ b/benchmarks/workloads/e2e_traversal_hop3.gqt @@ -0,0 +1,448 @@ +# issue: none +# notes: One checked warmup precedes one measured query per fresh process; a restart and exact result check follow. This repetition boundary differs from the former repeated Rust timing loop. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query hop3() { + match { + $a: Person + $b: Person + $c: Person + $d: Person + $a knows $b + $b knows $c + $c knows $d + } + return { $a.name, $d.name } +} +--- expect unordered +{"a.name":"p0","d.name":"p3"} +{"a.name":"p0","d.name":"p6"} +{"a.name":"p0","d.name":"p6"} +{"a.name":"p0","d.name":"p9"} +{"a.name":"p0","d.name":"p6"} +{"a.name":"p0","d.name":"p9"} +{"a.name":"p0","d.name":"p9"} +{"a.name":"p0","d.name":"p12"} +{"a.name":"p1","d.name":"p4"} +{"a.name":"p1","d.name":"p7"} +{"a.name":"p1","d.name":"p7"} +{"a.name":"p1","d.name":"p10"} +{"a.name":"p1","d.name":"p7"} +{"a.name":"p1","d.name":"p10"} +{"a.name":"p1","d.name":"p10"} +{"a.name":"p1","d.name":"p13"} +{"a.name":"p2","d.name":"p5"} +{"a.name":"p2","d.name":"p8"} +{"a.name":"p2","d.name":"p8"} +{"a.name":"p2","d.name":"p11"} +{"a.name":"p2","d.name":"p8"} +{"a.name":"p2","d.name":"p11"} +{"a.name":"p2","d.name":"p11"} +{"a.name":"p2","d.name":"p14"} +{"a.name":"p3","d.name":"p6"} +{"a.name":"p3","d.name":"p9"} +{"a.name":"p3","d.name":"p9"} +{"a.name":"p3","d.name":"p12"} +{"a.name":"p3","d.name":"p9"} +{"a.name":"p3","d.name":"p12"} +{"a.name":"p3","d.name":"p12"} +{"a.name":"p3","d.name":"p15"} +{"a.name":"p4","d.name":"p7"} +{"a.name":"p4","d.name":"p10"} +{"a.name":"p4","d.name":"p10"} +{"a.name":"p4","d.name":"p13"} +{"a.name":"p4","d.name":"p10"} +{"a.name":"p4","d.name":"p13"} +{"a.name":"p4","d.name":"p13"} +{"a.name":"p4","d.name":"p0"} +{"a.name":"p5","d.name":"p8"} +{"a.name":"p5","d.name":"p11"} +{"a.name":"p5","d.name":"p11"} +{"a.name":"p5","d.name":"p14"} +{"a.name":"p5","d.name":"p11"} +{"a.name":"p5","d.name":"p14"} +{"a.name":"p5","d.name":"p14"} +{"a.name":"p5","d.name":"p1"} +{"a.name":"p6","d.name":"p9"} +{"a.name":"p6","d.name":"p12"} +{"a.name":"p6","d.name":"p12"} +{"a.name":"p6","d.name":"p15"} +{"a.name":"p6","d.name":"p12"} +{"a.name":"p6","d.name":"p15"} +{"a.name":"p6","d.name":"p15"} +{"a.name":"p6","d.name":"p2"} +{"a.name":"p7","d.name":"p10"} +{"a.name":"p7","d.name":"p13"} +{"a.name":"p7","d.name":"p13"} +{"a.name":"p7","d.name":"p0"} +{"a.name":"p7","d.name":"p13"} +{"a.name":"p7","d.name":"p0"} +{"a.name":"p7","d.name":"p0"} +{"a.name":"p7","d.name":"p3"} +{"a.name":"p8","d.name":"p11"} +{"a.name":"p8","d.name":"p14"} +{"a.name":"p8","d.name":"p14"} +{"a.name":"p8","d.name":"p1"} +{"a.name":"p8","d.name":"p14"} +{"a.name":"p8","d.name":"p1"} +{"a.name":"p8","d.name":"p1"} +{"a.name":"p8","d.name":"p4"} +{"a.name":"p9","d.name":"p12"} +{"a.name":"p9","d.name":"p15"} +{"a.name":"p9","d.name":"p15"} +{"a.name":"p9","d.name":"p2"} +{"a.name":"p9","d.name":"p15"} +{"a.name":"p9","d.name":"p2"} +{"a.name":"p9","d.name":"p2"} +{"a.name":"p9","d.name":"p5"} +{"a.name":"p10","d.name":"p13"} +{"a.name":"p10","d.name":"p0"} +{"a.name":"p10","d.name":"p0"} +{"a.name":"p10","d.name":"p3"} +{"a.name":"p10","d.name":"p0"} +{"a.name":"p10","d.name":"p3"} +{"a.name":"p10","d.name":"p3"} +{"a.name":"p10","d.name":"p6"} +{"a.name":"p11","d.name":"p14"} +{"a.name":"p11","d.name":"p1"} +{"a.name":"p11","d.name":"p1"} +{"a.name":"p11","d.name":"p4"} +{"a.name":"p11","d.name":"p1"} +{"a.name":"p11","d.name":"p4"} +{"a.name":"p11","d.name":"p4"} +{"a.name":"p11","d.name":"p7"} +{"a.name":"p12","d.name":"p15"} +{"a.name":"p12","d.name":"p2"} +{"a.name":"p12","d.name":"p2"} +{"a.name":"p12","d.name":"p5"} +{"a.name":"p12","d.name":"p2"} +{"a.name":"p12","d.name":"p5"} +{"a.name":"p12","d.name":"p5"} +{"a.name":"p12","d.name":"p8"} +{"a.name":"p13","d.name":"p0"} +{"a.name":"p13","d.name":"p3"} +{"a.name":"p13","d.name":"p3"} +{"a.name":"p13","d.name":"p6"} +{"a.name":"p13","d.name":"p3"} +{"a.name":"p13","d.name":"p6"} +{"a.name":"p13","d.name":"p6"} +{"a.name":"p13","d.name":"p9"} +{"a.name":"p14","d.name":"p1"} +{"a.name":"p14","d.name":"p4"} +{"a.name":"p14","d.name":"p4"} +{"a.name":"p14","d.name":"p7"} +{"a.name":"p14","d.name":"p4"} +{"a.name":"p14","d.name":"p7"} +{"a.name":"p14","d.name":"p7"} +{"a.name":"p14","d.name":"p10"} +{"a.name":"p15","d.name":"p2"} +{"a.name":"p15","d.name":"p5"} +{"a.name":"p15","d.name":"p5"} +{"a.name":"p15","d.name":"p8"} +{"a.name":"p15","d.name":"p5"} +{"a.name":"p15","d.name":"p8"} +{"a.name":"p15","d.name":"p8"} +{"a.name":"p15","d.name":"p11"} +--- expect shape +a.name: String +d.name: String + +--- query +query hop3() { + match { + $a: Person + $b: Person + $c: Person + $d: Person + $a knows $b + $b knows $c + $c knows $d + } + return { $a.name, $d.name } +} +--- expect unordered +{"a.name":"p0","d.name":"p3"} +{"a.name":"p0","d.name":"p6"} +{"a.name":"p0","d.name":"p6"} +{"a.name":"p0","d.name":"p9"} +{"a.name":"p0","d.name":"p6"} +{"a.name":"p0","d.name":"p9"} +{"a.name":"p0","d.name":"p9"} +{"a.name":"p0","d.name":"p12"} +{"a.name":"p1","d.name":"p4"} +{"a.name":"p1","d.name":"p7"} +{"a.name":"p1","d.name":"p7"} +{"a.name":"p1","d.name":"p10"} +{"a.name":"p1","d.name":"p7"} +{"a.name":"p1","d.name":"p10"} +{"a.name":"p1","d.name":"p10"} +{"a.name":"p1","d.name":"p13"} +{"a.name":"p2","d.name":"p5"} +{"a.name":"p2","d.name":"p8"} +{"a.name":"p2","d.name":"p8"} +{"a.name":"p2","d.name":"p11"} +{"a.name":"p2","d.name":"p8"} +{"a.name":"p2","d.name":"p11"} +{"a.name":"p2","d.name":"p11"} +{"a.name":"p2","d.name":"p14"} +{"a.name":"p3","d.name":"p6"} +{"a.name":"p3","d.name":"p9"} +{"a.name":"p3","d.name":"p9"} +{"a.name":"p3","d.name":"p12"} +{"a.name":"p3","d.name":"p9"} +{"a.name":"p3","d.name":"p12"} +{"a.name":"p3","d.name":"p12"} +{"a.name":"p3","d.name":"p15"} +{"a.name":"p4","d.name":"p7"} +{"a.name":"p4","d.name":"p10"} +{"a.name":"p4","d.name":"p10"} +{"a.name":"p4","d.name":"p13"} +{"a.name":"p4","d.name":"p10"} +{"a.name":"p4","d.name":"p13"} +{"a.name":"p4","d.name":"p13"} +{"a.name":"p4","d.name":"p0"} +{"a.name":"p5","d.name":"p8"} +{"a.name":"p5","d.name":"p11"} +{"a.name":"p5","d.name":"p11"} +{"a.name":"p5","d.name":"p14"} +{"a.name":"p5","d.name":"p11"} +{"a.name":"p5","d.name":"p14"} +{"a.name":"p5","d.name":"p14"} +{"a.name":"p5","d.name":"p1"} +{"a.name":"p6","d.name":"p9"} +{"a.name":"p6","d.name":"p12"} +{"a.name":"p6","d.name":"p12"} +{"a.name":"p6","d.name":"p15"} +{"a.name":"p6","d.name":"p12"} +{"a.name":"p6","d.name":"p15"} +{"a.name":"p6","d.name":"p15"} +{"a.name":"p6","d.name":"p2"} +{"a.name":"p7","d.name":"p10"} +{"a.name":"p7","d.name":"p13"} +{"a.name":"p7","d.name":"p13"} +{"a.name":"p7","d.name":"p0"} +{"a.name":"p7","d.name":"p13"} +{"a.name":"p7","d.name":"p0"} +{"a.name":"p7","d.name":"p0"} +{"a.name":"p7","d.name":"p3"} +{"a.name":"p8","d.name":"p11"} +{"a.name":"p8","d.name":"p14"} +{"a.name":"p8","d.name":"p14"} +{"a.name":"p8","d.name":"p1"} +{"a.name":"p8","d.name":"p14"} +{"a.name":"p8","d.name":"p1"} +{"a.name":"p8","d.name":"p1"} +{"a.name":"p8","d.name":"p4"} +{"a.name":"p9","d.name":"p12"} +{"a.name":"p9","d.name":"p15"} +{"a.name":"p9","d.name":"p15"} +{"a.name":"p9","d.name":"p2"} +{"a.name":"p9","d.name":"p15"} +{"a.name":"p9","d.name":"p2"} +{"a.name":"p9","d.name":"p2"} +{"a.name":"p9","d.name":"p5"} +{"a.name":"p10","d.name":"p13"} +{"a.name":"p10","d.name":"p0"} +{"a.name":"p10","d.name":"p0"} +{"a.name":"p10","d.name":"p3"} +{"a.name":"p10","d.name":"p0"} +{"a.name":"p10","d.name":"p3"} +{"a.name":"p10","d.name":"p3"} +{"a.name":"p10","d.name":"p6"} +{"a.name":"p11","d.name":"p14"} +{"a.name":"p11","d.name":"p1"} +{"a.name":"p11","d.name":"p1"} +{"a.name":"p11","d.name":"p4"} +{"a.name":"p11","d.name":"p1"} +{"a.name":"p11","d.name":"p4"} +{"a.name":"p11","d.name":"p4"} +{"a.name":"p11","d.name":"p7"} +{"a.name":"p12","d.name":"p15"} +{"a.name":"p12","d.name":"p2"} +{"a.name":"p12","d.name":"p2"} +{"a.name":"p12","d.name":"p5"} +{"a.name":"p12","d.name":"p2"} +{"a.name":"p12","d.name":"p5"} +{"a.name":"p12","d.name":"p5"} +{"a.name":"p12","d.name":"p8"} +{"a.name":"p13","d.name":"p0"} +{"a.name":"p13","d.name":"p3"} +{"a.name":"p13","d.name":"p3"} +{"a.name":"p13","d.name":"p6"} +{"a.name":"p13","d.name":"p3"} +{"a.name":"p13","d.name":"p6"} +{"a.name":"p13","d.name":"p6"} +{"a.name":"p13","d.name":"p9"} +{"a.name":"p14","d.name":"p1"} +{"a.name":"p14","d.name":"p4"} +{"a.name":"p14","d.name":"p4"} +{"a.name":"p14","d.name":"p7"} +{"a.name":"p14","d.name":"p4"} +{"a.name":"p14","d.name":"p7"} +{"a.name":"p14","d.name":"p7"} +{"a.name":"p14","d.name":"p10"} +{"a.name":"p15","d.name":"p2"} +{"a.name":"p15","d.name":"p5"} +{"a.name":"p15","d.name":"p5"} +{"a.name":"p15","d.name":"p8"} +{"a.name":"p15","d.name":"p5"} +{"a.name":"p15","d.name":"p8"} +{"a.name":"p15","d.name":"p8"} +{"a.name":"p15","d.name":"p11"} +--- expect shape +a.name: String +d.name: String + +--- restart + +--- query +query hop3() { + match { + $a: Person + $b: Person + $c: Person + $d: Person + $a knows $b + $b knows $c + $c knows $d + } + return { $a.name, $d.name } +} +--- expect unordered +{"a.name":"p0","d.name":"p3"} +{"a.name":"p0","d.name":"p6"} +{"a.name":"p0","d.name":"p6"} +{"a.name":"p0","d.name":"p9"} +{"a.name":"p0","d.name":"p6"} +{"a.name":"p0","d.name":"p9"} +{"a.name":"p0","d.name":"p9"} +{"a.name":"p0","d.name":"p12"} +{"a.name":"p1","d.name":"p4"} +{"a.name":"p1","d.name":"p7"} +{"a.name":"p1","d.name":"p7"} +{"a.name":"p1","d.name":"p10"} +{"a.name":"p1","d.name":"p7"} +{"a.name":"p1","d.name":"p10"} +{"a.name":"p1","d.name":"p10"} +{"a.name":"p1","d.name":"p13"} +{"a.name":"p2","d.name":"p5"} +{"a.name":"p2","d.name":"p8"} +{"a.name":"p2","d.name":"p8"} +{"a.name":"p2","d.name":"p11"} +{"a.name":"p2","d.name":"p8"} +{"a.name":"p2","d.name":"p11"} +{"a.name":"p2","d.name":"p11"} +{"a.name":"p2","d.name":"p14"} +{"a.name":"p3","d.name":"p6"} +{"a.name":"p3","d.name":"p9"} +{"a.name":"p3","d.name":"p9"} +{"a.name":"p3","d.name":"p12"} +{"a.name":"p3","d.name":"p9"} +{"a.name":"p3","d.name":"p12"} +{"a.name":"p3","d.name":"p12"} +{"a.name":"p3","d.name":"p15"} +{"a.name":"p4","d.name":"p7"} +{"a.name":"p4","d.name":"p10"} +{"a.name":"p4","d.name":"p10"} +{"a.name":"p4","d.name":"p13"} +{"a.name":"p4","d.name":"p10"} +{"a.name":"p4","d.name":"p13"} +{"a.name":"p4","d.name":"p13"} +{"a.name":"p4","d.name":"p0"} +{"a.name":"p5","d.name":"p8"} +{"a.name":"p5","d.name":"p11"} +{"a.name":"p5","d.name":"p11"} +{"a.name":"p5","d.name":"p14"} +{"a.name":"p5","d.name":"p11"} +{"a.name":"p5","d.name":"p14"} +{"a.name":"p5","d.name":"p14"} +{"a.name":"p5","d.name":"p1"} +{"a.name":"p6","d.name":"p9"} +{"a.name":"p6","d.name":"p12"} +{"a.name":"p6","d.name":"p12"} +{"a.name":"p6","d.name":"p15"} +{"a.name":"p6","d.name":"p12"} +{"a.name":"p6","d.name":"p15"} +{"a.name":"p6","d.name":"p15"} +{"a.name":"p6","d.name":"p2"} +{"a.name":"p7","d.name":"p10"} +{"a.name":"p7","d.name":"p13"} +{"a.name":"p7","d.name":"p13"} +{"a.name":"p7","d.name":"p0"} +{"a.name":"p7","d.name":"p13"} +{"a.name":"p7","d.name":"p0"} +{"a.name":"p7","d.name":"p0"} +{"a.name":"p7","d.name":"p3"} +{"a.name":"p8","d.name":"p11"} +{"a.name":"p8","d.name":"p14"} +{"a.name":"p8","d.name":"p14"} +{"a.name":"p8","d.name":"p1"} +{"a.name":"p8","d.name":"p14"} +{"a.name":"p8","d.name":"p1"} +{"a.name":"p8","d.name":"p1"} +{"a.name":"p8","d.name":"p4"} +{"a.name":"p9","d.name":"p12"} +{"a.name":"p9","d.name":"p15"} +{"a.name":"p9","d.name":"p15"} +{"a.name":"p9","d.name":"p2"} +{"a.name":"p9","d.name":"p15"} +{"a.name":"p9","d.name":"p2"} +{"a.name":"p9","d.name":"p2"} +{"a.name":"p9","d.name":"p5"} +{"a.name":"p10","d.name":"p13"} +{"a.name":"p10","d.name":"p0"} +{"a.name":"p10","d.name":"p0"} +{"a.name":"p10","d.name":"p3"} +{"a.name":"p10","d.name":"p0"} +{"a.name":"p10","d.name":"p3"} +{"a.name":"p10","d.name":"p3"} +{"a.name":"p10","d.name":"p6"} +{"a.name":"p11","d.name":"p14"} +{"a.name":"p11","d.name":"p1"} +{"a.name":"p11","d.name":"p1"} +{"a.name":"p11","d.name":"p4"} +{"a.name":"p11","d.name":"p1"} +{"a.name":"p11","d.name":"p4"} +{"a.name":"p11","d.name":"p4"} +{"a.name":"p11","d.name":"p7"} +{"a.name":"p12","d.name":"p15"} +{"a.name":"p12","d.name":"p2"} +{"a.name":"p12","d.name":"p2"} +{"a.name":"p12","d.name":"p5"} +{"a.name":"p12","d.name":"p2"} +{"a.name":"p12","d.name":"p5"} +{"a.name":"p12","d.name":"p5"} +{"a.name":"p12","d.name":"p8"} +{"a.name":"p13","d.name":"p0"} +{"a.name":"p13","d.name":"p3"} +{"a.name":"p13","d.name":"p3"} +{"a.name":"p13","d.name":"p6"} +{"a.name":"p13","d.name":"p3"} +{"a.name":"p13","d.name":"p6"} +{"a.name":"p13","d.name":"p6"} +{"a.name":"p13","d.name":"p9"} +{"a.name":"p14","d.name":"p1"} +{"a.name":"p14","d.name":"p4"} +{"a.name":"p14","d.name":"p4"} +{"a.name":"p14","d.name":"p7"} +{"a.name":"p14","d.name":"p4"} +{"a.name":"p14","d.name":"p7"} +{"a.name":"p14","d.name":"p7"} +{"a.name":"p14","d.name":"p10"} +{"a.name":"p15","d.name":"p2"} +{"a.name":"p15","d.name":"p5"} +{"a.name":"p15","d.name":"p5"} +{"a.name":"p15","d.name":"p8"} +{"a.name":"p15","d.name":"p5"} +{"a.name":"p15","d.name":"p8"} +{"a.name":"p15","d.name":"p8"} +{"a.name":"p15","d.name":"p11"} +--- expect shape +a.name: String +d.name: String diff --git a/benchmarks/workloads/e2e_traversal_selective_csr.gqt b/benchmarks/workloads/e2e_traversal_selective_csr.gqt new file mode 100644 index 000000000..baf43d95e --- /dev/null +++ b/benchmarks/workloads/e2e_traversal_selective_csr.gqt @@ -0,0 +1,49 @@ +# issue: none +# notes: One query is measured on a fresh handle with prepared traversal indexes; a restart and exact result check follow. This bounded topology and preparation differ from the former Rust timing loop. +# traversal: csr + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query sel($name: String) { + match { + $a: Person { name: $name } + $a knows{1,2} $b + } + return { $b.name } +} +--- params +{"name":"p0"} +--- expect unordered +{"b.name":"p1"} +{"b.name":"p2"} +{"b.name":"p4"} +{"b.name":"p5"} +{"b.name":"p8"} +--- expect shape +b.name: String + +--- restart + +--- query +query sel($name: String) { + match { + $a: Person { name: $name } + $a knows{1,2} $b + } + return { $b.name } +} +--- params +{"name":"p0"} +--- expect unordered +{"b.name":"p1"} +{"b.name":"p2"} +{"b.name":"p4"} +{"b.name":"p5"} +{"b.name":"p8"} +--- expect shape +b.name: String diff --git a/benchmarks/workloads/e2e_traversal_selective_indexed.gqt b/benchmarks/workloads/e2e_traversal_selective_indexed.gqt new file mode 100644 index 000000000..547b69d25 --- /dev/null +++ b/benchmarks/workloads/e2e_traversal_selective_indexed.gqt @@ -0,0 +1,49 @@ +# issue: none +# notes: One query is measured on a fresh handle with prepared traversal indexes; a restart and exact result check follow. This bounded topology and preparation differ from the former Rust timing loop. +# traversal: indexed + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query sel($name: String) { + match { + $a: Person { name: $name } + $a knows{1,2} $b + } + return { $b.name } +} +--- params +{"name":"p0"} +--- expect unordered +{"b.name":"p1"} +{"b.name":"p2"} +{"b.name":"p4"} +{"b.name":"p5"} +{"b.name":"p8"} +--- expect shape +b.name: String + +--- restart + +--- query +query sel($name: String) { + match { + $a: Person { name: $name } + $a knows{1,2} $b + } + return { $b.name } +} +--- params +{"name":"p0"} +--- expect unordered +{"b.name":"p1"} +{"b.name":"p2"} +{"b.name":"p4"} +{"b.name":"p5"} +{"b.name":"p8"} +--- expect shape +b.name: String diff --git a/benchmarks/workloads/equal_current_different_history.gqt b/benchmarks/workloads/equal_current_different_history.gqt new file mode 100644 index 000000000..bffa6a6f9 --- /dev/null +++ b/benchmarks/workloads/equal_current_different_history.gqt @@ -0,0 +1,46 @@ +# issue: none +# notes: Exact equal current rows after different past payload/batch recipes; historical row images and compaction are not asserted. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"row-0","value":0,"payload":"final"} +{"key":"row-1","value":0,"payload":"final"} +{"key":"row-2","value":0,"payload":"final"} +{"key":"row-3","value":0,"payload":"final"} +--- expect shape +key: String +value: I64 +payload: String + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"row-0","value":0,"payload":"final"} +{"key":"row-1","value":0,"payload":"final"} +{"key":"row-2","value":0,"payload":"final"} +{"key":"row-3","value":0,"payload":"final"} +--- expect shape +key: String +value: I64 +payload: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"row-0","value":0,"payload":"final"} +{"key":"row-1","value":0,"payload":"final"} +{"key":"row-2","value":0,"payload":"final"} +{"key":"row-3","value":0,"payload":"final"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/workloads/finbench_disjoint_merge.gqt b/benchmarks/workloads/finbench_disjoint_merge.gqt new file mode 100644 index 000000000..f28843f9c --- /dev/null +++ b/benchmarks/workloads/finbench_disjoint_merge.gqt @@ -0,0 +1,195 @@ +# issue: none +# notes: FinBench disjoint inserts; generated transfer IDs use logical-equivalence identity. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch merge "bench-source" into "bench-target" +--- expect outcome: merged + +--- query branch: bench-target +query reserved_accounts() { + match { $a: Account + $a.accountId starts_with "omnigraph-bench-fin-v1-" } + return { $a.accountId as account, $a.createTime as created, $a.isBlocked as blocked, $a.accountType as kind, $a.freqLoginType as login, $a.accountLevel as level, $a.nickname as nickname, $a.phonenum as phonenum, $a.email as email, $a.lastLoginTime as last_login } +} +--- expect unordered +{"account":"omnigraph-bench-fin-v1-src-a","created":"2020-01-01T00:00:00","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +{"account":"omnigraph-bench-fin-v1-src-b","created":"2020-01-01T00:00:00","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +{"account":"omnigraph-bench-fin-v1-tgt-a","created":"2020-01-01T00:00:01","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +{"account":"omnigraph-bench-fin-v1-tgt-b","created":"2020-01-01T00:00:01","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +--- expect shape +account: String +created: DateTime +blocked: Bool +kind: String +login: String +level: String +nickname: String? +phonenum: String? +email: String? +last_login: DateTime? + +--- query branch: bench-target +query reserved_transfers() { + match { $a: Account + $a $e:accounttransferaccount $b + $e.orderNum starts_with "omnigraph-bench-fin-v1-" } + return { $e.@src as src, $e.@dst as dst, $e.amount as amount, $e.createTime as created, $e.orderNum as order_num, $e.payType as pay, $e.goodsType as goods, $e.comment as comment } +} +--- expect unordered +{"src":"omnigraph-bench-fin-v1-src-a","dst":"omnigraph-bench-fin-v1-src-b","amount":1.25,"created":"2020-01-01T00:00:00","order_num":"omnigraph-bench-fin-v1-src-order","pay":"bank_transfer","goods":"bank_transfer"} +{"src":"omnigraph-bench-fin-v1-tgt-a","dst":"omnigraph-bench-fin-v1-tgt-b","amount":2.5,"created":"2020-01-01T00:00:01","order_num":"omnigraph-bench-fin-v1-tgt-order","pay":"bank_transfer","goods":"bank_transfer"} +--- expect shape +src: String +dst: String +amount: F64 +created: DateTime +order_num: String +pay: String +goods: String +comment: String? + +--- query branch: bench-target +query account_count() { + match { $a: Account } + return { count($a) as n } +} +--- expect unordered +{"n":1534184} +--- expect shape +n: I64 + +--- query branch: bench-target +query transfer_count() { + match { $a: Account + $a $e:accounttransferaccount $b } + return { count($e) as n } +} +--- expect unordered +{"n":6219883} +--- expect shape +n: I64 + +--- query branch: bench-source +query reserved_accounts() { + match { $a: Account + $a.accountId starts_with "omnigraph-bench-fin-v1-" } + return { $a.accountId as account, $a.createTime as created, $a.isBlocked as blocked, $a.accountType as kind, $a.freqLoginType as login, $a.accountLevel as level, $a.nickname as nickname, $a.phonenum as phonenum, $a.email as email, $a.lastLoginTime as last_login } +} +--- expect unordered +{"account":"omnigraph-bench-fin-v1-src-a","created":"2020-01-01T00:00:00","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +{"account":"omnigraph-bench-fin-v1-src-b","created":"2020-01-01T00:00:00","blocked":false,"kind":"internet_account","login":"ipv4","level":"basic"} +--- expect shape +account: String +created: DateTime +blocked: Bool +kind: String +login: String +level: String +nickname: String? +phonenum: String? +email: String? +last_login: DateTime? + +--- query branch: bench-source +query reserved_transfers() { + match { $a: Account + $a $e:accounttransferaccount $b + $e.orderNum starts_with "omnigraph-bench-fin-v1-" } + return { $e.@src as src, $e.@dst as dst, $e.amount as amount, $e.createTime as created, $e.orderNum as order_num, $e.payType as pay, $e.goodsType as goods, $e.comment as comment } +} +--- expect unordered +{"src":"omnigraph-bench-fin-v1-src-a","dst":"omnigraph-bench-fin-v1-src-b","amount":1.25,"created":"2020-01-01T00:00:00","order_num":"omnigraph-bench-fin-v1-src-order","pay":"bank_transfer","goods":"bank_transfer"} +--- expect shape +src: String +dst: String +amount: F64 +created: DateTime +order_num: String +pay: String +goods: String +comment: String? + +--- query branch: bench-source +query account_count() { + match { $a: Account } + return { count($a) as n } +} +--- expect unordered +{"n":1534182} +--- expect shape +n: I64 + +--- query branch: bench-source +query transfer_count() { + match { $a: Account + $a $e:accounttransferaccount $b } + return { count($e) as n } +} +--- expect unordered +{"n":6219882} +--- expect shape +n: I64 + +--- query branch: main +query reserved_accounts() { + match { $a: Account + $a.accountId starts_with "omnigraph-bench-fin-v1-" } + return { $a.accountId as account, $a.createTime as created, $a.isBlocked as blocked, $a.accountType as kind, $a.freqLoginType as login, $a.accountLevel as level, $a.nickname as nickname, $a.phonenum as phonenum, $a.email as email, $a.lastLoginTime as last_login } +} +--- expect unordered +--- expect shape +account: String +created: DateTime +blocked: Bool +kind: String +login: String +level: String +nickname: String? +phonenum: String? +email: String? +last_login: DateTime? + +--- query branch: main +query reserved_transfers() { + match { $a: Account + $a $e:accounttransferaccount $b + $e.orderNum starts_with "omnigraph-bench-fin-v1-" } + return { $e.@src as src, $e.@dst as dst, $e.amount as amount, $e.createTime as created, $e.orderNum as order_num, $e.payType as pay, $e.goodsType as goods, $e.comment as comment } +} +--- expect unordered +--- expect shape +src: String +dst: String +amount: F64 +created: DateTime +order_num: String +pay: String +goods: String +comment: String? + +--- query branch: main +query account_count() { + match { $a: Account } + return { count($a) as n } +} +--- expect unordered +{"n":1534180} +--- expect shape +n: I64 + +--- query branch: main +query transfer_count() { + match { $a: Account + $a $e:accounttransferaccount $b } + return { count($e) as n } +} +--- expect unordered +{"n":6219881} +--- expect shape +n: I64 diff --git a/benchmarks/workloads/hot_table_idle_base.gqt b/benchmarks/workloads/hot_table_idle_base.gqt new file mode 100644 index 000000000..e49be850d --- /dev/null +++ b/benchmarks/workloads/hot_table_idle_base.gqt @@ -0,0 +1,44 @@ +# issue: none +# notes: One hot-table update; all idle current views remain exact. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query hot_write() { update Hot set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":1} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":1} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String diff --git a/benchmarks/workloads/hot_table_idle_branches_4.gqt b/benchmarks/workloads/hot_table_idle_branches_4.gqt new file mode 100644 index 000000000..efa7b622d --- /dev/null +++ b/benchmarks/workloads/hot_table_idle_branches_4.gqt @@ -0,0 +1,116 @@ +# issue: none +# notes: One hot-table update; all idle current views remain exact. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query hot_write() { update Hot set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: idle0 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle1 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle2 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle3 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"idle0"} +{"name":"idle1"} +{"name":"idle2"} +{"name":"idle3"} +--- expect shape +name: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: idle0 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle1 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle2 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle3 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"idle0"} +{"name":"idle1"} +{"name":"idle2"} +{"name":"idle3"} +--- expect shape +name: String diff --git a/benchmarks/workloads/hot_table_idle_branches_4_aged.gqt b/benchmarks/workloads/hot_table_idle_branches_4_aged.gqt new file mode 100644 index 000000000..efa7b622d --- /dev/null +++ b/benchmarks/workloads/hot_table_idle_branches_4_aged.gqt @@ -0,0 +1,116 @@ +# issue: none +# notes: One hot-table update; all idle current views remain exact. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query hot_write() { update Hot set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: idle0 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle1 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle2 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle3 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"idle0"} +{"name":"idle1"} +{"name":"idle2"} +{"name":"idle3"} +--- expect shape +name: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: idle0 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle1 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle2 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: idle3 +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"idle0"} +{"name":"idle1"} +{"name":"idle2"} +{"name":"idle3"} +--- expect shape +name: String diff --git a/benchmarks/workloads/hot_table_idle_tables_4.gqt b/benchmarks/workloads/hot_table_idle_tables_4.gqt new file mode 100644 index 000000000..eb6d9d212 --- /dev/null +++ b/benchmarks/workloads/hot_table_idle_tables_4.gqt @@ -0,0 +1,108 @@ +# issue: none +# notes: One hot-table update; all idle current views remain exact. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query hot_write() { update Hot set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: Hot } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"hot","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Idle3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"sentinel","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String diff --git a/benchmarks/workloads/identity_lifecycle.gqt b/benchmarks/workloads/identity_lifecycle.gqt new file mode 100644 index 000000000..ef3773bd1 --- /dev/null +++ b/benchmarks/workloads/identity_lifecycle.gqt @@ -0,0 +1,86 @@ +# issue: none +# notes: First write on recreated feature; exact main and retained old-child isolation before/after reopen. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate branch: feature +query new_lifetime_write() { update Item set { value: 1 } where key = "alice" } +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"alice","value":0} +{"key":"new_main","value":20} +--- expect shape +key: String +value: I64 + +--- query branch: feature +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"alice","value":1} +{"key":"new_main","value":20} +--- expect shape +key: String +value: I64 + +--- query branch: old_child +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"alice","value":0} +{"key":"old_only","value":10} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"feature"} +{"name":"old_child"} +--- expect shape +name: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"alice","value":0} +{"key":"new_main","value":20} +--- expect shape +key: String +value: I64 + +--- query branch: feature +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"alice","value":1} +{"key":"new_main","value":20} +--- expect shape +key: String +value: I64 + +--- query branch: old_child +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"alice","value":0} +{"key":"old_only","value":10} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"feature"} +{"name":"old_child"} +--- expect shape +name: String diff --git a/benchmarks/workloads/nearest_ranks_updated_embedding.gqt b/benchmarks/workloads/nearest_ranks_updated_embedding.gqt new file mode 100644 index 000000000..2bb3266ca --- /dev/null +++ b/benchmarks/workloads/nearest_ranks_updated_embedding.gqt @@ -0,0 +1,50 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query nearest_after_update($q: Vector(4)) { + match { $d: Doc } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 6 +} + +--- params +{"q": [-0.3, 0.0, 0.0, 0.0]} + +--- expect ordered +{"d.slug":"d000"} +{"d.slug":"d004"} +{"d.slug":"d001"} +{"d.slug":"d002"} +{"d.slug":"d003"} + +--- expect shape +d.slug: String + +--- query +query nearest_after_update($q: Vector(4)) { + match { $d: Doc } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 6 +} + +--- params +{"q": [-0.3, 0.0, 0.0, 0.0]} + +--- expect ordered +{"d.slug":"d000"} +{"d.slug":"d004"} +{"d.slug":"d001"} +{"d.slug":"d002"} +{"d.slug":"d003"} + +--- expect shape +d.slug: String diff --git a/benchmarks/workloads/nearest_skips_deleted_rows_and_fills_limit.gqt b/benchmarks/workloads/nearest_skips_deleted_rows_and_fills_limit.gqt new file mode 100644 index 000000000..8233d9399 --- /dev/null +++ b/benchmarks/workloads/nearest_skips_deleted_rows_and_fills_limit.gqt @@ -0,0 +1,46 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query +query nearest_after_delete($q: Vector(4)) { + match { $d: Doc } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 +} + +--- params +{"q": [-0.3, 0.0, 0.0, 0.0]} + +--- expect ordered +{"d.slug":"d003"} +{"d.slug":"d004"} +{"d.slug":"d005"} + +--- expect shape +d.slug: String + +--- query +query nearest_after_delete($q: Vector(4)) { + match { $d: Doc } + return { $d.slug } + order { nearest($d.embedding, $q) } + limit 3 +} + +--- params +{"q": [-0.3, 0.0, 0.0, 0.0]} + +--- expect ordered +{"d.slug":"d003"} +{"d.slug":"d004"} +{"d.slug":"d005"} + +--- expect shape +d.slug: String diff --git a/benchmarks/workloads/parallel_tables_1.gqt b/benchmarks/workloads/parallel_tables_1.gqt new file mode 100644 index 000000000..df5c84a1c --- /dev/null +++ b/benchmarks/workloads/parallel_tables_1.gqt @@ -0,0 +1,80 @@ +# issue: none +# notes: One mutation changes 1 tables; exact touched and untouched rows. No actor-overlap claim. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query update_tables() { + update T0 set { value: 1 } where key = "row" +} +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query current_rows() { match { $r: T0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- restart + +--- query branch: main +query current_rows() { match { $r: T0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 diff --git a/benchmarks/workloads/parallel_tables_2.gqt b/benchmarks/workloads/parallel_tables_2.gqt new file mode 100644 index 000000000..d5e1fdc05 --- /dev/null +++ b/benchmarks/workloads/parallel_tables_2.gqt @@ -0,0 +1,81 @@ +# issue: none +# notes: One mutation changes 2 tables; exact touched and untouched rows. No actor-overlap claim. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query update_tables() { + update T0 set { value: 1 } where key = "row" + update T1 set { value: 1 } where key = "row" +} +--- expect affected: nodes=2 edges=0 + +--- query branch: main +query current_rows() { match { $r: T0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- restart + +--- query branch: main +query current_rows() { match { $r: T0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":0} +--- expect shape +key: String +value: I64 diff --git a/benchmarks/workloads/parallel_tables_4.gqt b/benchmarks/workloads/parallel_tables_4.gqt new file mode 100644 index 000000000..bc2562219 --- /dev/null +++ b/benchmarks/workloads/parallel_tables_4.gqt @@ -0,0 +1,83 @@ +# issue: none +# notes: One mutation changes 4 tables; exact touched and untouched rows. No actor-overlap claim. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query update_tables() { + update T0 set { value: 1 } where key = "row" + update T1 set { value: 1 } where key = "row" + update T2 set { value: 1 } where key = "row" + update T3 set { value: 1 } where key = "row" +} +--- expect affected: nodes=4 edges=0 + +--- query branch: main +query current_rows() { match { $r: T0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- restart + +--- query branch: main +query current_rows() { match { $r: T0 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T1 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T2 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: T3 } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"row","value":1} +--- expect shape +key: String +value: I64 diff --git a/benchmarks/workloads/repeated_deletion_recreation_branches.gqt b/benchmarks/workloads/repeated_deletion_recreation_branches.gqt new file mode 100644 index 000000000..8b5b02859 --- /dev/null +++ b/benchmarks/workloads/repeated_deletion_recreation_branches.gqt @@ -0,0 +1,62 @@ +# issue: none +# notes: Final recreation after bounded prior cycles; exact live rows/registry after reopen. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch create "recycled" from main +--- expect ok + +--- query branch: recycled +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"recycled"} +--- expect shape +name: String + +--- restart + +--- query branch: recycled +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +--- expect shape +key: String +value: I64 + +--- query branch: main +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +{"name":"recycled"} +--- expect shape +name: String diff --git a/benchmarks/workloads/repeated_deletion_recreation_rows.gqt b/benchmarks/workloads/repeated_deletion_recreation_rows.gqt new file mode 100644 index 000000000..47db65a9e --- /dev/null +++ b/benchmarks/workloads/repeated_deletion_recreation_rows.gqt @@ -0,0 +1,46 @@ +# issue: none +# notes: Final recreation after bounded prior cycles; exact live rows/registry after reopen. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query recreate_row() { insert Item { key: "temporary", value: 99 } } +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +{"key":"temporary","value":99} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: Item } return { $r.key as key, $r.value as value } } +--- expect unordered +{"key":"baseline","value":0} +{"key":"temporary","value":99} +--- expect shape +key: String +value: I64 + +--- query +branch list +--- expect unordered +{"name":"main"} +--- expect shape +name: String diff --git a/benchmarks/workloads/threshold_crossings_after.gqt b/benchmarks/workloads/threshold_crossings_after.gqt new file mode 100644 index 000000000..362d26635 --- /dev/null +++ b/benchmarks/workloads/threshold_crossings_after.gqt @@ -0,0 +1,56 @@ +# issue: none +# notes: Selected insert at a configured history-release boundary shape; no optimize/index/cache threshold is assumed. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +set history_release_bytes = 2048; +--- expect ok + +--- mutate branch: b +query next_publish() { insert Person { name: "carol", age: 1 } } +--- expect affected: nodes=1 edges=0 + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":4} +{"name":"bob","age":0} +{"name":"carol","age":1} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 + +--- restart + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":4} +{"name":"bob","age":0} +{"name":"carol","age":1} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 diff --git a/benchmarks/workloads/threshold_crossings_at.gqt b/benchmarks/workloads/threshold_crossings_at.gqt new file mode 100644 index 000000000..9076fc7fb --- /dev/null +++ b/benchmarks/workloads/threshold_crossings_at.gqt @@ -0,0 +1,56 @@ +# issue: none +# notes: Selected insert at a configured history-release boundary shape; no optimize/index/cache threshold is assumed. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +set history_release_bytes = 2048; +--- expect ok + +--- mutate branch: b +query next_publish() { insert Person { name: "carol", age: 1 } } +--- expect affected: nodes=1 edges=0 + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":3} +{"name":"bob","age":0} +{"name":"carol","age":1} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 + +--- restart + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":3} +{"name":"bob","age":0} +{"name":"carol","age":1} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 diff --git a/benchmarks/workloads/threshold_crossings_before.gqt b/benchmarks/workloads/threshold_crossings_before.gqt new file mode 100644 index 000000000..a19755779 --- /dev/null +++ b/benchmarks/workloads/threshold_crossings_before.gqt @@ -0,0 +1,56 @@ +# issue: none +# notes: Selected insert at a configured history-release boundary shape; no optimize/index/cache threshold is assumed. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +set history_release_bytes = 2048; +--- expect ok + +--- mutate branch: b +query next_publish() { insert Person { name: "carol", age: 1 } } +--- expect affected: nodes=1 edges=0 + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":2} +{"name":"bob","age":0} +{"name":"carol","age":1} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 + +--- restart + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":2} +{"name":"bob","age":0} +{"name":"carol","age":1} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 diff --git a/benchmarks/workloads/threshold_crossings_production_control.gqt b/benchmarks/workloads/threshold_crossings_production_control.gqt new file mode 100644 index 000000000..c8d4ea881 --- /dev/null +++ b/benchmarks/workloads/threshold_crossings_production_control.gqt @@ -0,0 +1,56 @@ +# issue: none +# notes: Selected insert at a configured history-release boundary shape; no optimize/index/cache threshold is assumed. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +set history_release_bytes = 262144; +--- expect ok + +--- mutate branch: b +query next_publish() { insert Person { name: "carol", age: 1 } } +--- expect affected: nodes=1 edges=0 + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":3} +{"name":"bob","age":0} +{"name":"carol","age":1} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 + +--- restart + +--- query branch: b +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":3} +{"name":"bob","age":0} +{"name":"carol","age":1} +--- expect shape +name: String +age: I32 + +--- query branch: main +query current_rows() { match { $r: Person } return { $r.name as name, $r.age as age } } +--- expect unordered +{"name":"alice","age":0} +{"name":"bob","age":0} +--- expect shape +name: String +age: I32 diff --git a/benchmarks/workloads/tiny_branch.gqt b/benchmarks/workloads/tiny_branch.gqt new file mode 100644 index 000000000..19e7a5dca --- /dev/null +++ b/benchmarks/workloads/tiny_branch.gqt @@ -0,0 +1,24 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +branch create "child" from main +--- expect ok + +--- query branch: child +query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } +} +--- expect unordered +{"key":"a","val":1} +{"key":"b","val":2} +--- expect shape +key: String +val: I64 diff --git a/benchmarks/workloads/tiny_load.gqt b/benchmarks/workloads/tiny_load.gqt new file mode 100644 index 000000000..e1d411972 --- /dev/null +++ b/benchmarks/workloads/tiny_load.gqt @@ -0,0 +1,33 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- load generate: v1 seed: 0 mode: append +tables: + - kind: node + name: Item + rows: 1 + commits: 1 + batch_rows: 1 + columns: + key: {kind: key, prefix: c, width: 1} + val: {kind: literal, value: 3} +--- expect ok + +--- query branch: main +query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } +} +--- expect unordered +{"key":"a","val":1} +{"key":"b","val":2} +{"key":"c0","val":3} +--- expect shape +key: String +val: I64 diff --git a/benchmarks/workloads/tiny_mutate.gqt b/benchmarks/workloads/tiny_mutate.gqt new file mode 100644 index 000000000..a17302837 --- /dev/null +++ b/benchmarks/workloads/tiny_mutate.gqt @@ -0,0 +1,25 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query add() { insert Item { key: "c", val: 3 } } +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } +} +--- expect unordered +{"key":"a","val":1} +{"key":"b","val":2} +{"key":"c","val":3} +--- expect shape +key: String +val: I64 diff --git a/benchmarks/workloads/tiny_post_reopen.gqt b/benchmarks/workloads/tiny_post_reopen.gqt new file mode 100644 index 000000000..236ee3f7e --- /dev/null +++ b/benchmarks/workloads/tiny_post_reopen.gqt @@ -0,0 +1,46 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query branch: main +query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } +} +--- expect unordered +{"key":"a","val":1} +{"key":"b","val":2} +--- expect shape +key: String +val: I64 + +--- restart + +--- query branch: main +query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } +} +--- expect unordered +{"key":"a","val":1} +{"key":"b","val":2} +--- expect shape +key: String +val: I64 + +--- query branch: main +query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } +} +--- expect unordered +{"key":"a","val":1} +{"key":"b","val":2} +--- expect shape +key: String +val: I64 diff --git a/benchmarks/workloads/tiny_read.gqt b/benchmarks/workloads/tiny_read.gqt new file mode 100644 index 000000000..384daf8bf --- /dev/null +++ b/benchmarks/workloads/tiny_read.gqt @@ -0,0 +1,32 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query branch: main +query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } +} +--- expect unordered +{"key":"a","val":1} +{"key":"b","val":2} +--- expect shape +key: String +val: I64 + +--- query branch: main +query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } +} +--- expect unordered +{"key":"a","val":1} +{"key":"b","val":2} +--- expect shape +key: String +val: I64 diff --git a/benchmarks/workloads/tiny_restart.gqt b/benchmarks/workloads/tiny_restart.gqt new file mode 100644 index 000000000..9067e90ed --- /dev/null +++ b/benchmarks/workloads/tiny_restart.gqt @@ -0,0 +1,22 @@ +# issue: none +# notes: Shared benchmark dataset/query contract. + +--- runner +timeout_ms: 600000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- restart + +--- query branch: main +query items() { + match { $i: Item } + return { $i.key as key, $i.val as val } +} +--- expect unordered +{"key":"a","val":1} +{"key":"b","val":2} +--- expect shape +key: String +val: I64 diff --git a/benchmarks/workloads/very_long_history_read.gqt b/benchmarks/workloads/very_long_history_read.gqt new file mode 100644 index 000000000..aef311a8b --- /dev/null +++ b/benchmarks/workloads/very_long_history_read.gqt @@ -0,0 +1,37 @@ +# issue: none +# notes: Fixed-live-data history checkpoint; selected read is separate from verification. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":0,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":0,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":0,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/workloads/very_long_history_reopen.gqt b/benchmarks/workloads/very_long_history_reopen.gqt new file mode 100644 index 000000000..9781d2d01 --- /dev/null +++ b/benchmarks/workloads/very_long_history_reopen.gqt @@ -0,0 +1,30 @@ +# issue: none +# notes: Fixed-live-data history checkpoint; selected reopen is separate from verification. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- restart + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":0,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":0,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/benchmarks/workloads/very_long_history_write.gqt b/benchmarks/workloads/very_long_history_write.gqt new file mode 100644 index 000000000..7ec828260 --- /dev/null +++ b/benchmarks/workloads/very_long_history_write.gqt @@ -0,0 +1,32 @@ +# issue: none +# notes: Fixed-live-data history checkpoint; selected write is separate from verification. + +--- runner +timeout_ms: 60000 +environments: + - target: omnigraph-engine + storage: local-filesystem + +--- mutate +query next_write() { update HistoryRow set { value: 1 } where key = "hot" } +--- expect affected: nodes=1 edges=0 + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":1,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String + +--- restart + +--- query branch: main +query current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } } +--- expect unordered +{"key":"hot","value":1,"payload":"fixed"} +--- expect shape +key: String +value: I64 +payload: String diff --git a/changelog.d/gqt-benchmark-scenarios.changed.md b/changelog.d/gqt-benchmark-scenarios.changed.md new file mode 100644 index 000000000..6da8939cc --- /dev/null +++ b/changelog.d/gqt-benchmark-scenarios.changed.md @@ -0,0 +1,32 @@ +- Benchmark cases now use `gqt-v1` dataset/query pairs with an ordinal and exact + operation echo. The release harness builds a persistent verified dataset cache, + derives cache treatment from preparation reads/reopen, and measures one selected + engine operation before GQT expectations and verification. Named scenario groups, + raw `dataset build`/`dataset validate`, and explicit dataset/query invocations + share the same worker and archive pipeline. Registered FinBench and D50 cases + use GQT; the old authored `branch-merge-v1` runner and `fixture run-graph` command + are retired. Historical run records preserve their canonical bytes and remain + queryable beside typed GQT records. New logical identities and warm-up programs + do not claim identical points or comparable timings to the retired recipes. +- The GQT catalog adds bounded history, idle-table/branch, multi-table mutation, + branch-name reuse, separate row/branch churn, configured history-release, and + equal-current/different-history pairs with exact post-operation and restart + checks. Explicit 1,000/10,000/100,000-update history recipes remain opt-in and + do not imply completed scale or performance measurements. +- Registered dataset identity preserves exact floating-point values associated + with exported IDs. Cache quarantine markers refuse symlinks without following + them. Acquisition rejects receipt budgets that cannot fit the archive before + dataset work, and recording errors retain one completed prefix alongside the + failed repetition's diagnostics. +- The benchmark catalog now separates `fixtures/` from `workloads/` and uses + one `benchmarks.yaml`. Run a scenario by name or pass custom YAML with + `--config`. `list`, `show`, read-only `cache status`/`cache list`, `init` and + human/JSON help make inputs, operation selectors and cache state discoverable. + Legacy case/suite readers and historical records remain supported. +- The catalog adds 33 bounded end-to-end merge, load, branch, search, query and + traversal scenarios with exact results and reopened verification. Former Rust + benchmark entry points are retired. Unsupported maintenance, concurrency, + HTTP, history/physical-observation and scale instruments are preserved under + `benchmarks/deferred/`, outside Cargo discovery. Cleanup and optimization await + GQ support; no separate GQT maintenance commands are added. New bounded + scenarios have distinct experiment identities and timing series. diff --git a/changelog.d/gqt-external-store.added.md b/changelog.d/gqt-external-store.added.md new file mode 100644 index 000000000..2488a365f --- /dev/null +++ b/changelog.d/gqt-external-store.added.md @@ -0,0 +1,7 @@ +- GQT files can omit schema and seed together and run against an existing + local, S3-compatible or Azure store with `omnigraph-gqt --store `; + dataset-only files may have zero steps. External-store reports cannot replay, + and `--measure` requires a selected DST environment. See the + [GQT runner guide][gqt-existing-store]. + +[gqt-existing-store]: ../crates/omnigraph-gqt/README.md#explicit-execution diff --git a/changelog.d/gqt-generated-fixtures.added.md b/changelog.d/gqt-generated-fixtures.added.md new file mode 100644 index 000000000..18c3489d7 --- /dev/null +++ b/changelog.d/gqt-generated-fixtures.added.md @@ -0,0 +1,12 @@ +- GQT supports bounded, deterministic `generate: v1` seeds and append or keyed + merge load steps, including explicit commit partitioning, vectors and uniform + or Zipf endpoints. Generated loads share normal branch, restart, expectation + and fault-injection behavior, so benchmark datasets can live in `.gqt` files. +- Generated seeds preserve blank lines in YAML block strings. Shared GQT YAML + admission rejects duplicate mapping keys, aliases, anchors, tags and merge keys + using syntax tokens while preserving literal punctuation in scalar values. + Mapping keys must be strings, so a plain `true` or `1` key is refused instead + of silently merging with its quoted twin; admission errors name the section. + A YAML section body keeps its final line break, so a block scalar ending a + recipe loads the newline the file shows, and `#` lines inside a generated + recipe are YAML text rather than refused comments. diff --git a/crates/omnigraph-bench/Cargo.toml b/crates/omnigraph-bench/Cargo.toml index d57217c42..e27f59856 100644 --- a/crates/omnigraph-bench/Cargo.toml +++ b/crates/omnigraph-bench/Cargo.toml @@ -22,6 +22,7 @@ futures = { workspace = true } lance = { workspace = true } object_store = { workspace = true } omnigraph = { package = "omnigraph-engine", path = "../omnigraph", version = "0.13.0" } +omnigraph-gqt-core = { path = "../omnigraph-gqt-core", version = "0.13.0" } omnigraph-compiler = { path = "../omnigraph-compiler", version = "0.13.0" } serde = { workspace = true } serde_json = { workspace = true } @@ -41,6 +42,7 @@ predicates = "3" tempfile = { workspace = true } [build-dependencies] +sha2 = { workspace = true } toml = "0.9" [lints] diff --git a/crates/omnigraph-bench/README.md b/crates/omnigraph-bench/README.md index b3c3471fd..b8c9426ed 100644 --- a/crates/omnigraph-bench/README.md +++ b/crates/omnigraph-bench/README.md @@ -1,125 +1,135 @@ # OmniGraph benchmark harness -`omnigraph-bench` owns benchmark definitions, planning, execution, durable run -records, and the rebuildable result projection. It parses strict, versioned -YAML case and suite documents, validates their semantics, computes stable -experiment identities, and can execute supported local `branch-merge-v1` -points. Run wall-clock measurements from a clean, flag-free release build only -(the workspace `.cargo/config.toml` sets `--cfg tokio_unstable` for -development builds; the empty `RUSTFLAGS` clears it, and the runner refuses a -build whose build script saw any encoded Rust flags): +`omnigraph-bench run tiny-read` runs a named GQT benchmark in a supervised +release worker. One [`benchmarks.yaml`](../../benchmarks/benchmarks.yaml) +selects fixtures, workloads and run settings. `run --config FILE` accepts the +same format for custom experiments; [custom.example.yaml](../../benchmarks/custom.example.yaml) +is a complete starting point. The measured operation is selected by ordinal +plus exact header/body echo. GQT remains the language for data, +operations, and expectations; it has no benchmark timing or cache labels. +The production parser/executor comes from `omnigraph-gqt-core`, which has no +build script or normal `test-util` requirement. The GQT binary separately owns +correctness/DST execution and never supplies these wall-clock measurements. + +The [catalog guide](../../benchmarks/README.md) contains complete examples. The +[`local-regression` group](../../benchmarks/benchmarks.yaml) +contains bounded history, idle-registration, multi-table, branch-identity, +churn, configured history-release, and equal-current/different-history pairs. +The larger [history recipes](../../benchmarks/README.md#opt-in-history-scale) are opt-in. +For a qualified flag-free release build, the existing build command is +`RUSTFLAGS= cargo build --release --locked -p omnigraph-bench`; this clears the +workspace's development `--cfg tokio_unstable`. Neither that flag nor debug +assertions may remain in a measured worker. Then run a small suite: ```bash -RUSTFLAGS= cargo run --release --locked -p omnigraph-bench -- \ - suite run benchmarks/suites/local-smoke.suite-v1.yaml \ - --archive .bench/archive +target/release/omnigraph-bench run local-fast \ + --dataset-cache /qualified/cache --json ``` -The checked-in catalog and command examples are in -[`../../benchmarks/README.md`](../../benchmarks/README.md). RFC 0039 owns the -measurement protocol and identity vocabulary. - -Synthetic fixtures can optionally execute the versioned -[`reversible-updates-v1` preparation recipe](../../benchmarks/README.md#preparing-additional-write-history) -before branching. It adds verified real write history while restoring all -logical contents, under the existing bounded fixture process and reset -protocol. The recipe is part of case and stamped fixture identity; absent -preparation preserves earlier canonical records and point identifiers. - -## Boundaries - -- A case describes exactly one benchmark point. -- A suite references cases and sets repetition counts. Repetitions acquire more - evidence for a point; they do not change its identity. -- `point_id` is the full SHA-256 of the canonical typed experiment identity. - The readable `point_name` is display text, never a key. -- Process lifecycle, engine preparation, OS page-cache treatment, and the - named warm-up program are separate cache-condition fields in point identity. - Process-cold explicitly leaves the OS page cache uncontrolled. Neither - page-cache-cold nor storage-cold is representable without stronger controls. -- The engine does not depend on this crate. The runner depends on the public - engine surface and consumes the plans produced here. -- Runner-v1 builds one already-diverged fixture at a stable `active` path, - verifies it, closes it, and freezes its complete physical tree by SHA-256. - Public execution performs construction in a dedicated process group under a - bounded watchdog. That child byte-digests the completed tree, makes a - never-opened reset template, and removes `active` before returning an - identity-checked handoff. APFS uses forced clonefile; Linux XFS uses a full - verified copy only for process-fresh points with an uncontrolled page cache. - The parent accepts it only after the direct child - has been reaped and the process group is gone. Any failed, partial, or - panicked fixture build quarantines its disposable workspace instead of - deleting possibly active state. Every repetition restores the template - to that same `active` path, so Lance shallow - branches retain valid absolute base paths and samples do not accumulate - branch, manifest, or deletion history. Clonefile never falls back to copying; - plain-copy reset reads and verifies all bytes outside timing. -- Every repetition runs in a fresh worker process whose executable SHA-256, - source commit/dirty state, Cargo's - release/opt-level observations, compiler-effective debug assertions, the - checked-in release-profile declaration, build-script-visible flag/override - state, Cargo features reported by `omnigraph-engine` itself, and a versioned - allowlist of effective engine environment. Fixture and repetition children - start from a cleared environment with fixed locale. The fixture child gets a - protocol-owned empty `fixture-scratch-v1` directory as `TMPDIR`; each measured - worker gets its own empty `worker-scratch-N` directory as both `TMPDIR` and - `OMNIGRAPH_MERGE_STAGING_DIR`. The child validates that these absolute paths - are real siblings of the active store on the verified backend. They are - removed only after process containment is proved; an uncontained failure - quarantines the whole workspace. The only inherited engine setting is - `LANCE_MEM_POOL_SIZE`, admitted only when it is the canonical decimal `u64` - byte count Lance actually parses; that applied byte count becomes typed SUT - identity. Non-UTF-8, unit-suffixed, noncanonical, and overflowing values are - refused before execution. Parent-side - `TOKIO_WORKER_THREADS`/`RAYON_NUM_THREADS` and unknown `LANCE_*` or - engine-facing `OMNIGRAPH_*` overrides are refused without serializing their - values. Cargo does not expose the final target rustc invocation to - `build.rs`, so effective LTO/codegen-unit/strip settings remain explicitly - unproved until later controlled infrastructure supplies a digest-bound build - receipt. - Its complete cache condition is part of point identity. When declared, its - read-only warm-up program runs before measured counters and the monotonic - merge timer begin. A storage firewall permits only the engine's one balanced, - empty create-if-absent capability probe during each read-write open; every - other pre-measurement write is rejected. The worker also proves the restored - tree's complete metadata shape before it declares itself ready. Each timed - repetition performs exactly one branch merge. `reopened-after-program` - additionally drops and reopens the engine handle after the warm-up while the - firewall remains closed; it makes no cache-invalidation claim. - `preparation-only` is executable as process-cold: it has no declared warm-up, - while ordinary engine open and protected-head capture still occur and the OS - page cache remains explicitly uncontrolled. -- After the measured window closes, the worker reads and verifies the exact - expected rows and values across every table on target, source, and main, - including untouched tables, and proves that source and main branch heads did - not move. The parent does not independently read those content bytes. It - independently derives and validates the point/case identities, merge route, - and declared table/total-row count attestations returned by the worker. The - run also requires a real three-way merge and one `TableWalk` interval per - diverged edge table, so a fast-forward or otherwise vacuous sample fails - loudly. This runner-v1 verification is deliberately O(store), outside the - measured window. Receipt-based O(delta) certification begins with the future - versioned-S3 reset slice. A future DST oracle may add an independent check, - but never replaces the per-repetition content probes. -- The supervisor starts the declared hard deadline immediately before sending - `Begin`. If the worker has not sent `Settled` by that deadline, the supervisor - sends `SIGKILL` to its process group, waits for and reaps the child, and proves - the group is gone. Every repetition failure, including a trailing protocol - frame after `Complete`, rejects the sample. Cleanup is permitted only when - the direct child was reaped, its process group is gone, and bounded - stdout/stderr capture reached clean EOF; otherwise the disposable workspace - is quarantined. Thus a contained failure may be cleaned up, while an unproved - containment state is preserved for inspection. A killed or partial mutation - never becomes a sample. - Preparation and exact verification use separate bounded watchdogs, each with - a 300-second minimum allowance. -- Store counts are **logical store calls** made by the engine. They do not - observe retries, pagination, multipart fan-out, or other physical attempts, - and therefore are not network-request or cloud-cost measurements. -- Fixture validation covers the exact schema, empty index inventory, and every - row on `main`, `bench-source`, and `bench-target`. Its logical-content digest - is stable across rebuilt Lance ids, timestamps, and encodings; a separate - physical tree digest pins the exact bytes restored for every repetition. +Use `list fixtures`, `list workloads` and `list scenarios` to discover inputs; +`show NAME` reports effective settings and `show --workload FILE` lists operation +ordinals. `init --help` explains config generation. All support JSON output. +`cache status NAME` and paginated `cache list` are read-only: `present` validates +published evidence, while `--verify` audits bytes before reporting `cached`. +Missing sources and absent cache entries remain distinct. See `help config`, +`help cache`, or the versioned `help --json` schema. Inspection/help do not need +a release build or a dataset cache. + +## Execution and identity boundaries + +A scenario is one selected operation on a fixture. Groups select scenario +IDs, while the config's explicit `run` list supplies default selections. The +runner expands these into the existing validated-case representation before +execution; legacy case/suite file readers remain supported. File paths and source text are resolved/frozen before workers start. +Workers receive bounded immutable text and never reread authored files. +Selected ordinals must have matching exact echoes and cannot occur in loops. +Generated selected loads must make one loader call. Prefix writes are refused, +and at least one following step must carry an explicit verification +expectation. A restart alone does not meet that requirement. + +The prefix derives process-cold, warmed-by-program, or reopened-after-program +treatment. Settings/show are neutral. Warming requires observed engine-read +callbacks, not merely a syntactic query whose parameters fail before execution. +Every repetition uses a fresh process. OS page-cache state is uncontrolled or +conditioned by the named `gqt-read-set-v1` program; neither page-cache-cold nor +storage-cold is representable. + +The engine operation timer and logical counters close before expectations and +verification. Reads materialize results within the interval. A selected +restart installs fresh counting storage before timing, measures the engine +open, and validates its preparation gate after the interval. Generated load +rows are prepared outside a single-call measurement. Optional merge probes +exist only for selected merges with per-phase attribution. The result carries +operation-kind/ordinal/occurrence receipts, selected elapsed time, verification +facts, and optional applicable merge evidence. Physical retries, pagination, +multipart fan-out, cloud costs, calibration, and concurrency witnesses remain +absent unless the record explicitly says otherwise. + +A later assertion, timeout, protocol, or process-exit failure rejects the +repetition. Accepted Settled timing can survive as diagnostic evidence without +becoming a valid sample. The parent enforces a separate measured-operation +watchdog and preparation/verification bounds; the authored whole-file GQT +budget also applies. The operation alone owns the benchmark clock. Parsing, +building, restore, warm-up, assertions, archival work, and cleanup are excluded. + +Dataset construction runs in a bounded child process. The cache builds at its +final `/active` path, closes every engine handle, freezes a never-opened +`root/` template, retires active, and publishes `fixture-source.json` followed +by `dataset-build.json`. The parent accepts only after reap, process-group +exit, and clean bounded output capture. The exclusive cache lease remains +held through all repetitions and final cleanup. APFS requires forced clonefile; +qualified XFS uses verified plain copies. Both restore the exact original +active path so Lance shallow-branch references remain valid. Relocatable +entries also use this conservative stable-path policy. + +`dataset build ` builds without a measured workload. Optional +`--queries ` contributes index requirements; `dataset build +` uses that case's exact union. Indexes are prepared with the seed +before authored updates/deletes. Dataset-only and query-required index variants +use different cache keys. `dataset validate` and `run --no-build` require +a published hit. A hit validates descriptor, logical receipt, and template +bytes once; APFS repetition preflight uses metadata/clone witnesses rather +than rehashing the whole template. Plain-copy reset necessarily reads bytes +outside timing. + +Cache keys bind recipe, engine/builder source digest, backend/reset, index +needs, canonical cache location, and registered physical source identity where +applicable. `GQT_ENGINE_DIGEST` covers production engine/core dependencies and +benchmark build/observer/reset code, plus manifests, lockfile, toolchain and +configuration. Authored inputs use separate text digests. Cache hit status and +physical tree digest are durable audit facts outside point identity. Missing +or changed published evidence is corruption, never a silent rebuild. Unknown +unpublished state and uncertain process containment are preserved/quarantined; +operator inspection must establish quiescence before removing such state. + +Final `point_id` binds recipe/query contents, verified dataset logical witness, +selected ordinal/echo, derived cache treatment, backend, and protocol. It is +unavailable during syntax-only planning; `planned_sha256` detects duplicate +content experiments before build. Paths, human case IDs, repetitions, physical +tree bytes, and cache hits do not change the point. Dataset identity covers +all live branches' keyed-node properties, edge endpoints/properties and +multiplicity, schema/index inventory, and normalized two-parent commit DAGs. +Generated unkeyed edge IDs, commit ULIDs/timestamps, and physical manifest +versions are excluded. Explicit IDs authored in a recipe remain bound by its +text digest. Historical row images are not attested. Both parent links must +resolve within bounded traversal, and parent generations must be smaller. + +Historical `branch-merge-v1` records retain their original field ordering and +canonical bytes and remain readable beside GQT records. Their old authored +execution and Rust fixture builder are retired; the legacy builder is a test +oracle only. D50 fixture parity covers construction equivalence. Its new warm +prefix consists of 24 authored aggregate queries and is not comparable as the +same cache program to the retired Rust scans. + +Children use a cleared environment, fixed locale, and protocol-owned scratch +siblings for `TMPDIR`; measured workers also use that scratch for +`OMNIGRAPH_MERGE_STAGING_DIR`. Only modeled canonical `LANCE_MEM_POOL_SIZE` +values are inherited. Unknown engine/Lance settings and Tokio/Rayon thread +count overrides are refused. Each child attests executable digest, source, +release/compiler facts, engine features, and machine identity. Effective +LTO/codegen/strip options remain unproved without a controlled build receipt. +Cleanup requires direct-child reap, process-group exit, and clean stdio; +uncertain containment cannot release a cache entry for safe reuse. ## Logical references for real graphs @@ -136,7 +146,7 @@ An externally built graph first needs a strict logical declaration. A against a byte-verified disposable copy. The checked-in FinGraph declaration is -`benchmarks/fixtures/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml`. +`benchmarks/fixtures/finbench/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml`. Its implemented algorithms are `omnigraph-schema-shape-v1`, `omnigraph-logical-properties-v1`, and `omnigraph-logical-graph-multiset-v1`. The document remains deliberately @@ -154,7 +164,7 @@ Validate the declaration with: ```bash target/release/omnigraph-bench fixture reference validate \ - benchmarks/fixtures/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml \ + benchmarks/fixtures/finbench/finbench-2026-08-21-sf10-v1.fixture-reference-v1.yaml \ --json ``` @@ -252,27 +262,16 @@ observations and relocation safety, recheck its physical bytes, and then clean it up. They neither download from S3 nor open or mutate the registered source as an OmniGraph database. -`fixture run-graph` is the narrow runnable adapter for the checked-in FinGraph -reference and strict real-graph run YAML. From a release binary, it validates -the copied graph, prepares a deterministic disjoint node-and-edge delta on two -branches, freezes that prepared state, and restores identical inputs at the -same path for fresh-process merge repetitions. macOS uses forced APFS -clonefiles. Linux requires XFS on a directly mounted EC2 instance-store NVMe -namespace and uses complete verified plain copies; it reserves one additional -prepared-tree copy plus 1 GiB before freezing. On a dedicated benchmark mount, -it waits for filesystem-wide writeback with `syncfs` after freezing and after -each restore, outside timing. The result records -`xfs-plain-copy-syncfs-same-active-path`, backend evidence, and machine evidence -captured in each measured worker; differing worker identities fail the run. - -This path is deliberately diagnostic: its output always records -`claim_eligible: false` and `durable_record: false`, has no warm-up, leaves the -OS page cache uncontrolled, and cannot publish through `--archive`. Plain-copy -reset reads the complete tree outside timing and can warm that cache. The -command still does not download a fixture, dispatch through AWS, or publish -durable telemetry. See the -[FinGraph diagnostic instructions](../../benchmarks/README.md#fingraph-diagnostic-runner) -for the declarative run shape and exact command. +Registered datasets use the same `gqt-v1` case/suite/cache/archive path. A +logical reference and schema-less GQT preparation are part of the recipe; +`--fixture ID=BUNDLE` supplies only the current source location. The source is +never opened directly as a database. Current imports require a main-only, +relocation-self-contained graph with deterministic node `@key` columns; +unkeyed nodes and named source branches are explicit scope refusals. An +identity-aware export digest binds the fixed source's original IDs before +preparation. Prepared generated edge IDs use the documented logical-equivalence +domain. See the [registered FinBench recipe](../../benchmarks/README.md#registered-finbench-merge). +The former `fixture run-graph` command and run YAML are retired. The local source namespace is a trusted-input boundary: the operator must keep it quiescent for the command. Digest/copy verification detects ordinary drift @@ -306,8 +305,7 @@ compiler/build/engine facts. Build after committing the intended source, then verify the resulting archive: ```bash -target/release/omnigraph-bench suite run \ - benchmarks/suites/local-smoke.suite-v1.yaml \ +target/release/omnigraph-bench run local-smoke \ --archive .bench/archive target/release/omnigraph-bench archive verify .bench/archive @@ -412,35 +410,27 @@ Query callers choose fixed, parameterized names; arbitrary GQ text is not accepted. The projection may be deleted at any time and rebuilt without losing evidence. -## Runner-v1 support envelope - -Execution currently supports only synthetic builder v3 with seed `0`. Its even -total table count is split equally between immutable node endpoint tables and -uniform-ring edge tables; declared divergence applies to edge tables. It uses -scalar uniform bulk-loaded data, no indexes or pre-existing deletion history, -local filesystem storage, same-host embedded execution, one client, distinct-key -write-heavy divergence, manual scheduling, per-phase attribution, and a -monotonic timer. APFS uses local-clonefile reset and supports process-cold, -warmed-by-program, and reopened-after-program engine preparation. Linux/XFS -admits only verified plain-copy reset with the exact process-fresh, -preparation-only, uncontrolled-page-cache, no-program contract described below. - -The host probe proves APFS on an internal macOS NVMe or SATA SSD, or XFS on a -direct EC2 instance-store NVMe namespace (and distinguishes EBS). A debug -build, S3 or Azure backend, server execution, unproved -host declaration, unsupported scenario axis, deadline breach, reset witness -mismatch, non-general merge route, or content mismatch is refused instead of -being approximated. A true OS-page-cache-cold claim is not representable yet; -it requires a named platform/backend control and a post-control eviction -witness. Storage-cold is likewise unsupported and unrepresentable. - -Before initialization, runner-v1 derives the exact builder publication recipe -and refuses an emergent history depth. Its local construction envelope is at -most 256 tables, 10 million base rows, 4 GiB of conservatively estimated -generated bytes, 100,000 commits per branch, and 750,000 estimated fixture -entries. It also requires free scratch capacity for a 16x byte-amplification -allowance plus 1 GiB and the exact staged worker executable before writing the -fixture. These are runner safety limits, not case-schema or engine limits. +## Local support envelope + +The adapter accepts direct-engine, local-filesystem GQT environments without +DST seams or concurrent actor blocks. The admitted tuples are APFS with +local-clonefile or qualified XFS with plain-copy, on the declared NVMe SSD +backend. The platform probe remains authoritative. Cloud stores, remote +servers, unproved backend declarations, and OS page-cache eviction claims are +refused; unsupported diagnostic sources are retained under `benchmarks/deferred/`. + +A frozen source is bounded at 512 KiB, the combined plan at 256 KiB, the bound +request reservation at 512 KiB, and the actual framed request at 1 MiB. The +selected echo is at most 16 KiB and must fit the projection's serialized row +budget. Query programs are limited to 4096 expanded steps. Before acquiring or +building a dataset, the runner bounds all repetitions' canonical receipts plus +2 MiB reserved for the record envelope against the 64 MiB archive limit. Reduce +repetitions when this bound is exceeded; the final record size is also checked. +Dataset manifests are bounded at 1 MiB. Dataset history +observation is bounded at 1024 live branches and one million reachable commits +per branch; both parent links must be available. Generator-specific bounds +remain in the core GQT grammar. These limits are explicit refusals, not silent +truncation or fallback execution. Without `--archive`, `suite run --json` still emits a versioned diagnostic execution projection whose runs have `durable_record: false`; it must not be @@ -460,64 +450,22 @@ print the same complete recovery JSON envelope, not only a timing summary. If acquisition fails and publishing its censored prefix also fails, that envelope retains the recording error and the complete structured acquisition error as separate fields. -Fixture caching and controlled cloud orchestration belong to later, separately reviewed -slices. +Controlled cloud orchestration remains a later, separately reviewed slice. Machine-readable diagnostic-mode failures keep the suite/case/point identity and all completed runs or repetitions. A worker killed at its hard deadline contributes structured process-containment evidence, but never a partial sample. -## Diagnostic engine comparison - -`examples/compare_engines.rs` times engine v2 through `Session::query` on a -synthetic graph (engine v1 is the frozen test reference and has no production -door to time). It checks row counts and records each shape's complete result -before timing, then checks every measured result against it outside the -timer. The ten shapes cover lookup, narrow -and whole-node scans, filtering, counting, grouped aggregation, ordered top-k, -traversal, filtered traversal and negation. - -```bash -RUSTFLAGS= cargo run --release --locked -p omnigraph-bench --example compare_engines -- \ - --rows 10000 --iterations 20 --warmups 5 -``` - -Setup, index construction, JSON conversion and verification are outside the -measured window. Five warm-up passes precede 20 measured rounds; query order -rotates. The timer includes query compilation/cache -lookup, planning and execution through materialized result batches. Tokio uses -four workers. The fixture has one edge per two nodes, a 1,080-byte biography -and a 32-dimensional vector per node. Run sizes must be multiples of 100, -from 1,000 through 100,000. +## End-to-end query and traversal workloads -Output is diagnostic JSON lines, not durable suite records. This measures warm -local latency with shared engine caches and an uncontrolled OS page cache; it -does not qualify cold reads, cloud storage, concurrent throughput or search. -Repeat in fresh processes and record the executable/source hashes, machine, -profile and effective Lance thread/pool settings alongside the raw samples. - -### Traversal and aggregation memory diagnostic - -`examples/issue_shapes.rs` measures `count_bare`, `destination_projection`, -`grouped_fanout` and `destination_search` with 200 hubs and 500 edges per hub. -Each person has a biography and a 1,024-dimensional vector; every tenth -person matches the text search. The default fixture holds 20,000 people. - -```bash -RUSTFLAGS= cargo run --release --locked -p omnigraph-bench --example issue_shapes -- \ - --out /tmp/omnigraph-issue-shapes-run --rows 20000 --repeats 4 -``` +The shared [catalog](../../benchmarks/benchmarks.yaml) owns the `end-to-end`, +`query-shapes` and `traversal` groups. They execute complete public graph +operations with expected rows authored in GQT. Each case identifies its own +fixture size and cache treatment; bounded replacements have new experiment +identities and do not preserve the historical Rust timing series. -Both diagnostics refuse builds carrying encoded Rust flags. Build-time -commit, dirty-state and compiler facts identify the compiled code; the memory -diagnostic additionally hashes its executable and embedded source before -measurement. Output is diagnostic evidence, never a qualified performance claim. - -Before timing, engine v2 is checked against complete fixture-derived -results; a mismatch refuses the run. Every timed answer is checked outside -the timer. Each shape/repeat uses a fresh child, so peak RSS cannot inherit -another shape's high-water mark. `ru_maxrss` includes opening, warmups and result -verification: it is a process upper bound, not operator live memory. The OS -page cache is uncontrolled. `--out` is required and existing output files are refused. `--store`, -when supplied, must be empty; an old fixture is not trusted from its row count. +The [deferred inventory](../../benchmarks/deferred/README.md) preserves unsupported +maintenance, concurrency, transport and scale experiments outside Cargo target +discovery. GQ must expose maintenance operations before those scenarios return; +GQT adds no separate cleanup or optimization command. diff --git a/crates/omnigraph-bench/build.rs b/crates/omnigraph-bench/build.rs index a5eafd3ea..c74dc47f1 100644 --- a/crates/omnigraph-bench/build.rs +++ b/crates/omnigraph-bench/build.rs @@ -73,6 +73,9 @@ fn main() { } emit_git_rerun_paths(repository); } + if let Some(root) = repository { + emit_gqt_engine_digest(root); + } let source_git_commit = repository .and_then(probe_git_commit) .unwrap_or_else(|| UNKNOWN.to_string()); @@ -821,3 +824,67 @@ fn emit_reference_rerun_path(reference: &Path, git_dir: &Path) { ancestor = path.parent(); } } + +fn emit_gqt_engine_digest(root: &Path) { + use sha2::{Digest, Sha256}; + fn collect(path: &Path, files: &mut Vec) { + if path.file_name().is_some_and(|n| { + n == "tests" || n == "tests.rs" || n == "gqt_tests.rs" || n == "branch_merge_oracle.rs" + }) { + return; + } + + if path.is_dir() { + println!("cargo:rerun-if-changed={}", path.display()); + let mut children = std::fs::read_dir(path) + .expect("read engine digest directory") + .map(|e| e.expect("read engine digest entry").path()) + .collect::>(); + children.sort(); + for child in children { + collect(&child, files) + } + } else if path.is_file() { + files.push(path.to_path_buf()) + } + } + let mut files = Vec::new(); + for name in ["Cargo.toml", "Cargo.lock", "rust-toolchain.toml"] { + let path = root.join(name); + if path.exists() { + files.push(path) + } + } + if root.join(".cargo").is_dir() { + collect(&root.join(".cargo"), &mut files) + } + for entry in std::fs::read_dir(root.join("crates")).expect("read workspace crates") { + let path = entry.expect("read crate entry").path(); + let name = path.file_name().unwrap().to_string_lossy(); + if matches!( + name.as_ref(), + "omnigraph-gqt" | "omnigraph-dst" | "omnigraph-reference-engine" + ) { + continue; + } + for leaf in ["Cargo.toml", "build.rs", "src"] { + let input = path.join(leaf); + if input.exists() { + collect(&input, &mut files) + } + } + } + files.sort(); + let mut digest = Sha256::new(); + digest.update(b"omnigraph-gqt-engine-inputs-v1\0"); + for path in files { + let relative = path.strip_prefix(root).unwrap().to_string_lossy(); + let bytes = std::fs::read(&path).expect("read engine digest input"); + digest.update((relative.len() as u64).to_le_bytes()); + digest.update(relative.as_bytes()); + digest.update((bytes.len() as u64).to_le_bytes()); + digest.update(bytes); + println!("cargo:rerun-if-changed={}", path.display()) + } + println!("cargo:rustc-env=GQT_ENGINE_DIGEST={:x}", digest.finalize()); +} diff --git a/crates/omnigraph-bench/src/archive.rs b/crates/omnigraph-bench/src/archive.rs index a8f8e7b58..dbc31dce9 100644 --- a/crates/omnigraph-bench/src/archive.rs +++ b/crates/omnigraph-bench/src/archive.rs @@ -37,7 +37,10 @@ use std::sync::Arc; #[cfg(unix)] use std::time::Instant; -use crate::record::{RunRecordV1, canonical_record_bytes, parse_canonical_record}; +use crate::gqt_record::{ + AnyRunRecordV1, AuthorityRecord, canonical_bytes as canonical_record_bytes, + parse as parse_canonical_record, +}; /// Version of the archive pointer and receipt contract. pub const ARCHIVE_FORMAT_VERSION: u32 = 1; @@ -140,7 +143,7 @@ pub struct ArchiveReceiptV1 { /// pointer. Unreachable content objects are deliberately not records. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ArchivedRecord { - pub record: RunRecordV1, + pub record: AnyRunRecordV1, pub receipt: ArchiveReceiptV1, } @@ -1592,9 +1595,9 @@ pub fn preflight_archive_publication(archive_root: &Path) -> Result<(), ArchiveE /// /// Re-publishing byte-identical content for the same invocation is /// idempotent. Reusing an invocation id for different bytes fails closed. -pub fn publish_record( +pub fn publish_record( archive_root: &Path, - record: &RunRecordV1, + record: &R, ) -> Result { let bytes = canonical_record_bytes(record).map_err(|error| { ArchiveError::new( @@ -1619,7 +1622,7 @@ pub fn publish_record( } let record_sha256 = sha256_bytes(&bytes); require_sha256(&record_sha256, "record digest")?; - let invocation_id = &record.invocation.invocation_id; + let invocation_id = &record.invocation().invocation_id; let object_relative_path = object_relative_path(&record_sha256); let pointer_relative_path = pointer_relative_path(invocation_id)?; @@ -2143,13 +2146,14 @@ fn load_invocation( ), )); } - if record.invocation.invocation_id != pointer.invocation_id { + if record.invocation().invocation_id != pointer.invocation_id { return Err(ArchiveError::new( "archive_invocation_mismatch", Some(&object_path), format!( "pointer claims invocation {}, record contains {}", - pointer.invocation_id, record.invocation.invocation_id + pointer.invocation_id, + record.invocation().invocation_id ), )); } @@ -3327,7 +3331,7 @@ mod tests { let loaded = load_archive(archive.path()).unwrap(); assert_eq!(loaded.len(), 1); - assert_eq!(loaded[0].record, record); + assert_eq!(loaded[0].record, AnyRunRecordV1::Legacy(record.clone())); assert_eq!(loaded[0].receipt.record_sha256, first.record_sha256); assert!(!loaded[0].receipt.newly_published); @@ -3374,7 +3378,10 @@ mod tests { let record = crate::record::tests::valid_record_fixture(); let receipt = publish_record(&archive, &record).unwrap(); - assert_eq!(load_archive(&archive).unwrap()[0].record, record); + assert_eq!( + load_archive(&archive).unwrap()[0].record, + AnyRunRecordV1::Legacy(record.clone()) + ); assert!(archive.join(receipt.object_relative_path).is_file()); assert!(archive.join(receipt.pointer_relative_path).is_file()); assert_eq!(iter_archive(&replacement).unwrap().remaining(), 0); @@ -3483,7 +3490,7 @@ mod tests { let bytes = canonical_record_bytes(&record).unwrap(); let digest = sha256_bytes(&bytes); let object_relative = object_relative_path(&digest); - let pointer_relative = pointer_relative_path(&record.invocation.invocation_id).unwrap(); + let pointer_relative = pointer_relative_path(&record.invocation().invocation_id).unwrap(); let original_inode = { let lock = acquire_archive_lock( @@ -3599,7 +3606,10 @@ mod tests { assert!(receipt.newly_published); assert_eq!(remaining_pointer_directory_sync_failures(), 0); - assert_eq!(load_archive(archive.path()).unwrap()[0].record, record); + assert_eq!( + load_archive(archive.path()).unwrap()[0].record, + AnyRunRecordV1::Legacy(record.clone()) + ); } #[cfg(unix)] @@ -3640,7 +3650,7 @@ mod tests { let archive = holder.path().join("archive"); fs::create_dir(&archive).unwrap(); let record = crate::record::tests::valid_record_fixture(); - let pointer_relative = pointer_relative_path(&record.invocation.invocation_id).unwrap(); + let pointer_relative = pointer_relative_path(&record.invocation().invocation_id).unwrap(); let pointer_path = archive.join(&pointer_relative); let pointer_parent = pointer_path.parent().unwrap().to_path_buf(); let pointer_name = pointer_path.file_name().unwrap().to_owned(); @@ -3679,7 +3689,7 @@ mod tests { let archive = holder.path().join("archive"); fs::create_dir(&archive).unwrap(); let record = crate::record::tests::valid_record_fixture(); - let pointer_relative = pointer_relative_path(&record.invocation.invocation_id).unwrap(); + let pointer_relative = pointer_relative_path(&record.invocation().invocation_id).unwrap(); let pointer_path = archive.join(&pointer_relative); let shard_path = pointer_path.parent().unwrap().to_path_buf(); let shard_name = shard_path.file_name().unwrap().to_owned(); @@ -3707,7 +3717,10 @@ mod tests { fs::metadata(&displaced_invocation_root).unwrap().ino(), "the pointer shard must remain reachable through a newly installed ancestor" ); - assert_eq!(load_archive(&archive).unwrap()[0].record, record); + assert_eq!( + load_archive(&archive).unwrap()[0].record, + AnyRunRecordV1::Legacy(record.clone()) + ); } #[cfg(unix)] @@ -3718,12 +3731,12 @@ mod tests { let archive = tempfile::tempdir().unwrap(); let record = crate::record::tests::valid_record_fixture(); let record_sha256 = sha256_bytes(&canonical_record_bytes(&record).unwrap()); - let pointer_relative = pointer_relative_path(&record.invocation.invocation_id).unwrap(); + let pointer_relative = pointer_relative_path(&record.invocation().invocation_id).unwrap(); let pointer_path = archive.path().join(&pointer_relative); let displaced_pointer = archive.path().join("displaced-pointer"); let expected_pointer = serde_json::to_vec(&InvocationPointerV1 { archive_format_version: ARCHIVE_FORMAT_VERSION, - invocation_id: record.invocation.invocation_id.clone(), + invocation_id: record.invocation().invocation_id.clone(), record_sha256: record_sha256.clone(), object_relative_path: object_relative_path(&record_sha256), }) @@ -3764,7 +3777,7 @@ mod tests { assert_eq!(error.code, "archive_pointer_publication_unknown"); let possible = error.possibly_published.as_ref().unwrap(); assert_eq!(possible.archive_format_version, ARCHIVE_FORMAT_VERSION); - assert_eq!(possible.invocation_id, record.invocation.invocation_id); + assert_eq!(possible.invocation_id, record.invocation().invocation_id); assert_eq!(possible.record_sha256, expected_digest); assert_eq!( possible.object_relative_path, @@ -3772,7 +3785,7 @@ mod tests { ); assert_eq!( possible.pointer_relative_path, - pointer_relative_path(&record.invocation.invocation_id).unwrap() + pointer_relative_path(&record.invocation().invocation_id).unwrap() ); assert!( archive @@ -3784,7 +3797,7 @@ mod tests { let serialized = serde_json::to_value(&error).unwrap(); assert_eq!( serialized["possibly_published"]["invocation_id"], - record.invocation.invocation_id + record.invocation().invocation_id ); assert_eq!( remaining_pointer_directory_sync_failures(), @@ -3801,7 +3814,10 @@ mod tests { possible.as_ref() ); assert_eq!(remaining_pointer_directory_sync_failures(), 0); - assert_eq!(load_archive(archive.path()).unwrap()[0].record, record); + assert_eq!( + load_archive(archive.path()).unwrap()[0].record, + AnyRunRecordV1::Legacy(record.clone()) + ); inject_pointer_directory_sync_failures(std::iter::repeat_n( nix::libc::EINTR, @@ -3841,7 +3857,7 @@ mod tests { ); let conflicting = ArchivePublicationUnknownV1::new( - record.invocation.invocation_id.clone(), + record.invocation().invocation_id.clone(), "b".repeat(64), ) .unwrap(); @@ -3961,12 +3977,18 @@ mod tests { let anchored = load_invocation(&inventory.anchored_root, invocation_id) .unwrap() .0; - assert_eq!(anchored.record, original); - assert_ne!(anchored.record, forged_external_root); + assert_eq!(anchored.record, AnyRunRecordV1::Legacy(original.clone())); + assert_ne!( + anchored.record, + AnyRunRecordV1::Legacy(forged_external_root) + ); fs::rename(&archive, &replacement).unwrap(); fs::rename(&displaced, &archive).unwrap(); - assert_eq!(inventory.next().unwrap().unwrap().record, original); + assert_eq!( + inventory.next().unwrap().unwrap().record, + AnyRunRecordV1::Legacy(original) + ); } #[cfg(unix)] @@ -4144,7 +4166,7 @@ mod tests { .unwrap() .unwrap() .record - .invocation + .invocation() .invocation_id, first.invocation.invocation_id ); @@ -4155,7 +4177,7 @@ mod tests { .unwrap() .unwrap() .record - .invocation + .invocation() .invocation_id, second.invocation.invocation_id ); @@ -4164,7 +4186,7 @@ mod tests { assert_eq!( second_pass .by_ref() - .map(|result| result.unwrap().record.invocation.invocation_id) + .map(|result| result.unwrap().record.invocation().invocation_id.clone()) .collect::>(), vec![ first.invocation.invocation_id, diff --git a/crates/omnigraph-bench/src/bin/bench_cli/mod.rs b/crates/omnigraph-bench/src/bin/bench_cli/mod.rs new file mode 100644 index 000000000..52ed3459e --- /dev/null +++ b/crates/omnigraph-bench/src/bin/bench_cli/mod.rs @@ -0,0 +1,583 @@ +//! Discovery, config generation and help share the executable's parser. +use std::collections::BTreeMap; +use std::fs; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::process::ExitCode; + +use clap::{Args, CommandFactory, Subcommand, ValueEnum}; +use omnigraph_bench::catalog::{ + self, Catalog, ConfigV2, Defaults, FixtureInput, ProtocolOverrides, Scenario, +}; +use omnigraph_bench::dataset_cache::{self, CacheInspection, CacheState, SourceAvailability}; +use omnigraph_bench::discovery; +use omnigraph_bench::gqt_case::{self, GqtFixture, MeasuredStep}; +use omnigraph_bench::gqt_runner::GqtOperationKind; +use omnigraph_bench::{Diagnostic, RUNNER_OUTPUT_VERSION}; +use serde::Serialize; +use serde_json::{Value, json}; + +use super::{Cli, print_diagnostics, print_json_success}; + +#[derive(Debug, Args)] +pub struct CatalogArgs { + /// Read this config; otherwise discover benchmarks/benchmarks.yaml from cwd ancestors. + #[arg(long)] + pub config: Option, + /// Emit versioned machine-readable output. + #[arg(long)] + pub json: bool, +} +#[derive(Debug, Clone, Copy, ValueEnum)] +pub enum InventoryKind { + Fixtures, + Workloads, + Scenarios, +} +#[derive(Debug, Args)] +pub struct ListArgs { + #[arg(value_enum)] + pub kind: InventoryKind, + #[command(flatten)] + pub catalog: CatalogArgs, +} +#[derive(Debug, Args)] +pub struct ShowArgs { + /// Scenario ID from the selected config. + #[arg(required_unless_present = "workload", conflicts_with = "workload")] + pub name: Option, + /// Inspect parser operation ordinals/text in this cwd-relative GQT file. + #[arg(long, conflicts_with = "config")] + pub workload: Option, + #[command(flatten)] + pub catalog: CatalogArgs, +} +#[derive(Debug, Subcommand)] +pub enum CacheCommand { + /// Inspect the exact dataset variant needed by a scenario; never builds or restores it. + Status { + name: String, + #[command(flatten)] + catalog: CatalogArgs, + /// Same cwd-relative cache root used by run. + #[arg(long, default_value = "target/gqt-datasets")] + dataset_cache: PathBuf, + /// Registered source mapping, ID=BUNDLE. Never copied by inspection. + #[arg(long = "fixture", value_name = "ID=BUNDLE")] + fixtures: Vec, + /// Audit all published bytes as well as the descriptor and logical evidence. + #[arg(long)] + verify: bool, + }, + /// List a bounded page of existing cache variants, including historical entries. + List { + #[arg(long, default_value = "target/gqt-datasets")] + dataset_cache: PathBuf, + #[arg(long, default_value_t = 100)] + limit: usize, + /// Continue after the previous page's cursor. + #[arg(long)] + after: Option, + #[arg(long)] + verify: bool, + #[arg(long)] + json: bool, + }, +} +#[derive(Debug, Args)] +pub struct InitArgs { + /// Fixture GQT path relative to the current directory. + #[arg(long)] + pub fixture: PathBuf, + /// Workload GQT path relative to the current directory. + #[arg(long)] + pub workload: PathBuf, + /// Parser operation ordinal; use show --workload to discover these. + #[arg(long)] + pub step: usize, + /// New YAML file; existing files and symlinks are never replaced. + #[arg(long)] + pub output: PathBuf, + #[arg(long, default_value = "custom")] + pub name: String, + #[arg(long)] + pub json: bool, +} +#[derive(Debug, Args)] +pub struct HelpArgs { + /// config, cache, or a command path such as "suite run". + pub topic: Vec, + #[arg(long)] + pub json: bool, +} + +pub fn legacy_input(path: &Path) -> Result> { + if path.is_absolute() || path.components().count() > 1 || path.extension().is_some() { + return Ok(true); + } + match fs::symlink_metadata(path) { + Ok(_) => Ok(true), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(false), + Err(e) => Err(vec![Diagnostic::error( + "case_path_unreadable", + path.display().to_string(), + e.to_string(), + )]), + } +} + +pub fn load(args: &CatalogArgs) -> Result> { + Catalog::load(&catalog::find_config(args.config.as_deref())?) +} +pub fn failure(diagnostics: Vec, json_output: bool) -> ExitCode { + if json_output { + print_json_success(&json!({"cli_output_version":1,"ok":false,"diagnostics":diagnostics})); + ExitCode::FAILURE + } else { + print_diagnostics(&diagnostics) + } +} +fn success(value: &T, json_output: bool) -> ExitCode { + if json_output { + let value = match serde_json::to_value(value) { + Ok(value) => value, + Err(e) => return failure(problem("output_serialization_failed", e.to_string()), true), + }; + print_json_success( + &json!({"cli_output_version":1,"ok":true,"value":value,"diagnostics":[]}), + ) + } else { + match serde_yaml::to_string(value) { + Ok(text) => { + print!("{text}"); + ExitCode::SUCCESS + } + Err(e) => failure( + vec![Diagnostic::error("serialization_error", "$", e.to_string())], + false, + ), + } + } +} +fn problem(code: &str, message: impl Into) -> Vec { + vec![Diagnostic::error(code, "$", message)] +} + +pub fn list(args: ListArgs) -> ExitCode { + let catalog = match load(&args.catalog) { + Ok(c) => c, + Err(e) => return failure(e, args.catalog.json), + }; + match args.kind { + InventoryKind::Scenarios => { + let inventory = discovery::scenarios(&catalog); + if args.catalog.json { + return success(&inventory, true); + } + println!("SCENARIO SOURCE GROUPS"); + for entry in inventory.entries { + println!( + "{} {:?} {}", + entry.id, + entry.source, + entry.groups.join(", ") + ); + for diagnostic in entry.diagnostics { + eprintln!("{}: {}", diagnostic.path, diagnostic.message); + } + } + ExitCode::SUCCESS + } + kind => match discovery::sources(&catalog, matches!(kind, InventoryKind::Fixtures)) { + Ok(inventory) => { + if args.catalog.json { + return success(&inventory, true); + } + println!("PATH SOURCE KIND SCENARIOS"); + for entry in inventory.entries { + println!( + "{} {:?} {} {}", + entry.path.display(), + entry.source, + entry.kind, + entry.scenarios.join(", ") + ); + for diagnostic in entry.diagnostics { + eprintln!("{}: {}", diagnostic.path, diagnostic.message); + } + } + ExitCode::SUCCESS + } + Err(e) => failure(e, args.catalog.json), + }, + } +} + +pub fn show(args: ShowArgs) -> ExitCode { + if let Some(path) = args.workload { + let source = match gqt_case::read_source(&path) { + Ok(s) => s, + Err(e) => return failure(problem("invalid_workload", e), args.catalog.json), + }; + let case = match source.parse() { + Ok(c) => c, + Err(e) => return failure(problem("invalid_workload", e), args.catalog.json), + }; + let descriptors = match gqt_case::workload_steps(&case) { + Ok(steps) => steps, + Err(e) => return failure(problem("invalid_workload", e), args.catalog.json), + }; + let operations: Vec<_> = descriptors.into_iter().map(|s| { + json!({"ordinal":s.ordinal,"kind":GqtOperationKind::from(s.kind),"text":s.source,"in_loop":s.in_loop}) + }).collect(); + return success( + &json!({"workload":path.to_string_lossy(),"sha256":source.sha256,"operations":operations}), + args.catalog.json, + ); + } + let catalog = match load(&args.catalog) { + Ok(c) => c, + Err(e) => return failure(e, args.catalog.json), + }; + let name = args + .name + .as_deref() + .expect("clap requires scenario or workload"); + let plan = match catalog.plan(name) { + Ok(p) => p, + Err(e) => return failure(e, args.catalog.json), + }; + let scenario = catalog.scenario(name).expect("resolved scenario exists"); + let resolve = |path: &Path| { + let resolved = catalog.root.join(path).canonicalize()?; + if resolved.to_str().is_none() { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "resolved source path must be UTF-8", + )); + } + Ok(resolved) + }; + let resolved_fixture = match catalog::fixture_paths(&plan.definition.fixture) + .iter() + .map(|p| resolve(p)) + .collect::, _>>() + { + Ok(paths) => paths, + Err(e) => return failure(problem("source_changed", e.to_string()), args.catalog.json), + }; + let resolved_workload = match resolve(&scenario.workload) { + Ok(path) => path, + Err(e) => return failure(problem("source_changed", e.to_string()), args.catalog.json), + }; + success( + &json!({ + "id":name,"config":catalog.path,"config_version":catalog::CONFIG_VERSION,"fixture":plan.definition.fixture, + "resolved_fixture":resolved_fixture, + "resolved_workload":resolved_workload, + "workload":scenario.workload,"measured_step":plan.definition.workload.measured_step, + "environment":plan.definition.environment,"protocol":plan.definition.protocol, + "repetitions":scenario.expand(&catalog.definition.defaults).1, + "recipe_sha256":plan.recipe_sha256,"planned_sha256":plan.planned_sha256, + "needs_indices":plan.needs_indices,"cache_condition":plan.cache_condition, + }), + args.catalog.json, + ) +} + +pub fn cache(command: CacheCommand) -> ExitCode { + match command { + CacheCommand::List { + dataset_cache, + limit, + after, + verify, + json, + } => match dataset_cache::list(&dataset_cache, limit, after.as_deref(), verify) { + Ok(page) => { + let ok = page.entries.iter().all(inspection_succeeded); + let diagnostics = page + .entries + .iter() + .filter_map(|entry| { + entry.diagnostic.as_ref().map(|e| { + Diagnostic::error(&e.code, entry.path.display().to_string(), &e.message) + }) + }) + .collect(); + cache_output(&page, ok, diagnostics, json) + } + Err(e) => failure(problem(&e.code, e.message), json), + }, + CacheCommand::Status { + name, + catalog: args, + dataset_cache, + fixtures, + verify, + } => { + let catalog = match load(&args) { + Ok(c) => c, + Err(e) => return failure(e, args.json), + }; + let scenario = match catalog.scenario(&name) { + Ok(s) => s, + Err(e) => return failure(e, args.json), + }; + let plan = match catalog.plan(&name) { + Ok(plan) => plan, + Err(diagnostics) => { + let source = discovery::scenario(&catalog, scenario).source; + let inspection = CacheInspection { + inspection_version: 1, + source: Some(if source == discovery::SourceState::Missing { + SourceAvailability::Missing + } else { + SourceAvailability::Invalid + }), + cache: CacheState::Unknown, + key: None, + path: dataset_cache, + identity: None, + diagnostic: None, + }; + return cache_output( + &inspection, + inspection_succeeded(&inspection), + diagnostics, + args.json, + ); + } + }; + let binding = match fixture_binding(&scenario.fixture.definition(), &fixtures) { + Ok(binding) => binding, + Err(e) => return failure(e, args.json), + }; + let inspection = + dataset_cache::inspect(&plan.dataset_build_plan(), &dataset_cache, binding, verify); + let diagnostics = inspection + .diagnostic + .as_ref() + .map(|e| problem(&e.code, &e.message)) + .unwrap_or_default(); + cache_output( + &inspection, + inspection_succeeded(&inspection), + diagnostics, + args.json, + ) + } + } +} +fn inspection_succeeded(inspection: &CacheInspection) -> bool { + match inspection.source { + Some(SourceAvailability::Missing | SourceAvailability::Unbound) => true, + Some(SourceAvailability::Invalid) => false, + Some(SourceAvailability::Available) | None => match inspection.cache { + CacheState::Missing | CacheState::Present | CacheState::Cached | CacheState::Busy => { + true + } + CacheState::Invalid | CacheState::Incomplete | CacheState::Unknown => false, + }, + } +} +fn cache_output( + inspection: &T, + ok: bool, + diagnostics: Vec, + json_output: bool, +) -> ExitCode { + let output = if json_output { + let inspection = match serde_json::to_value(inspection) { + Ok(value) => value, + Err(e) => return failure(problem("output_serialization_failed", e.to_string()), true), + }; + print_json_success( + &json!({"cli_output_version":1,"ok":ok,"value":inspection,"diagnostics":diagnostics}), + ) + } else { + success(inspection, false) + }; + if ok { output } else { ExitCode::FAILURE } +} +fn fixture_binding<'a>( + fixture: &GqtFixture, + bindings: &'a [String], +) -> Result, Vec> { + let expected = match fixture { + GqtFixture::Registered { .. } => true, + GqtFixture::Dataset { .. } => false, + }; + if !expected && !bindings.is_empty() { + return Err(problem( + "unexpected_fixture_binding", + "GQT fixtures do not use --fixture bindings", + )); + } + if bindings.len() > 1 { + return Err(problem( + "invalid_fixture_binding", + "one scenario accepts at most one registered --fixture ID=BUNDLE", + )); + } + Ok(bindings.first().map(String::as_str)) +} + +pub fn init(args: InitArgs) -> ExitCode { + match generate(&args) { + Ok(config) => success(&json!({"config":config,"scenario":args.name}), args.json), + Err(e) => failure(e, args.json), + } +} +fn generate(args: &InitArgs) -> Result> { + let output = if args.output.is_absolute() { + args.output.clone() + } else { + std::env::current_dir() + .map_err(|e| problem("init_path_error", e.to_string()))? + .join(&args.output) + }; + if output.to_str().is_none() { + return Err(problem("invalid_output_path", "output path must be UTF-8")); + } + let parent = output + .parent() + .ok_or_else(|| problem("init_path_error", "output has no parent"))? + .canonicalize() + .map_err(|e| problem("init_path_error", e.to_string()))?; + let relative = |path: &Path| -> Result> { + path.canonicalize() + .map_err(|e| problem("source_path_error", e.to_string()))? + .strip_prefix(&parent) + .map(Path::to_path_buf) + .map_err(|_| { + problem( + "source_outside_root", + "place the output YAML in a directory containing both source files", + ) + }) + }; + let fixture = relative(&args.fixture)?; + let workload = relative(&args.workload)?; + let source = + gqt_case::read_source(&args.workload).map_err(|e| problem("invalid_workload", e))?; + let case = source.parse().map_err(|e| problem("invalid_workload", e))?; + let operation = gqt_case::workload_steps(&case) + .map_err(|e| problem("invalid_workload", e))? + .into_iter() + .find(|s| s.ordinal == args.step) + .ok_or_else(|| { + problem( + "unknown_operation", + "step ordinal does not exist; use show --workload", + ) + })?; + let config = ConfigV2 { + version: catalog::CONFIG_VERSION, + defaults: Defaults::default(), + scenarios: vec![Scenario { + id: args.name.clone(), + fixture: FixtureInput::Path(fixture), + workload, + measured_step: MeasuredStep { + ordinal: args.step, + text: operation.source, + }, + repetitions: None, + deadline_seconds: None, + environment: None, + protocol: ProtocolOverrides::default(), + }], + groups: BTreeMap::new(), + run: vec![args.name.clone()], + }; + let yaml = serde_yaml::to_string(&config) + .map_err(|e| problem("config_serialization_error", e.to_string()))?; + Catalog::from_source(&output, &yaml)?.resolve(None, None)?; + let mut file = fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&output) + .map_err(|e| problem("config_create_failed", format!("{}: {e}", output.display())))?; + file.write_all(yaml.as_bytes()) + .and_then(|()| file.sync_all()) + .map_err(|e| problem("config_write_failed", e.to_string()))?; + Ok(output) +} + +const CONFIG_HELP: &str = "Config version 2\n\nfixtures/ contains starting-state GQT; workloads/ contains operations and checks.\nbenchmarks.yaml defines scenarios once, optional groups of scenario IDs, and an explicit run list.\n\nrun NAME selects one scenario or group. run --config FILE uses only FILE's run list.\nWithout --config, explicit paths, filenames with a suffix, and existing local entries use the legacy case loader.\nUse ./NAME to force a case path; use --config to select a catalog name even if a local entry has that name.\nPaths inside YAML are relative to that YAML's directory and must stay inside it.\n--config never falls back if the file is missing or invalid.\n\nEach scenario needs id, fixture, workload and measured_step (ordinal plus exact operation text).\nA fixture is a GQT path, or {kind: registered, reference: ..., preparation: ...}.\nDefaults: repetitions=5, deadline_seconds=60, local APFS/clonefile on macOS or XFS/plain-copy elsewhere.\nEnvironment and protocol are expanded before identity: per-phase attribution, manual schedule, monotonic timer.\nScenario fields override defaults; run --repetitions overrides only sample quantity.\ndeadline_seconds: null disables the measurement deadline, not the supervisor watchdog.\nProtocol overrides are attribution, schedule, reset and timer; deadline_seconds is a scenario/default field.\n\nCopy benchmarks/custom.example.yaml, or generate a checked config:\n omnigraph-bench show --workload benchmarks/workloads/tiny_read.gqt\n omnigraph-bench init --fixture benchmarks/fixtures/tiny_graph.gqt --workload benchmarks/workloads/tiny_read.gqt --step 1 --output custom.yaml\n omnigraph-bench run --config custom.yaml\n"; +const CACHE_HELP: &str = "Cache inspection is read-only and never builds, restores, cleans or quarantines data.\n\n omnigraph-bench cache status tiny-read --json\n omnigraph-bench cache status tiny-read --verify --json\n omnigraph-bench cache list --limit 100 --json\n\nThe default cache is target/gqt-datasets relative to cwd. Use the same --dataset-cache path for run and status.\nKeys bind recipe, engine/builder, backend/reset, cache location, required indexes and registered-source identity.\nHistorical variants may exist while the current scenario has a cache miss.\nSource: available, missing, invalid, unbound. Cache: missing, present, cached, busy, invalid, incomplete, unknown.\npresent checks published evidence; --verify audits full bytes before reporting cached.\nbusy returns immediately for a held lease. Missing or unbound sources give unknown cache status.\nA status is a snapshot, not a reservation. Cache missing is a successful observation; inability to inspect fails.\nrun builds missing fixtures unless --no-build is supplied. dataset build prepares fixtures explicitly.\nLegacy dataset validate acquires a lease and stages worker files; use cache status for read-only inspection.\n"; + +pub fn help(args: HelpArgs) -> ExitCode { + let mut command = Cli::command(); + if args.json { + if !args.topic.is_empty() { + return failure( + problem( + "invalid_help_topic", + "help --json describes all commands; omit the topic", + ), + true, + ); + } + command.build(); + return success( + &json!({"config_version":catalog::CONFIG_VERSION,"cli_output_version":1,"runner_output_version":RUNNER_OUTPUT_VERSION, + "commands":command_schema(&command), + "required_combinations": {"show":"exactly one of NAME or --workload; --workload conflicts with --config", "run":"NAME or config run list; --dataset/--queries overrides require a legacy YAML case path", "init":"--fixture, --workload, --step and --output"},"config_help":CONFIG_HELP,"cache_help":CACHE_HELP, + "output":{"inspection":"cli_output_version=1, ok, value, diagnostics","execution":"runner_output_version=2 with archive/partial-failure evidence","errors":"severity, code, path, message; JSON stdout only"}, + "effects":{"help/list/show/cache":"read-only; no database execution","init":"creates one new YAML file","run/dataset":"builds, restores or executes; run may publish to an explicitly selected archive"}, + "examples":["omnigraph-bench list fixtures --json","omnigraph-bench list workloads --json","omnigraph-bench list scenarios --json","omnigraph-bench show tiny-read --json","omnigraph-bench run tiny-read","omnigraph-bench run --config benchmarks/custom.example.yaml","omnigraph-bench cache status tiny-read --json"] + }), + true, + ); + } + match args.topic.as_slice() { + [topic] if topic == "config" => { + print!( + "{CONFIG_HELP}\nExample:\n{}", + include_str!("../../../../../benchmarks/custom.example.yaml") + ); + ExitCode::SUCCESS + } + [topic] if topic == "cache" => { + print!("{CACHE_HELP}"); + ExitCode::SUCCESS + } + topics => { + for topic in topics { + let Some(child) = command.find_subcommand(topic) else { + return failure( + problem( + "unknown_help_topic", + format!("unknown help topic '{topic}'"), + ), + false, + ); + }; + command = child.clone(); + } + match command.print_long_help() { + Ok(()) => { + println!(); + ExitCode::SUCCESS + } + Err(e) => failure(problem("help_output_error", e.to_string()), false), + } + } + } +} +fn command_schema(command: &clap::Command) -> Value { + let mut printable = command.clone(); + let usage = printable.render_usage().to_string(); + json!({"name":command.get_name(),"usage":usage, + "groups":command.get_groups().map(|g| json!({"id":g.get_id().as_str(),"required":g.is_required_set(),"args":g.get_args().map(|a|a.as_str()).collect::>()})).collect::>(),"about":command.get_about().map(ToString::to_string), + "arguments":command.get_arguments().filter(|a| !a.is_hide_set()).map(|a| json!({ + "id":a.get_id().as_str(),"long":a.get_long(),"short":a.get_short(),"required":a.is_required_set(), + "help":a.get_help().map(ToString::to_string),"action":format!("{:?}",a.get_action()), + "defaults":a.get_default_values().iter().map(|v| v.to_string_lossy()).collect::>(), + "values":a.get_value_parser().possible_values().map(|values|values.map(|v| v.get_name().to_owned()).collect::>()), + "conflicts":command.get_arg_conflicts_with(a).iter().map(|v|v.get_id().as_str()).collect::>() + })).collect::>(), + "subcommands":command.get_subcommands().filter(|c| !c.is_hide_set()).map(command_schema).collect::>()}) +} diff --git a/crates/omnigraph-bench/src/bin/omnigraph-bench.rs b/crates/omnigraph-bench/src/bin/omnigraph-bench.rs index f282c6a36..a1d8a9cba 100644 --- a/crates/omnigraph-bench/src/bin/omnigraph-bench.rs +++ b/crates/omnigraph-bench/src/bin/omnigraph-bench.rs @@ -1,6 +1,7 @@ +mod bench_cli; use std::collections::BTreeMap; use std::fs; -use std::path::{Path, PathBuf}; +use std::path::{self, Path, PathBuf}; use std::process::ExitCode; use clap::{Parser, Subcommand}; @@ -8,7 +9,6 @@ use omnigraph_bench::archive::{ ArchiveError, ArchivePublicationUnknownV1, ArchiveReceiptV1, ArchiveReconciliationV1, iter_archive, preflight_archive_publication, publish_record, reconcile_archive_publication, }; -use omnigraph_bench::case::Backend; use omnigraph_bench::fixture_reference::load_fixture_reference; use omnigraph_bench::projection::{ DEFAULT_PROJECTION_PAGE_SIZE, ProjectionCursorV1, ProjectionError, ProjectionPageV1, @@ -17,12 +17,8 @@ use omnigraph_bench::projection::{ use omnigraph_bench::real_graph::{ RealGraphObservationV1, observe_real_graph, validate_real_graph_reference, }; -use omnigraph_bench::real_graph_run::{ - execute_real_graph_run, load_real_graph_run_spec, run_real_graph_worker_files, -}; use omnigraph_bench::record::{ - AcquisitionTerminalStageV1, AcquisitionTerminalV1, InvocationIdentityV1, ObservedBackendV1, - RecordInputV1, build_censored_run_record, build_run_record, sut_identity_for_execution, + AcquisitionTerminalStageV1, AcquisitionTerminalV1, InvocationIdentityV1, }; use omnigraph_bench::registered_fixture::{ FixtureCopyPreflightReceiptV1, fingerprint_registered_fixture, preflight_copy_fixture_bindings, @@ -44,7 +40,9 @@ const MAX_DIRECTORY_ENTRIES: usize = 100_000; #[command( name = "omnigraph-bench", version, - about = "Validate, plan, and run declarative OmniGraph benchmarks" + about = "Run GQT benchmarks from a named scenario or custom YAML", + disable_help_subcommand = true, + after_help = "Start here:\n omnigraph-bench list scenarios\n omnigraph-bench show tiny-read\n omnigraph-bench run tiny-read\n omnigraph-bench run --config benchmarks/custom.example.yaml\n omnigraph-bench cache status tiny-read\n\nfixtures/ holds starting states; workloads/ holds operations and checks.\nUse help config, help cache, init --help, or help --json for agents." )] struct Cli { #[command(subcommand)] @@ -53,6 +51,19 @@ struct Cli { #[derive(Debug, Subcommand)] enum Command { + /// List fixtures, workloads or named scenarios without building or executing. + List(bench_cli::ListArgs), + /// Inspect a scenario's effective settings or a workload's operation ordinals. + Show(bench_cli::ShowArgs), + /// Inspect cache contents without creating, restoring or changing them. + Cache { + #[command(subcommand)] + command: bench_cli::CacheCommand, + }, + /// Generate a custom YAML config from GQT inputs and a selected operation. + Init(bench_cli::InitArgs), + /// Explain config/cache topics or describe all commands as JSON. + Help(bench_cli::HelpArgs), /// Inspect one-case experiment definitions. Case { #[command(subcommand)] @@ -78,15 +89,181 @@ enum Command { #[command(subcommand)] command: ProjectionCommand, }, + /// Build, validate and reuse authored GQT datasets. + Dataset { + #[command(subcommand)] + command: DatasetCommand, + }, + /// Run a named scenario/group, custom config selection, or a legacy case file. + Run { + /// Scenario/group name; a legacy case YAML path is also accepted. + case: Option, + /// Explicit config; paths in it resolve beside the YAML file. + #[arg(long, conflicts_with_all = ["dataset", "queries"])] + config: Option, + #[arg(long)] + dataset: Option, + #[arg(long)] + queries: Option, + #[arg(long)] + repetitions: Option, + #[arg(long, default_value = "target/gqt-datasets")] + dataset_cache: PathBuf, + #[arg(long)] + no_build: bool, + #[arg(long = "fixture")] + fixtures: Vec, + #[arg(long)] + archive: Option, + #[arg(long)] + json: bool, + }, /// Private one-repetition worker endpoint used by the supervising runner. - #[command(name = "__worker-v1", hide = true)] + #[command(name = "__gqt-worker-v1", hide = true)] WorkerV1, /// Private bounded fixture-builder endpoint used by the supervising runner. - #[command(name = "__fixture-worker-v1", hide = true)] + #[command(name = "__dataset-worker-v1", hide = true)] FixtureWorkerV1 { request: PathBuf, result: PathBuf }, - /// Private real-graph diagnostic worker endpoint. - #[command(name = "__real-graph-worker-v1", hide = true)] - RealGraphWorkerV1 { request: PathBuf, result: PathBuf }, +} + +#[derive(Debug, Subcommand)] +enum DatasetCommand { + /// Build a raw dataset GQT, or the exact dataset needed by a case YAML. + Build { + input: PathBuf, + #[arg(long)] + queries: Option, + #[arg(long, value_parser = ["apfs", "xfs"])] + filesystem: Option, + #[arg(long)] + dataset_cache: PathBuf, + #[arg(long = "fixture")] + fixtures: Vec, + #[arg(long)] + json: bool, + }, + /// Verify an existing matching cache entry; never build on a miss. + Validate { + input: PathBuf, + #[arg(long)] + queries: Option, + #[arg(long, value_parser = ["apfs", "xfs"])] + filesystem: Option, + #[arg(long)] + dataset_cache: PathBuf, + #[arg(long = "fixture")] + fixtures: Vec, + #[arg(long)] + json: bool, + }, +} +fn local_backend( + filesystem: Option<&str>, +) -> ( + omnigraph_bench::case::Backend, + omnigraph_bench::case::ResetMode, +) { + use omnigraph_bench::case::{Backend, LocalFilesystem, LocalStorageClass, ResetMode}; + let selected = filesystem.unwrap_or(if cfg!(target_os = "macos") { + "apfs" + } else { + "xfs" + }); + let (filesystem, reset) = if selected == "apfs" { + (LocalFilesystem::Apfs, ResetMode::LocalClonefile) + } else { + (LocalFilesystem::Xfs, ResetMode::PlainCopy) + }; + ( + Backend::LocalFs { + filesystem, + storage_class: LocalStorageClass::NvmeSsd, + }, + reset, + ) +} +async fn run_dataset(command: DatasetCommand) -> ExitCode { + let (input, queries, filesystem, cache, fixtures, no_build, json) = match command { + DatasetCommand::Build { + input, + queries, + filesystem, + dataset_cache, + fixtures, + json, + } => ( + input, + queries, + filesystem, + dataset_cache, + fixtures, + false, + json, + ), + DatasetCommand::Validate { + input, + queries, + filesystem, + dataset_cache, + fixtures, + json, + } => ( + input, + queries, + filesystem, + dataset_cache, + fixtures, + true, + json, + ), + }; + let plan = if input.extension().is_some_and(|e| e == "gqt") { + let (backend, reset) = local_backend(filesystem.as_deref()); + match omnigraph_bench::gqt_case::dataset_file(&input, queries.as_deref(), backend, reset) { + Ok(p) => p, + Err(e) => { + return print_cli_failure(Diagnostic::error("invalid_dataset", "dataset", e), json); + } + } + } else { + if queries.is_some() || filesystem.is_some() { + return print_cli_failure( + Diagnostic::error( + "invalid_dataset_options", + "dataset", + "--queries and --filesystem apply only to a raw dataset .gqt; a case defines both", + ), + json, + ); + } + match load_case(&input).into_result() { + Ok(c) => match c.gqt() { + Ok(p) => p.dataset_build_plan(), + Err(e) => { + return print_cli_failure( + Diagnostic::error("invalid_case", "dataset", e), + json, + ); + } + }, + Err(e) => return print_cli_failures(e, json), + } + }; + match omnigraph_bench::gqt_runner::build_dataset( + &plan, + &RunOptions { + dataset_cache: Some(cache), + no_build, + fixture_bindings: fixtures, + worker_executable: std::env::current_exe().ok(), + ..Default::default() + }, + ) + .await + { + Ok(manifest) => print_json_success(&manifest), + Err(e) => print_cli_failure(Diagnostic::error(e.code, "dataset", e.message), json), + } } #[derive(Debug, Subcommand)] @@ -170,21 +347,6 @@ enum FixtureCommand { #[arg(long)] json: bool, }, - /// Run the fixed FinGraph-native diagnostic workload from a strict YAML spec. - RunGraph { - spec: PathBuf, - #[arg(long)] - reference: PathBuf, - /// Invocation-local fixture mapping in ID=BUNDLE form. - #[arg(long = "fixture", value_name = "ID=BUNDLE")] - fixture: String, - /// Place all disposable graph copies below this existing directory. - #[arg(long)] - scratch_root: Option, - /// Emit machine-readable diagnostic results. - #[arg(long)] - json: bool, - }, } #[derive(Debug, Subcommand)] @@ -218,21 +380,44 @@ enum SuiteCommand { json: bool, }, /// Execute a validated suite against the supported local runner-v1 envelope. - Run { - file: PathBuf, - /// Select exactly one case id from the suite. - #[arg(long)] - case: Option, - /// Place disposable fixture trees below this existing directory. - #[arg(long)] - scratch_root: Option, - /// Publish complete immutable run records under this archive root. - #[arg(long)] - archive: Option, - /// Emit machine-readable diagnostic execution output. - #[arg(long)] - json: bool, - }, + Run(Box), +} + +#[derive(Debug, clap::Args)] +struct SuiteRunArgs { + file: Option, + #[arg(long, requires = "queries", conflicts_with = "file")] + dataset: Option, + #[arg(long, requires = "dataset", conflicts_with = "file")] + queries: Option, + #[arg(long, requires = "dataset")] + measured_step: Option, + #[arg(long, requires = "measured_step", allow_hyphen_values = true)] + measured_text: Option, + #[arg(long, requires = "dataset", conflicts_with = "file")] + repetitions: Option, + #[arg(long, requires = "dataset", conflicts_with = "file")] + deadline_seconds: Option, + #[arg(long, requires = "dataset", conflicts_with = "file", value_parser=["apfs","xfs"])] + filesystem: Option, + /// Select exactly one case id from the suite. + #[arg(long)] + case: Option, + /// Place disposable fixture trees below this existing directory. + #[arg(long)] + scratch_root: Option, + #[arg(long)] + dataset_cache: Option, + #[arg(long)] + no_build: bool, + #[arg(long = "fixture")] + fixtures: Vec, + /// Publish complete immutable run records under this archive root. + #[arg(long)] + archive: Option, + /// Emit machine-readable diagnostic execution output. + #[arg(long)] + json: bool, } #[derive(Debug, Subcommand)] @@ -309,56 +494,206 @@ fn parse_projection_cursor(value: &str) -> Result { struct CaseSummary<'a> { id: &'a str, path: &'a Path, - point_id: &'a str, - point_name: &'a str, + point_id: Option<&'a str>, case_digest: &'a str, } - impl<'a> CaseSummary<'a> { fn new(path: &'a Path, case: &'a ValidatedCase) -> Self { Self { - id: &case.definition.id, + id: case.id(), path, - point_id: &case.point_id, - point_name: &case.point_name, - case_digest: &case.case_digest, + point_id: case.point_id(), + case_digest: case.case_digest(), } } } - #[derive(Debug, Serialize)] struct Plan<'a> { plan_version: u32, suite: &'a str, suite_path: &'a Path, - runs: Vec>, -} - -#[derive(Debug, Serialize)] -struct PlanRun<'a> { - case_id: &'a str, - case_path: &'a Path, - repetitions: u32, - point_id: &'a str, - point_name: &'a str, - case_digest: &'a str, - identity: &'a omnigraph_bench::PointIdentityV1, + runs: Vec<&'a ResolvedRun>, } #[tokio::main] async fn main() -> ExitCode { - match Cli::parse().command { + let cli = match Cli::try_parse() { + Ok(cli) => cli, + Err(error) => { + if error.use_stderr() && std::env::args_os().any(|arg| arg == "--json") { + return bench_cli::failure( + vec![Diagnostic::error( + "invalid_arguments", + "$", + error.to_string(), + )], + true, + ); + } + let failed = error.use_stderr(); + let _ = error.print(); + return if failed { + ExitCode::FAILURE + } else { + ExitCode::SUCCESS + }; + } + }; + match cli.command { + Command::List(args) => bench_cli::list(args), + Command::Show(args) => bench_cli::show(args), + Command::Cache { command } => bench_cli::cache(command), + Command::Init(args) => bench_cli::init(args), + Command::Help(args) => bench_cli::help(args), Command::Case { command } => run_case(command), Command::Fixture { command } => run_fixture(command).await, Command::Suite { command } => run_suite(command).await, Command::Archive { command } => run_archive(command), Command::Projection { command } => run_projection(command).await, - Command::WorkerV1 => omnigraph_bench::worker::run_worker_stdio_v1().await, + Command::WorkerV1 => omnigraph_bench::gqt_worker::run_worker_stdio_v1().await, Command::FixtureWorkerV1 { request, result } => { - omnigraph_bench::fixture_worker::run_fixture_worker_files_v1(&request, &result).await + omnigraph_bench::dataset_worker::run_dataset_worker_files_v1(&request, &result).await } - Command::RealGraphWorkerV1 { request, result } => { - run_real_graph_worker_files(&request, &result).await + Command::Dataset { command } => run_dataset(command).await, + Command::Run { + case, + config, + dataset, + queries, + repetitions, + dataset_cache, + no_build, + fixtures, + archive, + json, + } => { + let legacy = if config.is_none() { + match case.as_deref().map(bench_cli::legacy_input).transpose() { + Ok(legacy) => legacy.unwrap_or(false), + Err(e) => return bench_cli::failure(e, json), + } + } else { + false + }; + if !legacy { + if dataset.is_some() || queries.is_some() { + return bench_cli::failure( + vec![Diagnostic::error( + "legacy_case_required", + "$", + "source overrides require a legacy case YAML; use init for a custom config", + )], + json, + ); + } + let catalog = match bench_cli::load(&bench_cli::CatalogArgs { config, json }) { + Ok(c) => c, + Err(e) => return bench_cli::failure(e, json), + }; + let selector = match case.as_deref() { + Some(path) => match path.to_str() { + Some(name) => Some(name), + None => { + return bench_cli::failure( + vec![Diagnostic::error( + "invalid_selector", + "$", + "scenario ID must be UTF-8", + )], + json, + ); + } + }, + None => None, + }; + let suite = match catalog.resolve(selector, repetitions) { + Ok(s) => s, + Err(e) => return bench_cli::failure(e, json), + }; + return run_resolved_suite( + suite, + None, + RunOptions { + dataset_cache: Some(dataset_cache), + no_build, + fixture_bindings: fixtures, + worker_executable: std::env::current_exe().ok(), + ..Default::default() + }, + archive, + json, + ) + .await; + } + let case = match path::absolute(case.expect("legacy route requires a path")) { + Ok(path) => path, + Err(e) => { + return bench_cli::failure( + vec![Diagnostic::error( + "case_path_unreadable", + "$", + e.to_string(), + )], + json, + ); + } + }; + let repetitions = repetitions.unwrap_or(1); + let mut loaded = match load_case(&case).into_result() { + Ok(c) => c, + Err(e) => return print_cli_failures(e, json), + }; + if dataset.is_some() || queries.is_some() { + let plan = match loaded.gqt() { + Ok(p) => p.clone(), + Err(e) => { + return print_cli_failure( + Diagnostic::error("invalid_case", "case", e), + json, + ); + } + }; + loaded = match omnigraph_bench::gqt_case::override_sources( + plan, + dataset.as_deref(), + queries.as_deref(), + ) { + Ok(p) => ValidatedCase::Gqt(p), + Err(e) => { + return print_cli_failure( + Diagnostic::error("invalid_case", "sources", e), + json, + ); + } + } + } + let suite = ResolvedSuite { + definition: omnigraph_bench::SuiteV1 { + version: 1, + name: "command-line".into(), + runs: Vec::new(), + }, + suite_path: case.clone(), + runs: vec![ResolvedRun { + case_path: case, + repetitions, + case: loaded, + }], + }; + run_resolved_suite( + suite, + None, + RunOptions { + dataset_cache: Some(dataset_cache), + no_build, + fixture_bindings: fixtures, + worker_executable: std::env::current_exe().ok(), + ..Default::default() + }, + archive, + json, + ) + .await } } } @@ -744,39 +1079,6 @@ async fn run_fixture(command: FixtureCommand) -> ExitCode { inspect_real_graph_fixture(&fixture, scratch_root.as_deref(), Some(&reference), json) .await } - FixtureCommand::RunGraph { - spec, - reference, - fixture, - scratch_root, - json, - } => { - let spec = match load_real_graph_run_spec(&spec).into_result() { - Ok(spec) => spec, - Err(diagnostics) => return print_cli_failures(diagnostics, json), - }; - let reference = match load_fixture_reference(&reference).into_result() { - Ok(reference) => reference, - Err(diagnostics) => return print_cli_failures(diagnostics, json), - }; - match execute_real_graph_run(&spec, &reference, &fixture, scratch_root.as_deref()).await - { - Ok(report) => { - if json { - print_json_success(&report) - } else { - println!( - "FinGraph diagnostic: p50={}us over {} repetitions; claim-eligible=false, durable-record=false", - report.p50_us, report.repetitions - ); - ExitCode::SUCCESS - } - } - Err(error) => { - print_cli_failure(Diagnostic::error(error.code, "$", error.message), json) - } - } - } } } @@ -903,24 +1205,87 @@ async fn run_suite(command: SuiteCommand) -> ExitCode { } } SuiteCommand::Plan { file, case, json } => plan_suite(&file, case.as_deref(), json), - SuiteCommand::Run { - file, - case, - scratch_root, - archive, - json, - } => { - run_suite_execution( - &file, - case.as_deref(), - RunOptions { - scratch_root, - worker_executable: std::env::current_exe().ok(), - }, + SuiteCommand::Run(args) => { + let SuiteRunArgs { + file, + case, + scratch_root, + dataset_cache, + no_build, + fixtures, archive, json, - ) - .await + dataset, + queries, + measured_step, + measured_text, + repetitions, + deadline_seconds, + filesystem, + } = *args; + let options = RunOptions { + scratch_root, + dataset_cache: dataset_cache.or_else(|| Some(PathBuf::from("target/gqt-datasets"))), + no_build, + fixture_bindings: fixtures, + worker_executable: std::env::current_exe().ok(), + }; + if let Some(file) = file { + return run_suite_execution(&file, case.as_deref(), options, archive, json).await; + } + let (Some(dataset), Some(queries), Some(ordinal), Some(text)) = + (dataset, queries, measured_step, measured_text) + else { + return print_cli_failure( + Diagnostic::error( + "missing_gqt_pair", + "suite run", + "supply a suite path or --dataset, --queries, --measured-step and --measured-text", + ), + json, + ); + }; + if case.is_some() { + return print_cli_failure( + Diagnostic::error( + "invalid_selector", + "--case", + "case selectors require a suite path", + ), + json, + ); + } + let (backend, reset) = local_backend(filesystem.as_deref()); + let plan = match omnigraph_bench::gqt_case::explicit_pair( + &dataset, + &queries, + omnigraph_bench::gqt_case::MeasuredStep { ordinal, text }, + backend, + reset, + Some(deadline_seconds.unwrap_or(60)), + ) { + Ok(p) => p, + Err(e) => { + return print_cli_failure( + Diagnostic::error("invalid_gqt_pair", "suite run", e), + json, + ); + } + }; + let suite = ResolvedSuite { + definition: omnigraph_bench::SuiteV1 { + version: 1, + name: "explicit-pair".into(), + runs: Vec::new(), + }, + suite_path: queries.clone(), + runs: vec![ResolvedRun { + case_path: queries, + repetitions: repetitions.unwrap_or(5), + case: ValidatedCase::Gqt(plan), + }], + }; + run_resolved_suite(suite, None, options, archive, json).await } } } @@ -928,16 +1293,10 @@ async fn run_suite(command: SuiteCommand) -> ExitCode { fn print_case_validation(file: &Path, outcome: ValidationOutcome) -> ExitCode { match outcome.into_result() { Ok(case) => { - println!( - "valid case {} {} ({})", - case.definition.id, case.point_id, case.point_name - ); + println!("valid case {} ({})", case.id(), file.display()); ExitCode::SUCCESS } - Err(diagnostics) => { - eprintln!("invalid case {}", file.display()); - print_diagnostics(&diagnostics) - } + Err(e) => print_diagnostics(&e), } } @@ -993,7 +1352,7 @@ fn list_cases(directory: &Path, json: bool) -> ExitCode { print_json_success(&cases) } else { for case in cases { - println!("{} {} {}", case.id, case.point_id, case.path.display()); + println!("{} {:?} {}", case.id, case.point_id, case.path.display()); } ExitCode::SUCCESS } @@ -1043,75 +1402,41 @@ fn case_files(directory: &Path) -> Result, Diagnostic> { } fn duplicate_catalog_diagnostics(cases: &[(&PathBuf, &ValidatedCase)]) -> Vec { - let mut diagnostics = Vec::new(); - let mut ids: BTreeMap<&str, &Path> = BTreeMap::new(); - let mut points: BTreeMap<&str, (&Path, &omnigraph_bench::PointIdentityV1)> = BTreeMap::new(); + let mut ids = BTreeMap::new(); + let mut points = BTreeMap::new(); + let mut out = Vec::new(); for (path, case) in cases { - if let Some(first) = ids.insert(&case.definition.id, path) { - diagnostics.push(Diagnostic::error( + if ids.insert(case.id(), *path).is_some() { + out.push(Diagnostic::error( "duplicate_case_id", path.display().to_string(), - format!( - "case id '{}' is already declared by {}", - case.definition.id, - first.display() - ), - )); + "duplicate case id", + )) } - if let Some((first_path, first_identity)) = - points.insert(&case.point_id, (path, &case.identity)) - { - let (code, message) = if first_identity == &case.identity { - ( - "duplicate_point_id", - format!( - "point id '{}' is already declared by {}", - case.point_id, - first_path.display() - ), - ) - } else { - ( - "point_id_collision", - format!( - "point id '{}' has unequal identities in {} and {}", - case.point_id, - first_path.display(), - path.display() - ), - ) - }; - diagnostics.push(Diagnostic::error(code, path.display().to_string(), message)); + if points.insert(case.planned_identity(), *path).is_some() { + out.push(Diagnostic::error( + "duplicate_point_id", + path.display().to_string(), + "duplicate experiment recipe", + )) } } - diagnostics + out } - fn plan_suite(path: &Path, selector: Option<&str>, json: bool) -> ExitCode { let suite = match load_suite(path).into_result() { - Ok(suite) => suite, - Err(diagnostics) => return print_cli_failures(diagnostics, json), + Ok(s) => s, + Err(e) => return print_cli_failures(e, json), }; let selected = match select_runs(&suite, selector) { - Ok(selected) => selected, - Err(diagnostic) => return print_cli_failure(diagnostic, json), + Ok(r) => r, + Err(e) => return print_cli_failure(e, json), }; let plan = Plan { plan_version: PLAN_FORMAT_VERSION, suite: &suite.definition.name, suite_path: &suite.suite_path, - runs: selected - .into_iter() - .map(|run| PlanRun { - case_id: &run.case.definition.id, - case_path: &run.case_path, - repetitions: run.repetitions, - point_id: &run.case.point_id, - point_name: &run.case.point_name, - case_digest: &run.case.case_digest, - identity: &run.case.identity, - }) - .collect(), + runs: selected, }; if json { print_json_success(&plan) @@ -1119,12 +1444,11 @@ fn plan_suite(path: &Path, selector: Option<&str>, json: bool) -> ExitCode { println!("suite {}", plan.suite); for run in plan.runs { println!( - "{} repetitions={} point_id={} case={}", - run.case_id, + "{} repetitions={} dataset-bound-point=pending case={}", + run.case.id(), run.repetitions, - run.point_id, run.case_path.display() - ); + ) } ExitCode::SUCCESS } @@ -1137,7 +1461,7 @@ fn select_runs<'a>( let selected = suite .runs .iter() - .filter(|run| selector.is_none_or(|id| run.case.definition.id == id)) + .filter(|run| selector.is_none_or(|id| run.case.id() == id)) .collect::>(); if let Some(id) = selector && selected.is_empty() @@ -1222,6 +1546,15 @@ async fn run_suite_execution( Ok(suite) => suite, Err(diagnostics) => return print_cli_failures(diagnostics, json), }; + run_resolved_suite(suite, selector, options, archive, json).await +} +async fn run_resolved_suite( + suite: ResolvedSuite, + selector: Option<&str>, + options: RunOptions, + archive: Option, + json: bool, +) -> ExitCode { let selected = match select_runs(&suite, selector) { Ok(selected) => selected, Err(diagnostic) => return print_cli_failure(diagnostic, json), @@ -1252,15 +1585,18 @@ async fn run_suite_execution( .then(|| Vec::with_capacity(selected.len())); let mut receipts = Vec::with_capacity(selected.len()); let mut completed_run_count = 0usize; + let mut bound_points = std::collections::BTreeSet::new(); for run in selected { let invocation = recording.as_ref().map(RecordingContext::begin_invocation); let execution = match execute_run(run, &options).await { Ok(execution) => execution, Err(mut error) => { - let partial_run = error.context.partial_run.as_deref().cloned(); + let partial_run = error.context.gqt_partial_run.as_deref().cloned(); let censored = if let Some(recording) = recording.as_ref() { match classify_censored_prefix( - partial_run.clone(), + partial_run.clone().filter(|partial| { + partial.samples.len() < (partial.requested_repetitions as usize) + }), |partial| partial.samples.len(), error .context @@ -1292,7 +1628,7 @@ async fn run_suite_execution( match recording.publish_censored(run, &partial, invocation, terminal) { Ok(receipt) => { receipts.push(receipt); - error.context.completed_samples.clear(); + error.context.clear_completed_prefix(); error.context.settled_sample = None; } Err(recording_error) => { @@ -1320,6 +1656,16 @@ async fn run_suite_execution( ); } }; + if !bound_points.insert(execution.point_id.clone()) { + return print_cli_failure( + Diagnostic::error( + "duplicate_point_id", + "suite", + "two planned recipes bound to the same dataset point", + ), + json, + ); + } if let Some(recording) = &recording { let invocation = invocation.expect("recording context minted an invocation"); match recording.publish(run, &execution, invocation) { @@ -1426,40 +1772,15 @@ fn print_execution(output: &SuiteRunOutput) -> ExitCode { } fn print_run_execution(run: &RunExecution) { - let tail = run.wall_clock.p95_us.map_or_else( - || "p95=unsupported".to_string(), - |value| format!("p95={value}us"), - ); println!( - "{} repetitions={} p50={}us min={}us max={}us {} build={}/cargo-O{} effective-codegen={} fixture_sha256={}", + "{} samples={} p50={}us point={} dataset={} cache_hit={}", run.case_id, - run.wall_clock.observed_repetitions, + run.samples.len(), run.wall_clock.p50_us, - run.wall_clock.min_us, - run.wall_clock.max_us, - tail, - run.build.cargo_profile, - run.build.cargo_opt_level, - if run.build.effective_codegen_options_proved { - "proved" - } else { - "unproved" - }, - run.fixture.stamp.manifest.physical.tree_sha256 + run.point_id, + run.fixture.handoff.summary.logical_content_sha256, + run.dataset_cache_hit ); - let cache_condition = serde_json::to_string(&run.cache_condition) - .unwrap_or_else(|_| "".to_string()); - println!(" cache_condition={cache_condition}"); - for sample in &run.samples { - println!( - " rep={} outcome={} elapsed={}us exact_tables={} exact_rows={}", - sample.repetition, - sample.outcome, - sample.elapsed_us, - sample.verification.tables, - sample.verification.rows - ); - } } #[derive(Debug, Serialize)] @@ -1593,90 +1914,28 @@ impl RecordingContext { fn publish( &self, - run: &ResolvedRun, + _run: &ResolvedRun, execution: &RunExecution, invocation: InvocationIdentityV1, ) -> Result { self.validate_worker_source(execution)?; - let fixture = execution.fixture.stamp.clone(); - let backend = match &run.case.definition.environment.backend { - Backend::LocalFs { - filesystem, - storage_class, - } => ObservedBackendV1::LocalFs { - filesystem: *filesystem, - storage_class: *storage_class, - storage_protocol: execution.environment.storage_protocol.clone(), - probe: execution.environment.probe.to_string(), - }, - Backend::S3 { .. } => { - return Err(RecordingError::new( - "recording_backend_unsupported", - "the local runner cannot produce observed S3 backend identity", - )); - } - }; - let record = build_run_record( - run, - execution, - RecordInputV1 { - invocation, - sut: sut_identity_for_execution(execution).map_err(RecordingError::from_record)?, - backend, - fixture, - }, - ) - .map_err(RecordingError::from_record)?; + let record = omnigraph_bench::gqt_record::build(execution, invocation, None) + .map_err(RecordingError::from_record)?; publish_record(&self.archive_root, &record).map_err(RecordingError::from_archive) } - fn publish_censored( &self, - run: &ResolvedRun, + _run: &ResolvedRun, execution: &RunExecution, invocation: InvocationIdentityV1, terminal: AcquisitionTerminalV1, ) -> Result { self.validate_worker_source(execution)?; - let fixture = execution.fixture.stamp.clone(); - let backend = self.observed_backend(run, execution)?; - let record = build_censored_run_record( - run, - execution, - RecordInputV1 { - invocation, - sut: sut_identity_for_execution(execution).map_err(RecordingError::from_record)?, - backend, - fixture, - }, - terminal, - ) - .map_err(RecordingError::from_record)?; + let record = omnigraph_bench::gqt_record::build(execution, invocation, Some(terminal)) + .map_err(RecordingError::from_record)?; publish_record(&self.archive_root, &record).map_err(RecordingError::from_archive) } - fn observed_backend( - &self, - run: &ResolvedRun, - execution: &RunExecution, - ) -> Result { - match &run.case.definition.environment.backend { - Backend::LocalFs { - filesystem, - storage_class, - } => Ok(ObservedBackendV1::LocalFs { - filesystem: *filesystem, - storage_class: *storage_class, - storage_protocol: execution.environment.storage_protocol.clone(), - probe: execution.environment.probe.to_string(), - }), - Backend::S3 { .. } => Err(RecordingError::new( - "recording_backend_unsupported", - "the local runner cannot produce observed S3 backend identity", - )), - } - } - fn validate_worker_source(&self, execution: &RunExecution) -> Result<(), RecordingError> { // A long-running suite can outlive a checkout change. Revalidate at // the publication boundary, then tie that checked checkout explicitly @@ -1756,9 +2015,7 @@ impl RecordingError { // Keep the failed repetition and containment diagnostics here, but do // not duplicate raw completed samples or suite runs in the nested // acquisition error. - diagnostic.context.completed_runs.clear(); - diagnostic.context.completed_samples.clear(); - diagnostic.context.partial_run = None; + diagnostic.context.clear_completed_prefix(); self.acquisition_failure = Some(Box::new(diagnostic)); self } @@ -1894,6 +2151,53 @@ mod tests { use super::*; + #[test] + fn dataset_and_pair_cli_admit_raw_files_and_refuse_ignored_suite_overrides() { + assert!( + Cli::try_parse_from([ + "bench", + "dataset", + "build", + "dataset.gqt", + "--queries", + "queries.gqt", + "--dataset-cache", + "/cache" + ]) + .is_ok() + ); + assert!( + Cli::try_parse_from([ + "bench", + "suite", + "run", + "--dataset", + "dataset.gqt", + "--queries", + "queries.gqt", + "--measured-step", + "1", + "--measured-text", + "--- restart" + ]) + .is_ok() + ); + for flag in ["--repetitions", "--deadline-seconds", "--filesystem"] { + let value = if flag == "--filesystem" { "xfs" } else { "2" }; + assert!( + Cli::try_parse_from([ + "bench", + "suite", + "run", + "catalog/suites/local-fast", + flag, + value + ]) + .is_err() + ); + } + } + fn assert_json_object_keys(value: &serde_json::Value, expected: &[&str]) { let actual = value .as_object() diff --git a/crates/omnigraph-bench/src/branch_merge.rs b/crates/omnigraph-bench/src/branch_merge.rs index dc30781b7..ed83522ad 100644 --- a/crates/omnigraph-bench/src/branch_merge.rs +++ b/crates/omnigraph-bench/src/branch_merge.rs @@ -7,26 +7,35 @@ //! module varies with a repetition number. use std::error::Error; -use std::fmt::{Display, Formatter, Write as _}; +#[cfg(test)] +use std::fmt::Write as _; +use std::fmt::{Display, Formatter}; +#[cfg(test)] use std::sync::Arc; use arrow_array::{Array, Int32Array, LargeStringArray, RecordBatch, StringArray, StringViewArray}; use arrow_schema::Schema as ArrowSchema; use futures::TryStreamExt; +#[cfg(test)] use omnigraph::Session; use omnigraph::db::{Omnigraph, ReadTarget}; +#[cfg(test)] use omnigraph::loader::LoadMode; +#[cfg(test)] use omnigraph::settings::SessionSettings; +use omnigraph_compiler::SystemColumns; +#[cfg(test)] use omnigraph_compiler::ir::ParamMap; +#[cfg(test)] use omnigraph_compiler::query::ast::Literal; +#[cfg(test)] use omnigraph_compiler::schema::parser::parse_schema; -use omnigraph_compiler::{ - SystemColumns, compile_schema_shape, schema_shape_from_ir, schema_shape_json, -}; +#[cfg(test)] +use omnigraph_compiler::{compile_schema_shape, schema_shape_from_ir, schema_shape_json}; use sha2::{Digest, Sha256}; -use crate::ValidatedCase; -use crate::case::{ +use crate::legacy::case::ValidatedCase; +use crate::legacy::case::{ Aging, Arrival, Backend, ColumnShape, CompactionRecency, Contention, DataProvenance, DeletionHistory, Execution, FixtureBuilderKind, FixturePreparation, MAX_PREPARATION_COMMITS, MAX_PREPARATION_ROWS_PER_COMMIT, NetworkPosition, ReadWriteMix, ResetMode, @@ -42,6 +51,7 @@ const BUILDER_VERSION: u32 = SYNTHETIC_BRANCH_MERGE_BUILDER_VERSION; const SUPPORTED_SEED: u64 = 0; const UPDATE_VALUE: i32 = i32::MAX; const NEW_COHORT: &str = "new"; +#[cfg(test)] const LOGICAL_FIXTURE_DIGEST_DOMAIN: &[u8] = b"omnigraph-bench-logical-fixture-v1\0"; /// The engine's keyed-write limits. Chunks stay at or below half of either @@ -841,6 +851,7 @@ impl<'a> BaseCohort<'a> { enum BranchState { Main, Source, + #[cfg(test)] Target, Merged, } @@ -851,7 +862,12 @@ impl BranchState { } fn has_target_effects(self) -> bool { - matches!(self, Self::Target | Self::Merged) + match self { + Self::Merged => true, + #[cfg(test)] + Self::Target => true, + _ => false, + } } } @@ -874,155 +890,13 @@ pub struct FixtureBuildSummary { /// The returned future drops its engine handle before returning. Callers may /// then digest and freeze the directory without opening the frozen original /// again. -pub async fn initialize_local_fixture( - root_uri: &str, - plan: &BranchMergePlan, -) -> BranchMergeResult { - let preflight = plan.preflight()?; - if root_uri.contains("://") && !root_uri.starts_with("file://") { - return Err(unsupported( - "invocation.root_uri", - format!("local fixture initialization cannot use {root_uri:?}"), - )); - } - let schema = schema_source(plan.tables); - let db = Session::from_defaults( - Arc::new(Omnigraph::init(root_uri, &schema).await.map_err(|error| { - fixture_error(format!("initialize fixture at {root_uri}: {error}")) - })?), - SessionSettings::default(), - ); - let base_load_commits = load_base(&db, plan).await?; - if u64::try_from(base_load_commits).ok() != Some(preflight.base_load_commits) { - return Err(fixture_error(format!( - "builder-v3 base-load recipe drifted: preflight declared {} publications, execution produced {base_load_commits}", - preflight.base_load_commits - ))); - } - let optimized_user_tables = match plan.compaction_recency { - CompactionRecency::Optimized => { - let outcomes = db - .optimize() - .await - .map_err(|error| fixture_error(format!("optimize fixture main branch: {error}")))?; - let intended_keys = (0..plan.node_tables()) - .map(node_table_key) - .chain((0..plan.edge_tables()).map(edge_table_key)); - for key in intended_keys { - let outcome = outcomes - .iter() - .find(|outcome| outcome.type_key == key) - .ok_or_else(|| { - fixture_error(format!( - "optimized fixture returned no outcome for intended user table {key}" - )) - })?; - if outcome.skipped.is_some() - || !outcome.committed - || outcome.fragments_removed == 0 - || outcome.fragments_added == 0 - { - return Err(fixture_error(format!( - "optimized fixture did not productively compact {key}: committed={}, fragments_removed={}, fragments_added={}, skipped={:?}", - outcome.committed, - outcome.fragments_removed, - outcome.fragments_added, - outcome.skipped - ))); - } - } - plan.tables - } - CompactionRecency::NotOptimized => 0, - }; - - prepare_reversible_updates(&db, plan).await?; - - db.branch_create_from(ReadTarget::branch(MAIN_BRANCH), SOURCE_BRANCH) - .await - .map_err(|error| fixture_error(format!("create {SOURCE_BRANCH}: {error}")))?; - db.branch_create_from(ReadTarget::branch(MAIN_BRANCH), TARGET_BRANCH) - .await - .map_err(|error| fixture_error(format!("create {TARGET_BRANCH}: {error}")))?; - - let queries = mutation_queries(plan.diverged_tables); - diverge(&db, SOURCE_BRANCH, Side::Source, plan, &queries).await?; - diverge(&db, TARGET_BRANCH, Side::Target, plan, &queries).await?; - - let schema_shape = verified_schema_shape_json(&db, plan)?; - let mut logical_digest = Sha256::new(); - logical_digest.update(LOGICAL_FIXTURE_DIGEST_DOMAIN); - hash_logical_field( - &mut logical_digest, - b"schema-shape", - schema_shape.as_bytes(), - ); - // Builder v2 declares no secondary indexes. The per-branch verification - // below proves that every node and edge manifest has an empty physical - // index inventory before this declared empty inventory is certified in the - // logical digest. Compaction layout and encoding remain derived state. - hash_logical_field(&mut logical_digest, b"logical-index-inventory", b"[]"); - verify_branch( - &db, - MAIN_BRANCH, - plan, - BranchState::Main, - Some(&mut logical_digest), - ) - .await?; - verify_branch( - &db, - SOURCE_BRANCH, - plan, - BranchState::Source, - Some(&mut logical_digest), - ) - .await?; - verify_branch( - &db, - TARGET_BRANCH, - plan, - BranchState::Target, - Some(&mut logical_digest), - ) - .await?; - let source_history_depth = u64::try_from( - db.list_commits(Some(SOURCE_BRANCH)) - .await - .map_err(|error| fixture_error(format!("list {SOURCE_BRANCH} commits: {error}")))? - .len(), - ) - .map_err(|_| fixture_error("source history depth does not fit u64"))?; - let target_history_depth = u64::try_from( - db.list_commits(Some(TARGET_BRANCH)) - .await - .map_err(|error| fixture_error(format!("list {TARGET_BRANCH} commits: {error}")))? - .len(), - ) - .map_err(|_| fixture_error("target history depth does not fit u64"))?; - if source_history_depth != plan.requested_history_depth - || target_history_depth != plan.requested_history_depth - { - return Err(unsupported( - "fixture.state.history_depth", - format!( - "requested exactly {} reachable commits per branch, but deterministic construction produced {source_history_depth} on {SOURCE_BRANCH} and {target_history_depth} on {TARGET_BRANCH}; builder v3 does not silently pad or squash history; declare the observed depth or revise the versioned deterministic builder contract", - plan.requested_history_depth - ), - )); - } - let logical_content_sha256 = format!("{:x}", logical_digest.finalize()); - - drop(db); - Ok(FixtureBuildSummary { - base_load_commits, - optimized_user_tables, - source_history_depth, - target_history_depth, - logical_content_sha256, - }) -} +#[cfg(test)] +#[path = "legacy/branch_merge_oracle.rs"] +mod oracle; +#[cfg(test)] +pub use oracle::initialize_local_fixture; +#[cfg(test)] fn verified_schema_shape_json(db: &Omnigraph, plan: &BranchMergePlan) -> BranchMergeResult { let catalog = db.catalog(); let accepted_ir = catalog.bound_schema_ir().ok_or_else(|| { @@ -1371,6 +1245,7 @@ pub struct VerificationSummary { pub rows: u64, } +#[cfg(test)] fn schema_source(tables: usize) -> String { debug_assert!(tables >= 2 && tables.is_multiple_of(2)); let node_tables = tables / 2; @@ -1397,6 +1272,7 @@ fn schema_source(tables: usize) -> String { source } +#[cfg(test)] fn mutation_queries(diverged_tables: usize) -> String { let mut source = String::new(); for table in 0..diverged_tables { @@ -1438,6 +1314,7 @@ fn insert_edge_id(side: Side, table: usize, row: usize) -> String { format!("{}_e{table:03}_n{row:07}", side.tag()) } +#[cfg(test)] fn jsonl_node_row(ty: &str, name: &str, cohort: &str, val: i32, payload: &str) -> String { serde_json::json!({ "type": ty, @@ -1451,6 +1328,7 @@ fn jsonl_node_row(ty: &str, name: &str, cohort: &str, val: i32, payload: &str) - .to_string() } +#[cfg(test)] fn jsonl_edge_row( ty: &str, id: &str, @@ -1483,6 +1361,7 @@ fn edge_endpoints(plan: &BranchMergePlan, table: usize, row: usize) -> (String, ) } +#[cfg(test)] async fn load_base(db: &Session, plan: &BranchMergePlan) -> BranchMergeResult { let payload = "x".repeat(plan.payload_bytes); let chunk_rows = load_chunk_rows(plan.payload_bytes)?; @@ -1559,6 +1438,7 @@ async fn load_base(db: &Session, plan: &BranchMergePlan) -> BranchMergeResult (usize, usize) { let mut digest = Sha256::new(); digest.update(b"omnigraph-bench-reversible-updates-v1\0"); @@ -1570,6 +1450,7 @@ fn preparation_batch(plan: &BranchMergePlan, seed: u64, pair: u64) -> (usize, us (table as usize, start as usize) } +#[cfg(test)] async fn prepare_reversible_updates(db: &Session, plan: &BranchMergePlan) -> BranchMergeResult<()> { let Some(recipe) = plan.preparation else { return Ok(()); @@ -1637,6 +1518,7 @@ impl Side { } } +#[cfg(test)] async fn diverge( db: &Session, branch: &str, @@ -2379,6 +2261,227 @@ mod tests { } } + fn generated_fixture_source(plan: &BranchMergePlan) -> String { + let source = if plan.diverged_tables == 4 { + include_str!("../../../benchmarks/fixtures/branch_merge_d50.gqt") + .split("--- query branch: main\nquery node_0_main()") + .next() + .unwrap() + .replace("rows: 100000", &format!("rows: {}", plan.rows_per_table)) + .replace( + "\"population\": 100000", + &format!("\"population\": {}", plan.rows_per_table), + ) + .replace( + "commits: 25", + &format!("commits: {}", plan.rows_per_table.div_ceil(4096)), + ) + } else { + include_str!("../../omnigraph-gqt/cases/generated_branch_merge_dataset.gqt").to_string() + }; + let Some(preparation) = plan.preparation else { + return source; + }; + let mut updates = String::new(); + for pair in 0..preparation.additional_commits() / 2 { + let (table, start) = preparation_batch(plan, preparation.seed(), pair); + let ranges = plan.ranges(table).unwrap(); + for restore in [false, true] { + let recipe = serde_json::json!({"tables": [{ + "kind": "edge", "name": edge_type_name(table), + "rows": preparation.rows_per_commit(), "commits": 1, + "start": start, "wrap": plan.rows_per_table, + "id": {"kind": "key", "prefix": format!("e{table:03}_r"), "width": 7}, + "from": {"kind": "endpoint", "prefix": format!("n{table:03}_r"), "width": 7, "population": plan.rows_per_table, "distribution": {"kind": "ordinal"}}, + "to": {"kind": "endpoint", "prefix": format!("n{:03}_r", (table + 1) % plan.node_tables()), "width": 7, "population": plan.rows_per_table, "distribution": {"kind": "ordinal"}}, + "columns": { + "cohort": {"kind": "ranges", "ranges": [ + {"end": ranges.source_updates_end, "value": plan.source_update_cohort}, + {"end": ranges.source_deletes_end, "value": plan.source_delete_cohort}, + {"end": ranges.target_updates_end, "value": plan.target_update_cohort}, + {"end": ranges.target_deletes_end, "value": plan.target_delete_cohort}], "fallback": "keep"}, + "val": {"kind": "ordinal", "start": if restore { 0 } else { -1 }, "step": if restore { 1 } else { -1 }}, + "payload": {"kind": "repeat", "text": "x", "count": plan.payload_bytes} + } + }]}); + writeln!( + updates, + "\n--- load generate: v1 seed: 0 mode: merge\n{}\n--- expect ok", + serde_json::to_string_pretty(&recipe).unwrap() + ) + .unwrap(); + } + } + source.replacen( + "\n--- mutate\nbranch create \"bench-source\"", + &format!("{updates}\n--- mutate\nbranch create \"bench-source\""), + 1, + ) + } + + #[test] + fn checked_in_generated_d50_retains_exact_publication_recipe() { + let source = include_str!("../../../benchmarks/fixtures/branch_merge_d50.gqt"); + let case = omnigraph_gqt_core::parse_case("branch_merge_d50", source).unwrap(); + let omnigraph_gqt_core::Seed::Generated(seed) = &case.fixture.as_ref().unwrap().seed else { + panic!("generated seed required"); + }; + assert_eq!(seed.call_count(), 200); + let steps = case.steps(); + assert_eq!(steps.len(), 50); + assert_eq!( + steps + .iter() + .filter(|step| step.kind == omnigraph_gqt_core::StepKind::Load) + .count(), + 16 + ); + assert_eq!( + steps + .iter() + .filter(|step| step.kind == omnigraph_gqt_core::StepKind::Mutate) + .count(), + 8 + ); + assert_eq!( + steps + .iter() + .filter(|step| step.kind == omnigraph_gqt_core::StepKind::BranchCreate) + .count(), + 2 + ); + let plan = plan(100_000, 4, 50); + assert_eq!( + plan.table_deltas + .iter() + .map(|delta| delta.source.updates) + .collect::>(), + [5, 4, 4, 4] + ); + let seed_body = source + .split_once("--- seed generate: v1 seed: 0\n") + .unwrap() + .1 + .split("\n--- ") + .next() + .unwrap(); + let recipe: serde_json::Value = serde_yaml::from_str(seed_body).unwrap(); + for (table, row) in recipe["tables"] + .as_array() + .unwrap() + .iter() + .skip(4) + .enumerate() + { + let ranges = plan.ranges(table).unwrap(); + let ends = row["columns"]["cohort"]["ranges"] + .as_array() + .unwrap() + .iter() + .map(|range| usize::try_from(range["end"].as_u64().unwrap()).unwrap()) + .collect::>(); + assert_eq!( + ends, + [ + ranges.source_updates_end, + ranges.source_deletes_end, + ranges.target_updates_end, + ranges.target_deletes_end + ] + ); + assert_eq!(row["rows"], 100_000); + assert_eq!(row["commits"], 25); + assert_eq!(row["batch_rows"], 4096); + for ordinal in 0..=ranges.target_deletes_end { + let expected = plan.base_cohort(table, ordinal).label(); + let actual = row["columns"]["cohort"]["ranges"] + .as_array() + .unwrap() + .iter() + .find(|range| u64::try_from(ordinal).unwrap() < range["end"].as_u64().unwrap()) + .map_or( + &row["columns"]["cohort"]["fallback"], + |range| &range["value"], + ); + assert_eq!(actual.as_str().unwrap(), expected); + } + } + } + + #[tokio::test] + async fn generated_dataset_matches_the_legacy_fixture_and_reversible_history() { + for (tables, delta, commits) in [(1, 3, 0), (1, 3, 2), (1, 3, 8), (1, 3, 64), (4, 50, 0)] { + let mut plan = plan(32, tables, delta); + plan.compaction_recency = CompactionRecency::NotOptimized; + plan.requested_history_depth = 1 + u64::try_from(tables * 5).unwrap() + commits; + if commits != 0 { + plan.preparation = Some(preparation(commits, 7, 42)); + } + let old_root = tempfile::tempdir().unwrap(); + let old = initialize_local_fixture(old_root.path().to_str().unwrap(), &plan) + .await + .unwrap(); + let case = omnigraph_gqt_core::parse_case( + "generated_branch_merge_dataset", + &generated_fixture_source(&plan), + ) + .unwrap(); + let fixture = case.fixture.as_ref().unwrap(); + let directory = tempfile::tempdir().unwrap(); + let uri = directory.path().to_str().unwrap(); + let session = Session::from_defaults( + Arc::new(Omnigraph::init(uri, &fixture.schema).await.unwrap()), + SessionSettings::default(), + ); + omnigraph_gqt_core::seed_case(&session, &fixture.seed, case.needs_indices) + .await + .unwrap(); + let db = omnigraph_gqt_core::execute_steps( + &case, + std::path::Path::new("unused.gqt"), + false, + session, + uri, + None, + &omnigraph_gqt_core::PlainHost, + ) + .await + .unwrap(); + let mut digest = Sha256::new(); + digest.update(LOGICAL_FIXTURE_DIGEST_DOMAIN); + hash_logical_field( + &mut digest, + b"schema-shape", + verified_schema_shape_json(&db, &plan).unwrap().as_bytes(), + ); + hash_logical_field(&mut digest, b"logical-index-inventory", b"[]"); + for (branch, state) in [ + (MAIN_BRANCH, BranchState::Main), + (SOURCE_BRANCH, BranchState::Source), + (TARGET_BRANCH, BranchState::Target), + ] { + verify_branch(&db, branch, &plan, state, Some(&mut digest)) + .await + .unwrap(); + } + assert_eq!( + format!("{:x}", digest.finalize()), + old.logical_content_sha256 + ); + assert_eq!( + db.list_commits(Some(SOURCE_BRANCH)).await.unwrap().len() as u64, + old.source_history_depth + ); + assert_eq!( + db.list_commits(Some(TARGET_BRANCH)).await.unwrap().len() as u64, + old.target_history_depth + ); + let protected = capture_protected_branch_heads(&db).await.unwrap(); + db.branch_merge(SOURCE_BRANCH, TARGET_BRANCH).await.unwrap(); + verify_merged_graph(&db, &plan, &protected).await.unwrap(); + } + } + #[test] fn delta_split_is_total_and_always_update_bearing() { for delta in [1, 2, 3, 50, 5_000] { @@ -2505,7 +2608,7 @@ mod tests { additional_commits: commits, rows_per_commit: rows, seed, - maintenance: crate::case::PreparationMaintenance::None, + maintenance: crate::legacy::case::PreparationMaintenance::None, } } diff --git a/crates/omnigraph-bench/src/case.rs b/crates/omnigraph-bench/src/case.rs index 49418ae17..f29f88a16 100644 --- a/crates/omnigraph-bench/src/case.rs +++ b/crates/omnigraph-bench/src/case.rs @@ -1,1712 +1,117 @@ -use std::path::Path; - -use serde::{Deserialize, Deserializer, Serialize}; - -use crate::model::{ - Diagnostic, ValidationOutcome, declared_version, read_yaml_file, strict_yaml, typed_sha256, - valid_kebab_id, +//! Strict scenario dispatch. Historical definitions remain readable; new runs use GQT. +pub use crate::legacy::case::{ + Attribution, Backend, CacheCondition, EnginePreparation, LocalFilesystem, LocalStorageClass, + PageCacheCondition, ProcessLifecycle, Protocol, ResetMode, S3Implementation, S3Versioning, + Schedule, Timer, WarmupProgram, }; -use crate::{CASE_FORMAT_VERSION, POINT_IDENTITY_VERSION}; - -// Planning rejects configurations that a bounded runner could not reasonably -// materialize. These ceilings sit well above the RFC's large-scale points but -// prevent a syntactically valid file from asking a future runner to iterate or -// allocate near integer limits before its invocation budget can intervene. -const MAX_TABLES: u64 = 10_000; -const MAX_ROWS_PER_TABLE: u64 = 1_000_000_000; -const MAX_TOTAL_ROWS: u64 = 10_000_000_000; -const MAX_PAYLOAD_BYTES_PER_ROW: u64 = 64 * 1024 * 1024; -const MAX_LOGICAL_PAYLOAD_BYTES: u64 = 1 << 50; -const MAX_HISTORY_DEPTH: u64 = 1_000_000; -pub(crate) const MAX_WARMUP_ITERATIONS: u32 = 1_000; -const MAX_DEADLINE_SECONDS: u64 = 3_600; -pub(crate) const SYNTHETIC_BRANCH_MERGE_BUILDER_VERSION: u32 = 3; -pub(crate) const MAX_PREPARATION_COMMITS: u64 = 10_000; -pub(crate) const MAX_PREPARATION_ROWS_PER_COMMIT: u64 = 4_096; - -/// A complete V1 branch-merge experiment. `id` is a human selector only. +use crate::model::{Diagnostic, ValidationOutcome}; +use serde::{Deserialize, Serialize}; +use std::path::Path; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct CaseV1 { - pub version: u32, - pub id: String, - pub scenario: Scenario, - pub fixture: Fixture, - pub workload: Workload, - pub environment: Environment, - pub protocol: Protocol, +#[serde(untagged)] +pub enum CaseV1 { + Gqt(crate::gqt_case::GqtCaseV1), + BranchMerge(crate::legacy::case::CaseV1), } - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -pub enum Scenario { - #[serde(rename = "branch-merge-v1")] - BranchMergeV1, +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[serde(tag = "state", rename_all = "kebab-case")] +pub enum ValidatedCase { + Gqt(crate::gqt_case::PlannedGqt), + Legacy(crate::legacy::case::ValidatedCase), } - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Fixture { - pub builder: FixtureBuilder, - pub data: Data, - pub state: State, - /// Optional, independently versioned preparation. Omitting this field must - /// preserve the canonical bytes of every existing builder-v3 point. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub preparation: Option, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(tag = "kind", deny_unknown_fields)] -pub enum FixturePreparation { - #[serde(rename = "reversible-updates-v1")] - ReversibleUpdatesV1 { - additional_commits: u64, - rows_per_commit: u64, - seed: u64, - maintenance: PreparationMaintenance, - }, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum PreparationMaintenance { - None, +#[serde(untagged)] +pub enum PointIdentityV1 { + Gqt(crate::gqt_case::GqtPointIdentityV1), + BranchMerge(crate::legacy::case::PointIdentityV1), } - -impl FixturePreparation { - pub fn additional_commits(self) -> u64 { +impl ValidatedCase { + pub fn id(&self) -> &str { match self { - Self::ReversibleUpdatesV1 { - additional_commits, .. - } => additional_commits, + Self::Gqt(c) => &c.definition.id, + Self::Legacy(c) => &c.definition.id, } } - - pub fn rows_per_commit(self) -> u64 { + pub fn case_digest(&self) -> &str { match self { - Self::ReversibleUpdatesV1 { - rows_per_commit, .. - } => rows_per_commit, + Self::Gqt(c) => &c.case_digest, + Self::Legacy(c) => &c.case_digest, } } - - pub fn seed(self) -> u64 { + pub fn planned_identity(&self) -> &str { match self { - Self::ReversibleUpdatesV1 { seed, .. } => seed, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct FixtureBuilder { - pub kind: FixtureBuilderKind, - pub version: u32, - pub seed: u64, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -pub enum FixtureBuilderKind { - #[serde(rename = "synthetic-branch-merge")] - SyntheticBranchMerge, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Data { - pub provenance: DataProvenance, - pub tables: u64, - pub rows_per_table: u64, - pub payload_bytes: u64, - pub column_shape: ColumnShape, - pub topology_skew: TopologySkew, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum DataProvenance { - Synthetic, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum ColumnShape { - Scalars, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum TopologySkew { - Uniform, - PowerLaw, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct State { - pub aging: Aging, - /// Structured index inventory. Empty means no indexes. Each entry names - /// the exact table/column, index mechanism, and current coverage state, so - /// adding indexed cases never requires replacing a lossy global tag. - pub indexes: Vec, - pub deletion_history: DeletionHistory, - pub compaction_recency: CompactionRecency, - pub history_depth: u64, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum Aging { - BulkLoaded, - SmallCommits, -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct IndexSpec { - pub table: String, - pub column: String, - pub kind: IndexKind, - pub freshness: IndexFreshness, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum IndexKind { - Btree, - Fts, - Ann, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum IndexFreshness { - Optimized, - RowsStale, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum DeletionHistory { - None, - Heavy, - ReversibleUpdates, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum CompactionRecency { - Optimized, - NotOptimized, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Workload { - pub delta_rows_per_side: u64, - pub diverged_tables: u64, - pub arrival: Arrival, - pub clients: u32, - pub read_write_mix: ReadWriteMix, - pub contention: Contention, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum Arrival { - UnscheduledSingleShot, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum ReadWriteMix { - ReadHeavy, - Balanced, - WriteHeavy, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum Contention { - NotApplicable, - SameKey, - DistinctKey, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Environment { - pub backend: Backend, - pub network_position: NetworkPosition, - pub execution: Execution, - pub cache_condition: CacheCondition, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] -#[serde(tag = "kind", rename_all = "kebab-case")] -pub enum Backend { - LocalFs { - filesystem: LocalFilesystem, - storage_class: LocalStorageClass, - }, - S3 { - implementation: S3Implementation, - implementation_version: String, - region: String, - storage_class: String, - versioning: S3Versioning, - image_digest: Option, - }, -} - -// Serde's internally tagged enum decoder accepts extra fields on a unit -// variant. Decode through strict variant DTOs so `{ kind: local-fs, ... }` -// cannot smuggle S3 or future identity fields into a local point. -impl<'de> Deserialize<'de> for Backend { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - match BackendWire::deserialize(deserializer)? { - BackendWire::Local(LocalBackendWire { - kind: LocalBackendKind::LocalFs, - filesystem, - storage_class, - }) => Ok(Self::LocalFs { - filesystem, - storage_class, - }), - BackendWire::S3(S3BackendWire { - kind: S3BackendKind::S3, - implementation, - implementation_version, - region, - storage_class, - versioning, - image_digest, - }) => Ok(Self::S3 { - implementation, - implementation_version, - region, - storage_class, - versioning, - image_digest, - }), + Self::Gqt(c) => &c.planned_sha256, + Self::Legacy(c) => &c.point_id, } } -} - -#[derive(Deserialize)] -#[serde(untagged)] -enum BackendWire { - Local(LocalBackendWire), - S3(S3BackendWire), -} - -#[derive(Deserialize)] -#[serde(deny_unknown_fields)] -struct LocalBackendWire { - kind: LocalBackendKind, - filesystem: LocalFilesystem, - storage_class: LocalStorageClass, -} - -#[derive(Deserialize)] -enum LocalBackendKind { - #[serde(rename = "local-fs")] - LocalFs, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum LocalFilesystem { - Apfs, - Ext4, - Xfs, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum LocalStorageClass { - NvmeSsd, - SataSsd, - NetworkBlock, - RamDisk, -} - -#[derive(Deserialize)] -#[serde(deny_unknown_fields)] -struct S3BackendWire { - kind: S3BackendKind, - implementation: S3Implementation, - implementation_version: String, - region: String, - storage_class: String, - versioning: S3Versioning, - #[serde(default)] - image_digest: Option, -} - -#[derive(Deserialize)] -enum S3BackendKind { - #[serde(rename = "s3")] - S3, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum S3Implementation { - AwsS3, - Minio, - Rustfs, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum S3Versioning { - Enabled, - Disabled, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum NetworkPosition { - SameHost, - SameRegion, - Remote, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum Execution { - Embedded, - Server, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct CacheCondition { - pub process: ProcessLifecycle, - pub engine: EnginePreparation, - pub page_cache: PageCacheCondition, - pub program: WarmupProgram, - pub iterations: u32, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum ProcessLifecycle { - FreshPerRepetition, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum EnginePreparation { - PreparationOnly, - WarmedByProgram, - ReopenedAfterProgram, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum PageCacheCondition { - Uncontrolled, - ProgramConditioned, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum WarmupProgram { - None, - BranchMergeReadSetV1, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Protocol { - /// Measured-operation deadline. An explicit YAML `null` means no - /// measurement deadline; the runner's independent supervisor watchdog - /// remains bounded either way. - #[serde(deserialize_with = "deserialize_required_optional_deadline")] - pub deadline_seconds: Option, - pub attribution: Attribution, - pub schedule: Schedule, - pub reset: ResetMode, - pub timer: Timer, -} - -fn deserialize_required_optional_deadline<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - Option::::deserialize(deserializer) -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum Attribution { - PerPhase, - Off, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum Schedule { - Manual, - Earned, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum ResetMode { - PlainCopy, - LocalClonefile, - S3Versioning, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum Timer { - Monotonic, -} - -/// Deterministic source/target change mix for `branch-merge-v1`. -/// -/// Fixture admission and fixture construction must use this one definition so -/// the capacity proof cannot drift from the rows the builder actually writes. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) struct BranchMergeChangeMix { - pub updates: u64, - pub deletes: u64, - pub inserts: u64, -} - -pub(crate) fn branch_merge_change_mix(delta: u64) -> BranchMergeChangeMix { - let updates = delta.div_ceil(3); - let remaining = delta - updates; - let deletes = remaining.div_ceil(2); - BranchMergeChangeMix { - updates, - deletes, - inserts: remaining - deletes, - } -} - -/// Versioned, canonical point identity. It deliberately has no case id, -/// source path, suite, or repetition quantity. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct PointIdentityV1 { - pub identity_version: u32, - pub scenario: Scenario, - pub fixture: Fixture, - pub workload: Workload, - pub environment: Environment, - pub protocol: Protocol, -} - -impl From<&CaseV1> for PointIdentityV1 { - fn from(case: &CaseV1) -> Self { - Self { - identity_version: POINT_IDENTITY_VERSION, - scenario: case.scenario, - fixture: case.fixture.clone(), - workload: case.workload.clone(), - environment: case.environment.clone(), - protocol: case.protocol.clone(), + pub fn point_id(&self) -> Option<&str> { + match self { + Self::Gqt(_) => None, + Self::Legacy(c) => Some(&c.point_id), } } -} - -/// A strict, semantically valid case plus its two distinct digests. -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] -pub struct ValidatedCase { - pub definition: CaseV1, - pub identity: PointIdentityV1, - /// Full SHA-256 of [`PointIdentityV1`], the experiment's natural key. - pub point_id: String, - /// Full SHA-256 of the complete typed case, including format version/id. - pub case_digest: String, - /// Human-readable convenience label. Never use this as identity. - pub point_name: String, -} - -/// Parse and semantically validate one case-v1 YAML document. -pub fn parse_case(source: &str) -> ValidationOutcome { - let version = match declared_version(source, "case") { - Ok(version) => version, - Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), - }; - if version != CASE_FORMAT_VERSION { - return ValidationOutcome::failure(vec![Diagnostic::error( - "unsupported_case_version", - "version", - format!( - "unsupported case version {version}; this build supports version {CASE_FORMAT_VERSION}" - ), - )]); - } - let definition: CaseV1 = match strict_yaml(source, "case") { - Ok(case) => case, - Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), - }; - validate_case(definition) -} - -/// Read, parse, and semantically validate one case-v1 YAML file. -pub fn load_case(path: &Path) -> ValidationOutcome { - let source = match read_yaml_file(path, "case") { - Ok(source) => source, - Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), - }; - parse_case(&source) -} - -/// Check cross-field invariants and derive stable identities. -pub fn validate_case(mut definition: CaseV1) -> ValidationOutcome { - normalize_identity_strings(&mut definition); - let mut diagnostics = Vec::new(); - if definition.version != CASE_FORMAT_VERSION { - diagnostics.push(Diagnostic::error( - "unsupported_case_version", - "version", - format!( - "unsupported case version {}; this build supports version {CASE_FORMAT_VERSION}", - definition.version - ), - )); - } - if !valid_kebab_id(&definition.id) || definition.id.len() > 128 { - diagnostics.push(Diagnostic::error( - "invalid_case_id", - "id", - "case id must be 1..=128 characters of kebab-case ASCII ([a-z0-9]+(?:-[a-z0-9]+)*)", - )); - } - if definition.fixture.builder.version != SYNTHETIC_BRANCH_MERGE_BUILDER_VERSION { - diagnostics.push(Diagnostic::error( - "unsupported_builder_version", - "fixture.builder.version", - format!( - "synthetic-branch-merge builder version {} is unsupported; this build supports version {SYNTHETIC_BRANCH_MERGE_BUILDER_VERSION}", - definition.fixture.builder.version, + pub fn gqt(&self) -> Result<&crate::gqt_case::PlannedGqt, String> { + match self { + Self::Gqt(c) => Ok(c), + Self::Legacy(_) => Err( + "branch-merge-v1 execution is retired; migrate the authored case to gqt-v1".into(), ), - )); - } - validate_fixture_scale(&definition.fixture, &mut diagnostics); - if definition.fixture.data.topology_skew != TopologySkew::Uniform { - diagnostics.push(Diagnostic::error( - "unsupported_branch_merge_topology", - "fixture.data.topology_skew", - "synthetic branch-merge-v1 currently supports topology_skew: uniform", - )); - } - validate_indexes( - definition.fixture.data.column_shape, - &definition.fixture.state.indexes, - &mut diagnostics, - ); - validate_fixture_state(&definition.fixture, &mut diagnostics); - validate_workload(&definition, &mut diagnostics); - validate_cache_condition(&definition.environment.cache_condition, &mut diagnostics); - validate_backend_protocol(&definition, &mut diagnostics); - - if !diagnostics.is_empty() { - return ValidationOutcome::failure(diagnostics); - } - - // Inventory order is presentation, not experiment identity. Normalize it - // before producing either typed digest so two authors listing the same - // indexes in a different order still name one point. - definition.fixture.state.indexes.sort(); - let identity = PointIdentityV1::from(&definition); - let point_id = match typed_sha256(&identity) { - Ok(digest) => digest, - Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), - }; - let case_digest = match typed_sha256(&definition) { - Ok(digest) => digest, - Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), - }; - let short = &point_id[..12]; - let point_name = format!( - "branch-merge-t{}-n{}-d{}-{}-{short}", - definition.fixture.data.tables, - definition.fixture.data.rows_per_table, - definition.workload.delta_rows_per_side, - definition.environment.cache_condition.display_label(), - ); - ValidationOutcome::success(ValidatedCase { - definition, - identity, - point_id, - case_digest, - point_name, - }) -} - -fn normalize_identity_strings(case: &mut CaseV1) { - for index in &mut case.fixture.state.indexes { - index.table = index.table.trim().to_owned(); - index.column = index.column.trim().to_owned(); - } - if let Backend::S3 { - implementation_version, - region, - storage_class, - .. - } = &mut case.environment.backend - { - *implementation_version = implementation_version.trim().to_owned(); - *region = region.trim().to_owned(); - *storage_class = storage_class.trim().to_owned(); - } -} - -impl CacheCondition { - fn display_label(&self) -> &'static str { - match self.engine { - EnginePreparation::PreparationOnly => "process-cold", - EnginePreparation::WarmedByProgram => "warm", - EnginePreparation::ReopenedAfterProgram => "post-reopen", } } } - -fn validate_workload(case: &CaseV1, diagnostics: &mut Vec) { - let data = &case.fixture.data; - let workload = &case.workload; - let edge_tables = data.tables / 2; - if workload.delta_rows_per_side == 0 { - diagnostics.push(Diagnostic::error( - "invalid_delta", - "workload.delta_rows_per_side", - "delta_rows_per_side must be >= 1", - )); - } - if workload.diverged_tables == 0 || workload.diverged_tables > edge_tables { - diagnostics.push(Diagnostic::error( - "invalid_diverged_tables", - "workload.diverged_tables", - format!( - "builder v3 diverges edge tables and requires diverged_tables between 1 and the fixture's {edge_tables} edge tables" - ), - )); - } - if workload.clients != 1 { - diagnostics.push(Diagnostic::error( - "unsupported_branch_merge_clients", - "workload.clients", - "branch-merge-v1 is an unscheduled single-shot workload and requires clients: 1", - )); - } - if workload.read_write_mix != ReadWriteMix::WriteHeavy { - diagnostics.push(Diagnostic::error( - "unsupported_branch_merge_read_write_mix", - "workload.read_write_mix", - "branch-merge-v1 measures one client-visible write and requires read_write_mix: write-heavy", - )); - } - if workload.contention != Contention::DistinctKey { - diagnostics.push(Diagnostic::error( - "unsupported_branch_merge_contention", - "workload.contention", - "branch-merge-v1 uses disjoint source/target cohorts and requires contention: distinct-key", - )); - } - - // The builder pre-tags separate source/target update and delete cohorts in - // each diverged edge table. Prove the busiest table can hold those rows without - // overflow rather than letting fixture construction fail much later. - if workload.delta_rows_per_side > 0 - && workload.diverged_tables > 0 - && workload.diverged_tables <= edge_tables - { - let change_mix = branch_merge_change_mix(workload.delta_rows_per_side); - let per_table = change_mix - .updates - .div_ceil(workload.diverged_tables) - .checked_add(change_mix.deletes.div_ceil(workload.diverged_tables)) - .and_then(|rows| rows.checked_mul(2)); - match per_table { - Some(required) if required <= data.rows_per_table => {} - Some(required) => diagnostics.push(Diagnostic::error( - "fixture_cohort_capacity_exceeded", - "workload.delta_rows_per_side", +pub fn parse_case(source: &str) -> ValidationOutcome { + match crate::model::declared_version(source, "case") { + Ok(crate::CASE_FORMAT_VERSION) => {} + Ok(version) => { + return ValidationOutcome::failure(vec![Diagnostic::error( + "unsupported_case_version", + "version", format!( - "the branch-merge cohorts need {required} base rows in the busiest table, but rows_per_table is {}", - data.rows_per_table + "unsupported case version {version}; expected {}", + crate::CASE_FORMAT_VERSION ), - )), - None => diagnostics.push(Diagnostic::error( - "fixture_cohort_capacity_overflow", - "workload.delta_rows_per_side", - "branch-merge cohort sizing overflowed u64", - )), - } - } -} - -fn validate_fixture_scale(fixture: &Fixture, diagnostics: &mut Vec) { - let data = &fixture.data; - if !(1..=MAX_TABLES).contains(&data.tables) { - diagnostics.push(Diagnostic::error( - "invalid_table_count", - "fixture.data.tables", - format!("table count must be in 1..={MAX_TABLES}"), - )); - } - if data.tables < 2 || !data.tables.is_multiple_of(2) { - diagnostics.push(Diagnostic::error( - "invalid_graph_table_mix", - "fixture.data.tables", - "synthetic-branch-merge builder v3 requires an even total table count >= 2, split equally between node and edge tables", - )); - } - if !(1..=MAX_ROWS_PER_TABLE).contains(&data.rows_per_table) { - diagnostics.push(Diagnostic::error( - "invalid_row_count", - "fixture.data.rows_per_table", - format!("rows_per_table must be in 1..={MAX_ROWS_PER_TABLE}"), - )); - } - if data.payload_bytes > MAX_PAYLOAD_BYTES_PER_ROW { - diagnostics.push(Diagnostic::error( - "invalid_payload_size", - "fixture.data.payload_bytes", - format!("payload_bytes must be <= {MAX_PAYLOAD_BYTES_PER_ROW}"), - )); - } - if !(1..=MAX_HISTORY_DEPTH).contains(&fixture.state.history_depth) { - diagnostics.push(Diagnostic::error( - "invalid_history_depth", - "fixture.state.history_depth", - format!("history_depth must be in 1..={MAX_HISTORY_DEPTH}"), - )); - } - - match data.tables.checked_mul(data.rows_per_table) { - Some(total_rows) if total_rows > MAX_TOTAL_ROWS => diagnostics.push(Diagnostic::error( - "fixture_row_budget_exceeded", - "fixture.data", - format!("tables * rows_per_table must be <= {MAX_TOTAL_ROWS}, got {total_rows}"), - )), - Some(total_rows) => match total_rows.checked_mul(data.payload_bytes) { - Some(total_bytes) if total_bytes > MAX_LOGICAL_PAYLOAD_BYTES => { - diagnostics.push(Diagnostic::error( - "fixture_payload_budget_exceeded", - "fixture.data", - format!( - "logical payload must be <= {MAX_LOGICAL_PAYLOAD_BYTES} bytes, got {total_bytes}" - ), - )); - } - Some(_) => {} - None => diagnostics.push(Diagnostic::error( - "fixture_payload_size_overflow", - "fixture.data", - "tables * rows_per_table * payload_bytes overflowed u64", - )), - }, - None => diagnostics.push(Diagnostic::error( - "fixture_row_count_overflow", - "fixture.data", - "tables * rows_per_table overflowed u64", - )), - } -} - -fn validate_fixture_state(fixture: &Fixture, diagnostics: &mut Vec) { - if let Some(preparation) = fixture.preparation { - if !(2..=MAX_PREPARATION_COMMITS).contains(&preparation.additional_commits()) - || !preparation.additional_commits().is_multiple_of(2) - { - diagnostics.push(Diagnostic::error( - "invalid_preparation_commits", "fixture.preparation.additional_commits", - format!("reversible updates require an even number of real commits in 2..={MAX_PREPARATION_COMMITS}"), - )); - } - if !(1..=MAX_PREPARATION_ROWS_PER_COMMIT).contains(&preparation.rows_per_commit()) - || preparation.rows_per_commit() > fixture.data.rows_per_table - { - diagnostics.push(Diagnostic::error( - "invalid_preparation_rows", "fixture.preparation.rows_per_commit", - format!("rows_per_commit must be in 1..={MAX_PREPARATION_ROWS_PER_COMMIT} and no greater than rows_per_table"), - )); - } - if fixture.state.aging != Aging::SmallCommits - || fixture.state.deletion_history != DeletionHistory::ReversibleUpdates - || fixture.state.compaction_recency != CompactionRecency::NotOptimized - || !fixture.state.indexes.is_empty() - { - diagnostics.push(Diagnostic::error( - "preparation_state_mismatch", "fixture.state", - "reversible-updates-v1 requires small-commits aging, reversible-updates deletion history, not-optimized compaction, and indexes: []", - )); + )]); } - } else if fixture.state.deletion_history == DeletionHistory::ReversibleUpdates { - diagnostics.push(Diagnostic::error( - "missing_preparation", - "fixture.preparation", - "reversible-updates deletion history requires its preparation recipe", - )); + Err(error) => return ValidationOutcome::failure(vec![error]), } - if fixture.builder.kind == FixtureBuilderKind::SyntheticBranchMerge - && fixture.builder.version == SYNTHETIC_BRANCH_MERGE_BUILDER_VERSION - && fixture.state.compaction_recency == CompactionRecency::Optimized - { - diagnostics.push(Diagnostic::error( - "impossible_optimized_index_state", - "fixture.state.compaction_recency", - "synthetic-branch-merge builder v3 cannot truthfully declare optimized state because OmniGraph optimization materializes indexes outside this builder's exact inventory contract; use not-optimized", - )); + match crate::model::strict_yaml(source, "case") { + Ok(c) => validate_case(c), + Err(e) => ValidationOutcome::failure(vec![e]), } } - -fn validate_indexes( - column_shape: ColumnShape, - indexes: &[IndexSpec], - diagnostics: &mut Vec, -) { - let mut seen = std::collections::BTreeSet::new(); - for (index, spec) in indexes.iter().enumerate() { - if spec.table.trim().is_empty() { - diagnostics.push(Diagnostic::error( - "empty_index_table", - format!("fixture.state.indexes[{index}].table"), - "index table must not be empty", - )); - } - if spec.column.trim().is_empty() { - diagnostics.push(Diagnostic::error( - "empty_index_column", - format!("fixture.state.indexes[{index}].column"), - "index column must not be empty", - )); - } - if !seen.insert((&spec.table, &spec.column, spec.kind)) { - diagnostics.push(Diagnostic::error( - "duplicate_index", - format!("fixture.state.indexes[{index}]"), - format!( - "duplicate {:?} index on {}.{}; freshness is one state of one index", - spec.kind, spec.table, spec.column - ), - )); - } - if column_shape == ColumnShape::Scalars && spec.kind == IndexKind::Ann { - diagnostics.push(Diagnostic::error( - "impossible_index_inventory", - format!("fixture.state.indexes[{index}].kind"), - "ANN indexes require a vector column shape; this case declares column_shape: scalars", - )); - } - } -} - -fn validate_cache_condition(condition: &CacheCondition, diagnostics: &mut Vec) { - let ProcessLifecycle::FreshPerRepetition = condition.process; - if condition.iterations > MAX_WARMUP_ITERATIONS { - diagnostics.push(Diagnostic::error( - "warmup_iteration_budget_exceeded", - "environment.cache_condition.iterations", - format!("warm-up iterations must be <= {MAX_WARMUP_ITERATIONS}"), - )); - } - match condition.engine { - EnginePreparation::PreparationOnly => { - if condition.page_cache != PageCacheCondition::Uncontrolled - || condition.program != WarmupProgram::None - || condition.iterations != 0 - { - diagnostics.push(Diagnostic::error( - "invalid_preparation_only_cache_condition", - "environment.cache_condition", - "preparation-only requires page_cache: uncontrolled, program: none, and iterations: 0", - )); - } - } - EnginePreparation::WarmedByProgram | EnginePreparation::ReopenedAfterProgram => { - if condition.page_cache != PageCacheCondition::ProgramConditioned - || condition.program != WarmupProgram::BranchMergeReadSetV1 - || condition.iterations == 0 - { - diagnostics.push(Diagnostic::error( - "invalid_programmed_cache_condition", - "environment.cache_condition", - "warmed-by-program and reopened-after-program require page_cache: program-conditioned, a named program, and iterations >= 1", - )); - } - } +pub fn validate_case(case: CaseV1) -> ValidationOutcome { + let result = match &case { + CaseV1::Gqt(c) => crate::gqt_case::validate_definition(c), + CaseV1::BranchMerge(c) => crate::legacy::case::validate_case(c.clone()) + .into_result() + .map(|_| ()) + .map_err(|e| format!("{e:?}")), + }; + match result { + Ok(()) => ValidationOutcome::success(case), + Err(e) => refusal(e), } } - -fn valid_sha256_image_digest(value: &str) -> bool { - let Some(hex) = value.strip_prefix("sha256:") else { - return false; +pub fn load_case(path: &Path) -> ValidationOutcome { + let source = match crate::model::read_yaml_file(path, "case") { + Ok(s) => s, + Err(e) => return ValidationOutcome::failure(vec![e]), }; - hex.len() == 64 - && hex - .bytes() - .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) -} - -fn validate_backend_protocol(case: &CaseV1, diagnostics: &mut Vec) { - let environment = &case.environment; - let protocol = &case.protocol; - if let Some(deadline_seconds) = protocol.deadline_seconds { - if !(1..=MAX_DEADLINE_SECONDS).contains(&deadline_seconds) { - diagnostics.push(Diagnostic::error( - "invalid_deadline", - "protocol.deadline_seconds", - format!("deadline_seconds must be null or in 1..={MAX_DEADLINE_SECONDS}"), - )); - } - } - if protocol.schedule != Schedule::Manual { - diagnostics.push(Diagnostic::error( - "unsupported_automatic_schedule", - "protocol.schedule", - "branch-merge-v1 is unscheduled and must use the manual schedule", - )); - } - if protocol.attribution == Attribution::PerPhase && environment.execution != Execution::Embedded - { - diagnostics.push(Diagnostic::error( - "unavailable_phase_attribution", - "protocol.attribution", - "per-phase attribution is currently available only for embedded execution", - )); - } - match &environment.backend { - Backend::LocalFs { filesystem, .. } => { - if environment.network_position != NetworkPosition::SameHost { - diagnostics.push(Diagnostic::error( - "invalid_local_network_position", - "environment.network_position", - "local-fs requires network_position: same-host", - )); - } - if !matches!( - protocol.reset, - ResetMode::PlainCopy | ResetMode::LocalClonefile - ) { - diagnostics.push(Diagnostic::error( - "invalid_local_reset", - "protocol.reset", - "local-fs requires reset: plain-copy or local-clonefile", - )); - } - if protocol.reset == ResetMode::LocalClonefile && *filesystem != LocalFilesystem::Apfs { - diagnostics.push(Diagnostic::error( - "invalid_clonefile_filesystem", - "protocol.reset", - "local-clonefile is the APFS clonefile reset; other filesystems must use plain-copy", - )); - } - } - Backend::S3 { - implementation, - implementation_version, - region, - storage_class, - versioning, - image_digest, - } => { - for (path, value) in [ - ( - "environment.backend.implementation_version", - implementation_version, - ), - ("environment.backend.region", region), - ("environment.backend.storage_class", storage_class), - ] { - if value.trim().is_empty() { - diagnostics.push(Diagnostic::error( - "incomplete_s3_identity", - path, - "S3 backend identity fields must not be empty", - )); - } - } - if *implementation == S3Implementation::AwsS3 - && environment.network_position == NetworkPosition::SameHost - { - diagnostics.push(Diagnostic::error( - "invalid_aws_s3_network_position", - "environment.network_position", - "AWS S3 requires network_position: same-region or remote; same-host is reserved for local compatible stores", - )); - } - if protocol.reset != ResetMode::S3Versioning { - diagnostics.push(Diagnostic::error( - "invalid_s3_reset", - "protocol.reset", - "S3 requires reset: s3-versioning", - )); - } - if *versioning != S3Versioning::Enabled { - diagnostics.push(Diagnostic::error( - "s3_versioning_required", - "environment.backend.versioning", - "s3-versioning reset requires bucket versioning to be enabled", - )); - } - match implementation { - S3Implementation::AwsS3 => { - if image_digest.is_some() { - diagnostics.push(Diagnostic::error( - "forbidden_aws_s3_image_digest", - "environment.backend.image_digest", - "AWS S3 is a managed service identity and must not declare image_digest", - )); - } - } - S3Implementation::Minio | S3Implementation::Rustfs => match image_digest { - None => diagnostics.push(Diagnostic::error( - "missing_s3_image_digest", - "environment.backend.image_digest", - "MinIO and RustFS backend identities require an image_digest", - )), - Some(digest) if !valid_sha256_image_digest(digest) => { - diagnostics.push(Diagnostic::error( - "invalid_s3_image_digest", - "environment.backend.image_digest", - "image_digest must be exactly lowercase sha256:<64hex>", - )); - } - Some(_) => {} - }, - } - } + let case = match parse_case(&source).into_result() { + Ok(c) => c, + Err(e) => return ValidationOutcome::failure(e), + }; + match case { + CaseV1::Gqt(c) => match crate::gqt_case::load(path, c) { + Ok(p) => ValidationOutcome::success(ValidatedCase::Gqt(p)), + Err(e) => refusal(e), + }, + CaseV1::BranchMerge(c) => match crate::legacy::case::validate_case(c).into_result() { + Ok(c) => ValidationOutcome::success(ValidatedCase::Legacy(c)), + Err(e) => ValidationOutcome::failure(e), + }, } } - -#[cfg(test)] -mod tests { - use super::*; - - const VALID: &str = r#" -version: 1 -id: m3-n100k-d50-warm -scenario: branch-merge-v1 -fixture: - builder: - kind: synthetic-branch-merge - version: 3 - seed: 0 - data: - provenance: synthetic - tables: 8 - rows_per_table: 100000 - payload_bytes: 64 - column_shape: scalars - topology_skew: uniform - state: - aging: bulk-loaded - indexes: [] - deletion_history: none - compaction_recency: not-optimized - history_depth: 1 -workload: - delta_rows_per_side: 50 - diverged_tables: 4 - arrival: unscheduled-single-shot - clients: 1 - read_write_mix: write-heavy - contention: distinct-key -environment: - backend: - kind: local-fs - filesystem: apfs - storage_class: nvme-ssd - network_position: same-host - execution: embedded - cache_condition: - process: fresh-per-repetition - engine: warmed-by-program - page_cache: program-conditioned - program: branch-merge-read-set-v1 - iterations: 1 -protocol: - deadline_seconds: 60 - attribution: per-phase - schedule: manual - reset: plain-copy - timer: monotonic -"#; - - fn valid() -> ValidatedCase { - parse_case(VALID).into_result().unwrap() - } - - fn s3_case( - implementation: &str, - implementation_version: &str, - versioning: &str, - image_digest: Option<&str>, - ) -> String { - let image = image_digest - .map(|digest| format!("\n image_digest: {digest}")) - .unwrap_or_default(); - VALID - .replace( - " backend:\n kind: local-fs\n filesystem: apfs\n storage_class: nvme-ssd", - &format!( - " backend:\n kind: s3\n implementation: {implementation}\n implementation_version: {implementation_version}\n region: us-east-1\n storage_class: standard\n versioning: {versioning}{image}" - ), - ) - .replace("network_position: same-host", "network_position: same-region") - .replace("reset: plain-copy", "reset: s3-versioning") - } - - #[test] - fn parses_strict_v1_and_derives_full_distinct_digests() { - let case = valid(); - assert_eq!(case.point_id.len(), 64); - assert_eq!(case.case_digest.len(), 64); - assert_ne!(case.point_id, case.case_digest); - assert!(case.point_name.ends_with(&case.point_id[..12])); - } - - #[test] - fn absent_preparation_preserves_existing_canonical_point_and_case_bytes() { - let case = parse_case(include_str!( - "../../../benchmarks/cases/branch-merge-d50-process-cold-xfs.case-v1.yaml" - )) - .into_result() - .unwrap(); - assert_eq!( - case.point_id, - "3a79a396ccb95f383370f55665136396ed8c83636b3cd08648eb3290c859bc33" - ); - assert_eq!( - case.case_digest, - "0f16aa99402d2359b934cdc3ac478a56bac46ec8ed245662c4e7ea9ce3ff3e7a" - ); - let bytes = serde_json::to_string(&case.definition).unwrap(); - assert!(!bytes.contains("\"preparation\":")); - assert_eq!( - serde_json::from_str::(&bytes).unwrap(), - case.definition - ); - } - - #[test] - fn reversible_preparation_is_strict_bounded_and_identity_bearing() { - let source = VALID.replace("fixture:\n", "fixture:\n preparation: { kind: reversible-updates-v1, additional_commits: 64, rows_per_commit: 7, seed: 42, maintenance: none }\n") - .replace("aging: bulk-loaded", "aging: small-commits") - .replace("deletion_history: none", "deletion_history: reversible-updates") - .replace("history_depth: 1", "history_depth: 277"); - let aged = parse_case(&source).into_result().unwrap(); - assert_eq!( - crate::branch_merge::BranchMergePlan::try_from(&aged) - .unwrap() - .preflight() - .unwrap() - .expected_history_depth, - 277 - ); - for (from, to) in [ - ("additional_commits: 64", "additional_commits: 2"), - ("rows_per_commit: 7", "rows_per_commit: 1"), - ("seed: 42", "seed: 43"), - ] { - let other = parse_case(&source.replace(from, to)).into_result().unwrap(); - assert_ne!(aged.point_id, other.point_id); - } - for (from, to) in [ - ("additional_commits: 64", "additional_commits: 0"), - ("additional_commits: 64", "additional_commits: 3"), - ("additional_commits: 64", "additional_commits: 10002"), - ("rows_per_commit: 7", "rows_per_commit: 0"), - ("rows_per_commit: 7", "rows_per_commit: 4097"), - ("rows_per_table: 100000", "rows_per_table: 6"), - ("reversible-updates-v1", "reversible-updates-v2"), - ("maintenance: none", "maintenance: optimize"), - (", maintenance: none", ""), - (", seed: 42", ""), - ("maintenance: none", "maintenance: none, typo: true"), - ("aging: small-commits", "aging: bulk-loaded"), - ( - "deletion_history: reversible-updates", - "deletion_history: none", - ), - ] { - assert!( - parse_case(&source.replace(from, to)).into_result().is_err(), - "accepted {to}" - ); - } - let without_recipe = VALID.replace( - "deletion_history: none", - "deletion_history: reversible-updates", - ); - assert!(parse_case(&without_recipe).into_result().is_err()); - } - - #[test] - fn case_id_and_yaml_format_do_not_change_point_identity() { - let first = valid(); - let reordered = VALID - .replace("id: m3-n100k-d50-warm", "id: another-id") - .replace( - "rows_per_table: 100000\n payload_bytes: 64", - "payload_bytes: 64\n rows_per_table: 100000", - ) - .replace( - "version: 1\nid:", - "# formatting is not identity\nversion: 1\nid:", - ); - let second = parse_case(&reordered).into_result().unwrap(); - assert_eq!(first.point_id, second.point_id); - assert_ne!(first.case_digest, second.case_digest); - } - - #[test] - fn every_typed_identity_change_moves_the_point_id() { - let first = valid(); - let changed = VALID.replace("payload_bytes: 64", "payload_bytes: 65"); - let second = parse_case(&changed).into_result().unwrap(); - assert_ne!(first.point_id, second.point_id); - } - - #[test] - fn complete_data_and_workload_factors_are_point_identity() { - let base = valid().definition; - let base_id = typed_sha256(&PointIdentityV1::from(&base)).unwrap(); - - let mut topology = base.clone(); - topology.fixture.data.topology_skew = TopologySkew::PowerLaw; - assert_ne!( - base_id, - typed_sha256(&PointIdentityV1::from(&topology)).unwrap() - ); - - let mut mix = base.clone(); - mix.workload.read_write_mix = ReadWriteMix::Balanced; - assert_ne!(base_id, typed_sha256(&PointIdentityV1::from(&mix)).unwrap()); - - let mut contention = base; - contention.workload.contention = Contention::SameKey; - assert_ne!( - base_id, - typed_sha256(&PointIdentityV1::from(&contention)).unwrap() - ); - } - - #[test] - fn branch_merge_requires_supported_complete_factor_levels() { - for (from, to, code) in [ - ( - "topology_skew: uniform", - "topology_skew: power-law", - "unsupported_branch_merge_topology", - ), - ( - "read_write_mix: write-heavy", - "read_write_mix: balanced", - "unsupported_branch_merge_read_write_mix", - ), - ( - "contention: distinct-key", - "contention: same-key", - "unsupported_branch_merge_contention", - ), - ] { - assert!( - parse_case(&VALID.replace(from, to)) - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == code), - "missing {code}" - ); - } - } - - #[test] - fn unknown_fields_and_versions_fail_closed() { - let unknown = VALID.replace("version: 1", "version: 1\nunknown: true"); - assert_eq!( - parse_case(&unknown).diagnostics[0].code, - "invalid_case_yaml" - ); - let future = VALID.replace("version: 1", "version: 2"); - assert_eq!( - parse_case(&future).diagnostics[0].code, - "unsupported_case_version" - ); - let old_builder = - VALID.replace(" version: 3\n seed: 0", " version: 2\n seed: 0"); - assert_eq!( - parse_case(&old_builder).diagnostics[0].code, - "unsupported_builder_version" - ); - let future_builder = - VALID.replace(" version: 3\n seed: 0", " version: 4\n seed: 0"); - assert_eq!( - parse_case(&future_builder).diagnostics[0].code, - "unsupported_builder_version" - ); - let duplicate = VALID.replace("version: 1", "version: 1\nversion: 1"); - assert_eq!( - parse_case(&duplicate).diagnostics[0].code, - "invalid_case_yaml" - ); - let backend_unknown = - VALID.replace("kind: local-fs", "kind: local-fs\n endpoint: surprise"); - assert_eq!( - parse_case(&backend_unknown).diagnostics[0].code, - "invalid_case_yaml" - ); - } - - #[test] - fn index_inventory_is_normalized_before_identity_and_duplicate_checks() { - let first_yaml = VALID.replace( - "indexes: []", - "indexes:\n - { table: n0, column: id, kind: btree, freshness: optimized }\n - { table: n1, column: name, kind: fts, freshness: rows-stale }", - ); - let second_yaml = first_yaml.replace( - " - { table: n0, column: id, kind: btree, freshness: optimized }\n - { table: n1, column: name, kind: fts, freshness: rows-stale }", - " - { table: n1, column: name, kind: fts, freshness: rows-stale }\n - { table: n0, column: id, kind: btree, freshness: optimized }", - ); - let first = parse_case(&first_yaml).into_result().unwrap(); - let second = parse_case(&second_yaml).into_result().unwrap(); - assert_eq!(first.point_id, second.point_id); - assert_eq!(first.case_digest, second.case_digest); - - let padded_yaml = first_yaml - .replace("table: n0", "table: ' n0 '") - .replace("column: id", "column: ' id '"); - let padded = parse_case(&padded_yaml).into_result().unwrap(); - assert_eq!(first.point_id, padded.point_id); - assert_eq!(first.case_digest, padded.case_digest); - - let duplicate = first_yaml.replace( - " - { table: n1, column: name, kind: fts, freshness: rows-stale }", - " - { table: n0, column: id, kind: btree, freshness: rows-stale }", - ); - assert!( - parse_case(&duplicate) - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "duplicate_index") - ); - - let padded_duplicate = first_yaml.replace( - " - { table: n1, column: name, kind: fts, freshness: rows-stale }", - " - { table: ' n0 ', column: ' id ', kind: btree, freshness: rows-stale }", - ); - assert!( - parse_case(&padded_duplicate) - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "duplicate_index") - ); - - let impossible = VALID.replace( - "indexes: []", - "indexes:\n - { table: n0, column: embedding, kind: ann, freshness: optimized }", - ); - assert!( - parse_case(&impossible) - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "impossible_index_inventory") - ); - } - - #[test] - fn builder_v3_rejects_optimized_fixture_state_for_any_index_inventory() { - let optimized = VALID.replace( - "compaction_recency: not-optimized", - "compaction_recency: optimized", - ); - let partial_inventory = optimized.replace( - "indexes: []", - "indexes:\n - { table: n0, column: id, kind: btree, freshness: optimized }", - ); - for yaml in [optimized, partial_inventory] { - let outcome = parse_case(&yaml); - assert!(!outcome.ok); - assert!(outcome.value.is_none()); - assert!(outcome.diagnostics.iter().any(|diagnostic| { - diagnostic.code == "impossible_optimized_index_state" - && diagnostic.path == "fixture.state.compaction_recency" - })); - } - } - - #[test] - fn bounds_and_structured_index_semantics_are_checked_together() { - let invalid = VALID - .replace("rows_per_table: 100000", "rows_per_table: 1") - .replace("diverged_tables: 4", "diverged_tables: 9") - .replace( - "indexes: []", - "indexes:\n - { table: '', column: id, kind: btree, freshness: optimized }", - ); - let codes: Vec<_> = parse_case(&invalid) - .diagnostics - .into_iter() - .map(|diagnostic| diagnostic.code) - .collect(); - assert!(codes.contains(&"invalid_diverged_tables".to_string())); - assert!(codes.contains(&"empty_index_table".to_string())); - } - - #[test] - fn builder_v3_requires_balanced_node_edge_tables_and_edge_divergence() { - for (yaml, code) in [ - ( - VALID.replace("tables: 8", "tables: 1"), - "invalid_graph_table_mix", - ), - ( - VALID.replace("tables: 8", "tables: 7"), - "invalid_graph_table_mix", - ), - ( - VALID.replace("diverged_tables: 4", "diverged_tables: 5"), - "invalid_diverged_tables", - ), - ] { - assert!( - parse_case(&yaml) - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == code), - "missing {code} for {yaml}" - ); - } - } - - #[test] - fn fixture_scale_is_bounded_before_a_runner_sees_the_plan() { - let oversized = VALID - .replace("tables: 8", "tables: 10001") - .replace("rows_per_table: 100000", "rows_per_table: 1000000000") - .replace("payload_bytes: 64", "payload_bytes: 67108864") - .replace("history_depth: 1", "history_depth: 1000001"); - let codes: Vec<_> = parse_case(&oversized) - .diagnostics - .into_iter() - .map(|diagnostic| diagnostic.code) - .collect(); - assert!(codes.contains(&"invalid_table_count".to_string())); - assert!(codes.contains(&"fixture_row_budget_exceeded".to_string())); - assert!(codes.contains(&"invalid_history_depth".to_string())); - - let oversized_payload = VALID - .replace("rows_per_table: 100000", "rows_per_table: 1000000000") - .replace("payload_bytes: 64", "payload_bytes: 67108864"); - assert!( - parse_case(&oversized_payload) - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "fixture_payload_budget_exceeded") - ); - } - - #[test] - fn cache_condition_is_typed_cross_validated_and_identity_bearing() { - let process_cold = VALID - .replace("engine: warmed-by-program", "engine: preparation-only") - .replace( - "page_cache: program-conditioned", - "page_cache: uncontrolled", - ) - .replace("program: branch-merge-read-set-v1", "program: none") - .replace("iterations: 1", "iterations: 0"); - let process_cold = parse_case(&process_cold).into_result().unwrap(); - assert!(process_cold.point_name.contains("process-cold")); - assert_ne!(valid().point_id, process_cold.point_id); - - let post_reopen = VALID.replace( - "engine: warmed-by-program", - "engine: reopened-after-program", - ); - let post_reopen = parse_case(&post_reopen).into_result().unwrap(); - assert!(post_reopen.point_name.contains("post-reopen")); - assert_ne!(valid().point_id, post_reopen.point_id); - - let two_iterations = parse_case(&VALID.replace("iterations: 1", "iterations: 2")) - .into_result() - .unwrap(); - assert_ne!(valid().point_id, two_iterations.point_id); - - let invalid = VALID.replace("engine: warmed-by-program", "engine: preparation-only"); - assert_eq!( - parse_case(&invalid).diagnostics[0].code, - "invalid_preparation_only_cache_condition" - ); - let invalid_warm_page_cache = VALID.replace( - "page_cache: program-conditioned", - "page_cache: uncontrolled", - ); - assert_eq!( - parse_case(&invalid_warm_page_cache).diagnostics[0].code, - "invalid_programmed_cache_condition" - ); - let false_page_cache_claim = VALID.replace( - "page_cache: program-conditioned", - "page_cache: witnessed-evicted", - ); - assert_eq!( - parse_case(&false_page_cache_claim).diagnostics[0].code, - "invalid_case_yaml" - ); - let unsupported = VALID.replace( - "program: branch-merge-read-set-v1", - "program: invented-warmup", - ); - assert_eq!( - parse_case(&unsupported).diagnostics[0].code, - "invalid_case_yaml" - ); - - let unbounded = VALID.replace("iterations: 1", "iterations: 1001"); - assert!( - parse_case(&unbounded) - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "warmup_iteration_budget_exceeded") - ); - } - - #[test] - fn backend_reset_and_identity_semantics_are_checked() { - let invalid = s3_case("aws-s3", "''", "disabled", None) - .replace("reset: s3-versioning", "reset: plain-copy"); - let codes: Vec<_> = parse_case(&invalid) - .diagnostics - .into_iter() - .map(|diagnostic| diagnostic.code) - .collect(); - assert!(codes.contains(&"incomplete_s3_identity".to_string())); - assert!(codes.contains(&"invalid_s3_reset".to_string())); - assert!(codes.contains(&"s3_versioning_required".to_string())); - - let invalid_clonefile = VALID - .replace("filesystem: apfs", "filesystem: ext4") - .replace("reset: plain-copy", "reset: local-clonefile"); - assert!( - parse_case(&invalid_clonefile) - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "invalid_clonefile_filesystem") - ); - } - - #[test] - fn deadline_is_explicit_bounded_or_none_and_remains_identity() { - let bounded = valid(); - let none = parse_case(&VALID.replace("deadline_seconds: 60", "deadline_seconds: null")) - .into_result() - .unwrap(); - assert_eq!(none.definition.protocol.deadline_seconds, None); - assert_eq!( - serde_json::to_value(&none.identity).unwrap()["protocol"]["deadline_seconds"], - serde_json::Value::Null - ); - assert_ne!(bounded.point_id, none.point_id); - - let thirty = parse_case(&VALID.replace("deadline_seconds: 60", "deadline_seconds: 30")) - .into_result() - .unwrap(); - assert_ne!(bounded.point_id, thirty.point_id); - - for seconds in [0, MAX_DEADLINE_SECONDS + 1] { - assert!( - parse_case(&VALID.replace( - "deadline_seconds: 60", - &format!("deadline_seconds: {seconds}") - )) - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "invalid_deadline") - ); - } - - let missing = VALID.replace(" deadline_seconds: 60\n", ""); - assert_eq!( - parse_case(&missing).diagnostics[0].code, - "invalid_case_yaml" - ); - } - - #[test] - fn aws_and_image_pinned_compatible_s3_identities_are_typed() { - let aws = parse_case(&s3_case("aws-s3", "managed", "enabled", None)) - .into_result() - .unwrap(); - let digest = format!("sha256:{}", "a".repeat(64)); - let minio = parse_case(&s3_case("minio", "release-1", "enabled", Some(&digest))) - .into_result() - .unwrap(); - assert_ne!(aws.point_id, minio.point_id); - - let same_host_minio = s3_case("minio", "release-1", "enabled", Some(&digest)).replace( - "network_position: same-region", - "network_position: same-host", - ); - assert!(parse_case(&same_host_minio).ok); - } - - #[test] - fn s3_identity_strings_are_normalized_before_validation_and_hashing() { - let digest = format!("sha256:{}", "a".repeat(64)); - let canonical = parse_case(&s3_case("minio", "release-1", "enabled", Some(&digest))) - .into_result() - .unwrap(); - let padded_yaml = s3_case("minio", "' release-1 '", "enabled", Some(&digest)) - .replace("region: us-east-1", "region: ' us-east-1 '") - .replace("storage_class: standard", "storage_class: ' standard '"); - let padded = parse_case(&padded_yaml).into_result().unwrap(); - - assert_eq!(canonical.point_id, padded.point_id); - assert_eq!(canonical.case_digest, padded.case_digest); - let Backend::S3 { - implementation_version, - region, - storage_class, - .. - } = padded.definition.environment.backend - else { - panic!("expected S3 backend"); - }; - assert_eq!(implementation_version, "release-1"); - assert_eq!(region, "us-east-1"); - assert_eq!(storage_class, "standard"); - } - - #[test] - fn compatible_s3_image_digest_rules_fail_closed() { - let missing = parse_case(&s3_case("minio", "release-1", "enabled", None)); - assert!( - missing - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "missing_s3_image_digest") - ); - - let malformed = format!("sha256:{}", "A".repeat(64)); - let malformed = parse_case(&s3_case("rustfs", "release-1", "enabled", Some(&malformed))); - assert!( - malformed - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "invalid_s3_image_digest") - ); - - let forbidden = format!("sha256:{}", "b".repeat(64)); - let forbidden = parse_case(&s3_case("aws-s3", "managed", "enabled", Some(&forbidden))); - assert!( - forbidden - .diagnostics - .iter() - .any(|diagnostic| diagnostic.code == "forbidden_aws_s3_image_digest") - ); - } +fn refusal(message: String) -> ValidationOutcome { + ValidationOutcome::failure(vec![Diagnostic::error("invalid_case", "$", message)]) } diff --git a/crates/omnigraph-bench/src/catalog.rs b/crates/omnigraph-bench/src/catalog.rs new file mode 100644 index 000000000..e63c70467 --- /dev/null +++ b/crates/omnigraph-bench/src/catalog.rs @@ -0,0 +1,497 @@ +//! One configuration selects GQT starting states and measured workloads. +use std::collections::{BTreeMap, BTreeSet}; +use std::path::{Path, PathBuf}; + +use serde::{Deserialize, Deserializer, Serialize}; + +use crate::case::{ + Attribution, Backend, LocalFilesystem, LocalStorageClass, Protocol, ResetMode, Schedule, Timer, + ValidatedCase, +}; +use crate::gqt_case::{ + self, GqtCaseV1, GqtEnvironment, GqtFixture, GqtScenario, GqtWorkload, MeasuredStep, PlannedGqt, +}; +use crate::model::{Diagnostic, declared_version, read_yaml_file, strict_yaml, valid_kebab_id}; +use crate::suite::{ + MAX_REPETITIONS_PER_CASE, MAX_SUITE_RUNS, MAX_TOTAL_REPETITIONS, ResolvedRun, ResolvedSuite, + SuiteV1, +}; + +pub const CONFIG_VERSION: u32 = 2; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV2 { + pub version: u32, + #[serde(default, skip_serializing_if = "Defaults::is_empty")] + pub defaults: Defaults, + pub scenarios: Vec, + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub groups: BTreeMap>, + #[serde(default)] + pub run: Vec, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Defaults { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub repetitions: Option, + #[serde( + default, + deserialize_with = "deadline", + skip_serializing_if = "Option::is_none" + )] + pub deadline_seconds: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub environment: Option, + #[serde(default, skip_serializing_if = "ProtocolOverrides::is_empty")] + pub protocol: ProtocolOverrides, +} + +impl Defaults { + fn is_empty(&self) -> bool { + self == &Self::default() + } +} +impl ProtocolOverrides { + fn is_empty(&self) -> bool { + self == &Self::default() + } +} + +fn deadline<'de, D: Deserializer<'de>>(deserializer: D) -> Result>, D::Error> { + Option::deserialize(deserializer).map(Some) +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ProtocolOverrides { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub attribution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub schedule: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub reset: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub timer: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum FixtureInput { + Path(PathBuf), + Explicit(GqtFixture), +} +impl FixtureInput { + pub fn definition(&self) -> GqtFixture { + match self { + Self::Path(path) => GqtFixture::Dataset { path: path.clone() }, + Self::Explicit(fixture) => fixture.clone(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Scenario { + pub id: String, + pub fixture: FixtureInput, + pub workload: PathBuf, + pub measured_step: MeasuredStep, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub repetitions: Option, + #[serde( + default, + deserialize_with = "deadline", + skip_serializing_if = "Option::is_none" + )] + pub deadline_seconds: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub environment: Option, + #[serde(default, skip_serializing_if = "ProtocolOverrides::is_empty")] + pub protocol: ProtocolOverrides, +} +impl Scenario { + pub fn expand(&self, defaults: &Defaults) -> (GqtCaseV1, u32) { + let environment = self + .environment + .clone() + .or_else(|| defaults.environment.clone()) + .unwrap_or_else(local_environment); + let reset = match environment.backend { + Backend::LocalFs { + filesystem: LocalFilesystem::Apfs, + .. + } => ResetMode::LocalClonefile, + _ => ResetMode::PlainCopy, + }; + let protocol = Protocol { + deadline_seconds: self + .deadline_seconds + .or(defaults.deadline_seconds) + .unwrap_or(Some(60)), + attribution: self + .protocol + .attribution + .or(defaults.protocol.attribution) + .unwrap_or(Attribution::PerPhase), + schedule: self + .protocol + .schedule + .or(defaults.protocol.schedule) + .unwrap_or(Schedule::Manual), + reset: self + .protocol + .reset + .or(defaults.protocol.reset) + .unwrap_or(reset), + timer: self + .protocol + .timer + .or(defaults.protocol.timer) + .unwrap_or(Timer::Monotonic), + }; + ( + GqtCaseV1 { + version: 1, + id: self.id.clone(), + scenario: GqtScenario::GqtV1, + fixture: self.fixture.definition(), + workload: GqtWorkload { + queries: self.workload.clone(), + measured_step: self.measured_step.clone(), + }, + environment, + protocol, + }, + self.repetitions.or(defaults.repetitions).unwrap_or(5), + ) + } +} + +pub fn local_environment() -> GqtEnvironment { + GqtEnvironment { + backend: Backend::LocalFs { + filesystem: if cfg!(target_os = "macos") { + LocalFilesystem::Apfs + } else { + LocalFilesystem::Xfs + }, + storage_class: LocalStorageClass::NvmeSsd, + }, + } +} + +#[derive(Debug, Clone)] +pub struct Catalog { + pub path: PathBuf, + pub root: PathBuf, + pub definition: ConfigV2, +} +impl Catalog { + pub fn load(path: &Path) -> Result> { + let metadata = + std::fs::metadata(path).map_err(|e| vec![error("config_read_error", e.to_string())])?; + if !metadata.is_file() { + return Err(vec![error( + "invalid_config_file", + "config must be a regular file", + )]); + } + let source = read_yaml_file(path, "config").map_err(|e| vec![e])?; + let catalog = Self::from_source(path, &source)?; + let canonical = path + .canonicalize() + .map_err(|e| vec![error("config_path_error", e.to_string())])?; + if !canonical.starts_with(&catalog.root) { + return Err(vec![error( + "config_outside_root", + "config symlink escapes its declared directory", + )]); + } + Ok(catalog) + } + + /// Also used before writing a generated config, whose file does not yet exist. + pub fn from_source(path: &Path, source: &str) -> Result> { + let version = declared_version(source, "config").map_err(|e| vec![e])?; + if version != CONFIG_VERSION { + return Err(vec![error( + "unsupported_config_version", + format!("expected config version {CONFIG_VERSION}, found {version}"), + )]); + } + let definition: ConfigV2 = strict_yaml(source, "config").map_err(|e| vec![e])?; + validate(&definition)?; + let absolute = if path.is_absolute() { + path.to_path_buf() + } else { + std::env::current_dir() + .map_err(|e| vec![error("config_path_error", e.to_string())])? + .join(path) + }; + if absolute.to_str().is_none() { + return Err(vec![error( + "config_path_error", + "config path must be UTF-8", + )]); + } + let root = absolute + .parent() + .ok_or_else(|| vec![error("config_path_error", "config has no parent")])? + .canonicalize() + .map_err(|e| vec![error("config_path_error", e.to_string())])?; + let path = root.join( + absolute + .file_name() + .ok_or_else(|| vec![error("config_path_error", "config has no filename")])?, + ); + Ok(Self { + path, + root, + definition, + }) + } + + pub fn scenario(&self, id: &str) -> Result<&Scenario, Vec> { + self.definition + .scenarios + .iter() + .find(|s| s.id == id) + .ok_or_else(|| { + vec![error( + "unknown_scenario", + format!("unknown scenario '{id}'; use list scenarios"), + )] + }) + } + + pub fn plan(&self, id: &str) -> Result> { + let scenario = self.scenario(id)?; + let (definition, _) = scenario.expand(&self.definition.defaults); + gqt_case::load_with_root(&self.path, definition, &self.root) + .map_err(|message| vec![Diagnostic::error("invalid_scenario", id, message)]) + } + + pub fn resolve( + &self, + selector: Option<&str>, + repetitions: Option, + ) -> Result> { + let ids = select(&self.definition, selector)?; + let configured: Vec<_> = ids + .iter() + .map(|id| { + let scenario = self.scenario(id)?; + let repetitions = + repetitions.unwrap_or(scenario.expand(&self.definition.defaults).1); + check_repetitions(repetitions)?; + Ok((id, repetitions)) + }) + .collect::>>()?; + if configured + .iter() + .map(|(_, reps)| u64::from(*reps)) + .sum::() + > MAX_TOTAL_REPETITIONS + { + return Err(vec![error( + "repetition_budget_exceeded", + "selection exceeds 100000 repetitions", + )]); + } + let mut runs = Vec::with_capacity(ids.len()); + let mut identities = BTreeSet::new(); + for (id, repetitions) in configured { + let plan = self.plan(id)?; + if !identities.insert(plan.planned_sha256.clone()) { + return Err(vec![error( + "duplicate_planned_identity", + format!("scenario '{id}' duplicates an experiment in this selection"), + )]); + } + runs.push(ResolvedRun { + case_path: self.path.clone(), + repetitions, + case: ValidatedCase::Gqt(plan), + }); + } + Ok(ResolvedSuite { + definition: SuiteV1 { + version: 1, + name: selector.unwrap_or("configured-benchmarks").into(), + runs: Vec::new(), + }, + suite_path: self.path.clone(), + runs, + }) + } +} + +pub fn find_config(explicit: Option<&Path>) -> Result> { + if let Some(path) = explicit { + return Ok(path.to_path_buf()); + } + let cwd = + std::env::current_dir().map_err(|e| vec![error("config_path_error", e.to_string())])?; + for directory in cwd.ancestors() { + for path in [ + directory.join("benchmarks.yaml"), + directory.join("benchmarks/benchmarks.yaml"), + ] { + match path.try_exists() { + Ok(true) => return Ok(path), + Ok(false) => {} + Err(e) => return Err(vec![error("config_path_error", e.to_string())]), + } + } + } + Err(vec![error( + "config_not_found", + "no benchmarks/benchmarks.yaml found; pass --config FILE", + )]) +} + +fn check_repetitions(value: u32) -> Result<(), Vec> { + if !(1..=MAX_REPETITIONS_PER_CASE).contains(&value) { + return Err(vec![error( + "invalid_repetitions", + format!("repetitions must be in 1..={MAX_REPETITIONS_PER_CASE}"), + )]); + } + Ok(()) +} +fn validate(config: &ConfigV2) -> Result<(), Vec> { + if config.scenarios.is_empty() + || config.scenarios.len() > MAX_SUITE_RUNS + || config.groups.len() > MAX_SUITE_RUNS + || config.run.len() > MAX_SUITE_RUNS + { + return Err(vec![error( + "invalid_catalog_size", + format!( + "config requires 1..={MAX_SUITE_RUNS} scenarios and at most {MAX_SUITE_RUNS} groups" + ), + )]); + } + let mut names = BTreeSet::new(); + for scenario in &config.scenarios { + if !valid_kebab_id(&scenario.id) + || scenario.id.len() > 128 + || !names.insert(scenario.id.as_str()) + { + return Err(vec![error( + "invalid_scenario_id", + format!( + "scenario ID '{}' must be unique kebab-case, at most 128 characters", + scenario.id + ), + )]); + } + let (definition, repetitions) = scenario.expand(&config.defaults); + check_repetitions(repetitions)?; + gqt_case::validate_definition(&definition) + .map_err(|e| vec![Diagnostic::error("invalid_scenario", &scenario.id, e)])?; + for path in fixture_paths(&definition.fixture) + .into_iter() + .chain([definition.workload.queries.as_path()]) + { + if path.is_absolute() + || path.as_os_str().is_empty() + || path + .components() + .any(|p| matches!(p, std::path::Component::ParentDir)) + { + return Err(vec![Diagnostic::error( + "invalid_source_path", + &scenario.id, + "source paths must be relative and stay inside the config directory", + )]); + } + } + } + for (name, members) in &config.groups { + if !valid_kebab_id(name) || name.len() > 128 || names.contains(name.as_str()) { + return Err(vec![error( + "invalid_group_id", + format!("group '{name}' must be unique kebab-case, distinct from scenario IDs"), + )]); + } + if members.is_empty() || members.len() > MAX_SUITE_RUNS { + return Err(vec![error( + "invalid_group_size", + format!("group '{name}' is empty or too large"), + )]); + } + let mut seen = BTreeSet::new(); + for id in members { + if !names.contains(id.as_str()) || !seen.insert(id) { + return Err(vec![error( + "invalid_group_member", + format!("group '{name}' has duplicate or unknown scenario '{id}'"), + )]); + } + } + } + if !config.run.is_empty() { + select(config, None)?; + } + Ok(()) +} +fn select(config: &ConfigV2, selector: Option<&str>) -> Result, Vec> { + let selectors: Vec<&str> = match selector { + Some(name) => vec![name], + None => config.run.iter().map(String::as_str).collect(), + }; + if selectors.is_empty() { + return Err(vec![error( + "empty_selection", + "supply a scenario/group name or an explicit run list in the config", + )]); + } + let names: BTreeSet<_> = config.scenarios.iter().map(|s| s.id.as_str()).collect(); + let mut seen = BTreeSet::new(); + let mut result = Vec::new(); + for selector in selectors { + let members = if let Some(members) = config.groups.get(selector) { + members.clone() + } else if names.contains(selector) { + vec![selector.to_owned()] + } else { + return Err(vec![error( + "unknown_selection", + format!("unknown scenario or group '{selector}'"), + )]); + }; + for id in members { + if !seen.insert(id.clone()) { + return Err(vec![error( + "duplicate_selection", + format!("scenario '{id}' is selected more than once"), + )]); + } + result.push(id); + if result.len() > MAX_SUITE_RUNS { + return Err(vec![error( + "selection_budget_exceeded", + "too many selected scenarios", + )]); + } + } + } + Ok(result) +} + +pub fn fixture_paths(fixture: &GqtFixture) -> Vec<&Path> { + match fixture { + GqtFixture::Dataset { path } => vec![path], + GqtFixture::Registered { + reference, + preparation, + } => vec![reference, preparation], + } +} +fn error(code: &str, message: impl Into) -> Diagnostic { + Diagnostic::error(code, "$", message) +} diff --git a/crates/omnigraph-bench/src/catalog_tests.rs b/crates/omnigraph-bench/src/catalog_tests.rs new file mode 100644 index 000000000..8f340ca7d --- /dev/null +++ b/crates/omnigraph-bench/src/catalog_tests.rs @@ -0,0 +1,238 @@ +use crate::catalog::{Catalog, ConfigV2, FixtureInput}; +use crate::discovery::{self, SourceState}; +use std::path::Path; + +fn setup() -> (tempfile::TempDir, Catalog) { + let directory = tempfile::tempdir().unwrap(); + for name in ["fixtures", "workloads"] { + std::fs::create_dir(directory.path().join(name)).unwrap(); + } + std::fs::write( + directory.path().join("fixtures/tiny_graph.gqt"), + include_str!("../../../benchmarks/fixtures/tiny_graph.gqt"), + ) + .unwrap(); + std::fs::write( + directory.path().join("workloads/tiny_read.gqt"), + include_str!("../../../benchmarks/workloads/tiny_read.gqt"), + ) + .unwrap(); + let source = include_str!("../../../benchmarks/custom.example.yaml"); + let path = directory.path().join("benchmarks.yaml"); + std::fs::write(&path, source).unwrap(); + let catalog = Catalog::load(&path).unwrap(); + (directory, catalog) +} +fn changed(catalog: &Catalog, config: &ConfigV2) -> Result> { + Catalog::from_source(&catalog.path, &serde_yaml::to_string(config).unwrap()) +} + +#[test] +fn strict_config_rejects_unknown_versions_fields_and_duplicate_yaml_keys() { + let (_directory, catalog) = setup(); + let source = std::fs::read_to_string(&catalog.path).unwrap(); + for changed in [ + source.replacen("version: 2", "version: 3", 1), + format!("{source}\nunknown: true\n"), + format!("{source}\nversion: 2\n"), + format!("{source}\ngroups:\n small: [custom-tiny-read]\n small: [custom-tiny-read]\n"), + ] { + assert!(Catalog::from_source(&catalog.path, &changed).is_err()); + } +} + +#[test] +fn selection_is_explicit_unique_and_does_not_load_unselected_sources() { + let (_directory, catalog) = setup(); + let mut config = catalog.definition.clone(); + let mut absent = config.scenarios[0].clone(); + absent.id = "absent".into(); + absent.fixture = FixtureInput::Path("fixtures/not-here.gqt".into()); + config.scenarios.push(absent); + config.run.clear(); + let explicit = changed(&catalog, &config).unwrap(); + assert!(explicit.resolve(None, None).is_err()); + assert_eq!( + explicit + .resolve(Some("custom-tiny-read"), None) + .unwrap() + .runs + .len(), + 1 + ); + assert!(explicit.resolve(Some("absent"), None).is_err()); + assert!(explicit.resolve(Some("typo"), None).is_err()); + config + .groups + .insert("small".into(), vec!["custom-tiny-read".into()]); + config.run = vec!["small".into(), "custom-tiny-read".into()]; + assert!(changed(&catalog, &config).is_err()); + config.run.clear(); + config + .groups + .insert("custom-tiny-read".into(), vec!["absent".into()]); + assert!(changed(&catalog, &config).is_err()); + config.groups.remove("custom-tiny-read"); + config + .groups + .insert("unknown".into(), vec!["missing".into()]); + assert!(changed(&catalog, &config).is_err()); + config.groups.clear(); + config.scenarios[1].id = "custom-tiny-read".into(); + assert!(changed(&catalog, &config).is_err()); +} + +#[test] +fn defaults_and_explicit_null_resolve_before_identity() { + let (_directory, catalog) = setup(); + let mut config = catalog.definition.clone(); + config.defaults.deadline_seconds = Some(Some(120)); + config.defaults.repetitions = Some(7); + for (deadline, expected) in [ + (None, Some(120)), + (Some(None), None), + (Some(Some(30)), Some(30)), + ] { + config.scenarios[0].deadline_seconds = deadline; + config.scenarios[0].repetitions = Some(2); + let changed = changed(&catalog, &config).unwrap(); + let suite = changed.resolve(None, None).unwrap(); + let plan = suite.runs[0].case.gqt().unwrap(); + assert_eq!(plan.definition.protocol.deadline_seconds, expected); + assert_eq!(suite.runs[0].repetitions, 2); + let overridden = changed.resolve(None, Some(3)).unwrap(); + assert_eq!(overridden.runs[0].repetitions, 3); + assert_eq!( + overridden.runs[0].case.planned_identity(), + plan.planned_sha256 + ); + } +} + +#[test] +fn repetition_budget_precedes_source_loading() { + let (_directory, catalog) = setup(); + for repetitions in [0, 10001] { + assert!(catalog.resolve(None, Some(repetitions)).is_err()); + } + let mut config = catalog.definition.clone(); + config.scenarios.clear(); + config.run.clear(); + for index in 0..11 { + let mut scenario = catalog.definition.scenarios[0].clone(); + scenario.id = format!("scenario-{index}"); + scenario.fixture = FixtureInput::Path("fixtures/missing.gqt".into()); + scenario.repetitions = Some(10000); + config.run.push(scenario.id.clone()); + config.scenarios.push(scenario); + } + let changed = changed(&catalog, &config).unwrap(); + assert_eq!( + changed.resolve(None, None).unwrap_err()[0].code, + "repetition_budget_exceeded" + ); +} + +#[test] +fn moved_catalogs_keep_identity_and_aliases_cannot_duplicate_execution() { + let (directory, catalog) = setup(); + let before = catalog.plan("custom-tiny-read").unwrap(); + let mut config = catalog.definition.clone(); + let mut alias = config.scenarios[0].clone(); + alias.id = "alias".into(); + config.scenarios.push(alias); + config.run.push("alias".into()); + let alias = changed(&catalog, &config).unwrap(); + assert_eq!( + alias.resolve(None, None).unwrap_err()[0].code, + "duplicate_planned_identity" + ); + assert!(alias.resolve(Some("alias"), None).is_ok()); + let moved_parent = tempfile::tempdir().unwrap(); + let moved = moved_parent.path().join("catalog"); + std::fs::rename(directory.path(), &moved).unwrap(); + let after = Catalog::load(&moved.join("benchmarks.yaml")) + .unwrap() + .plan("custom-tiny-read") + .unwrap(); + assert_eq!(before.planned_sha256, after.planned_sha256); + let logical = "a".repeat(64); + let algorithm = crate::dataset_identity::DATASET_LOGICAL_ALGORITHM; + assert_eq!( + before.bind(&logical, algorithm).unwrap().point_id, + after.bind(&logical, algorithm).unwrap().point_id + ); +} + +#[test] +fn inventory_retains_missing_invalid_and_unselected_sources() { + let (directory, catalog) = setup(); + std::fs::copy( + directory.path().join("fixtures/tiny_graph.gqt"), + directory.path().join("fixtures/unselected.gqt"), + ) + .unwrap(); + std::fs::remove_file(directory.path().join("fixtures/tiny_graph.gqt")).unwrap(); + std::fs::write(directory.path().join("workloads/tiny_read.gqt"), "not GQT").unwrap(); + let fixtures = discovery::sources(&catalog, true).unwrap(); + assert_eq!(fixtures.entries.len(), 2); + assert_eq!(fixtures.entries[0].source, SourceState::Missing); + assert_eq!(fixtures.entries[1].source, SourceState::Available); + assert!(fixtures.entries[1].scenarios.is_empty()); + let scenarios = discovery::scenarios(&catalog); + assert_eq!(scenarios.entries[0].source, SourceState::Invalid); + assert!(scenarios.entries[0].diagnostics.len() >= 2); +} + +#[test] +#[cfg(unix)] +fn config_and_source_paths_cannot_escape_or_block_on_special_files() { + use std::os::unix::fs::symlink; + let (directory, catalog) = setup(); + let outside = tempfile::tempdir().unwrap(); + std::fs::write( + outside.path().join("config.yaml"), + std::fs::read(&catalog.path).unwrap(), + ) + .unwrap(); + symlink( + outside.path().join("config.yaml"), + directory.path().join("alias.yaml"), + ) + .unwrap(); + assert!(Catalog::load(&directory.path().join("alias.yaml")).is_err()); + let source = directory.path().join("fixtures/tiny_graph.gqt"); + std::fs::rename(&source, outside.path().join("fixture.gqt")).unwrap(); + symlink(outside.path().join("fixture.gqt"), &source).unwrap(); + assert!(catalog.plan("custom-tiny-read").is_err()); + let mut config = catalog.definition.clone(); + for path in [Path::new("../escape.gqt"), Path::new("/escape.gqt")] { + config.scenarios[0].fixture = FixtureInput::Path(path.into()); + assert!(changed(&catalog, &config).is_err()); + } + let fifo = directory.path().join("fifo.yaml"); + nix::unistd::mkfifo(&fifo, nix::sys::stat::Mode::S_IRUSR).unwrap(); + assert!(Catalog::load(&fifo).is_err()); +} + +#[test] +#[cfg(unix)] +fn references_and_gqt_fifos_are_refused_by_the_shared_bounded_reader() { + let directory = tempfile::tempdir().unwrap(); + let fifo = directory.path().join("source"); + nix::unistd::mkfifo(&fifo, nix::sys::stat::Mode::S_IRUSR).unwrap(); + assert!(crate::model::read_yaml_file(&fifo, "reference").is_err()); + assert!(crate::gqt_case::read_source(&fifo).is_err()); +} + +#[test] +fn workload_descriptor_inspection_refuses_excessive_expansion_before_enumeration() { + let template = include_str!("../../../benchmarks/workloads/tiny_read.gqt"); + let header = template.split("--- query branch: main").next().unwrap(); + let source = format!( + "{header}{}", + "--- restart\n".repeat(crate::gqt_case::MAX_EXPANDED_STEPS + 1) + ); + let case = omnigraph_gqt_core::parse_case("many_steps", &source).unwrap(); + assert!(crate::gqt_case::workload_steps(&case).is_err()); +} diff --git a/crates/omnigraph-bench/src/dataset_cache.rs b/crates/omnigraph-bench/src/dataset_cache.rs new file mode 100644 index 000000000..3ef77ad9a --- /dev/null +++ b/crates/omnigraph-bench/src/dataset_cache.rs @@ -0,0 +1,1516 @@ +//! Frozen dataset cache. The lock owns the stable active path through builder +//! and repetition quiescence; the template is never opened by an engine. +use crate::case::ResetMode; +use crate::dataset_worker::FixtureBuildHandoff; +use crate::gqt_case::{DatasetBuildPlan, DatasetRecipe, digest as valid_digest}; +use crate::registered_fixture::{RegisteredPhysicalTreeV1, load_source_descriptor}; +use crate::reset::{self, MetadataDigest, PhysicalDigest, TraversalLimits}; +use crate::runner::{RunnerError, RunnerResult}; +use serde::{Deserialize, Serialize}; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use std::time::{Duration, Instant}; +pub(crate) const MAX_DATASET_MANIFEST_BYTES: usize = 1024 * 1024; +pub const GQT_ENGINE_DIGEST: &str = env!("GQT_ENGINE_DIGEST"); +const MAX_INSPECTION_ENTRIES: usize = 100_000; +const MAX_INSPECTION_PAGE: usize = 100; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum SourceAvailability { + Available, + Missing, + Invalid, + Unbound, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum CacheState { + Missing, + Present, + Cached, + Busy, + Invalid, + Incomplete, + Unknown, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct CacheIdentity { + pub recipe_sha256: String, + pub engine_digest: String, + pub needs_indices: bool, + pub reset: ResetMode, + pub logical_content_sha256: String, + pub tree_sha256: String, + pub files: u64, + pub bytes: u64, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct CacheInspection { + pub inspection_version: u32, + pub source: Option, + pub cache: CacheState, + pub key: Option, + pub path: PathBuf, + pub identity: Option, + pub diagnostic: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct CachePage { + pub inspection_version: u32, + pub cache_root: PathBuf, + pub root_state: CacheState, + pub entries: Vec, + pub next_cursor: Option, +} + +impl CacheInspection { + fn new(path: &Path, key: Option) -> Self { + Self { + inspection_version: 1, + source: None, + cache: CacheState::Unknown, + key, + path: path.into(), + identity: None, + diagnostic: None, + } + } + + fn fail(mut self, state: CacheState, code: &str, message: impl Into) -> Self { + self.cache = state; + self.diagnostic = Some(RunnerError::new(code, message)); + self + } +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct DatasetManifestV1 { + pub format_version: u32, + pub key: String, + pub recipe_sha256: String, + pub engine_digest: String, + pub needs_indices: bool, + pub reset: ResetMode, + pub handoff: FixtureBuildHandoff, +} +pub struct DatasetLease { + pub root: PathBuf, + pub active: PathBuf, + pub template: PathBuf, + pub manifest: DatasetManifestV1, + pub cache_hit: bool, + _directory: File, + #[cfg(unix)] + _lock: nix::fcntl::Flock, +} +impl DatasetLease { + pub fn restore(&self) -> RunnerResult { + self.verify()?; + let h = &self.manifest.handoff; + let limits = TraversalLimits::default(); + let prepared = match self.manifest.reset { + ResetMode::LocalClonefile => reset::accept_clonefile_template_handoff( + &self.active, + &self.template, + h.physical.clone(), + h.template_metadata.clone(), + limits, + ) + .and_then(|t| t.restore_active()), + ResetMode::PlainCopy => reset::accept_plain_copy_template_handoff( + &self.active, + &self.template, + h.physical.clone(), + h.template_metadata.clone(), + limits, + ) + .and_then(|t| t.restore_active()), + ResetMode::S3Versioning => return Err(error("unsupported dataset reset")), + } + .map_err(|e| error(e.to_string()))?; + prepared + .verify_unchanged() + .map_err(|e| error(e.to_string())) + } + pub fn verify(&self) -> RunnerResult<()> { + self.validate_ownership()?; + validate_manifest_evidence(&self.manifest).map_err(error)?; + + if is_quarantined(&self.root)? { + return Err(error( + "dataset entry is quarantined after uncertain worker containment", + )); + } + reset::verify_metadata_tree( + &self.template, + &self.manifest.handoff.template_metadata, + TraversalLimits::default(), + ) + .map_err(|e| error(format!("template metadata changed: {e}")))?; + Ok(()) + } + pub fn quarantine(&self, why: &str) -> RunnerResult<()> { + self.validate_ownership()?; + write_quarantine(&self.root, &self._directory, why) + } + pub fn remove_active(&self) -> RunnerResult<()> { + self.validate_ownership()?; + if self.active.exists() { + std::fs::remove_dir_all(&self.active).map_err(|e| error(e.to_string()))?; + } + Ok(()) + } + pub fn validate_ownership(&self) -> RunnerResult<()> { + #[cfg(unix)] + { + validate_entry(&self.root, &self._directory, &self._lock)?; + } + Ok(()) + } + pub fn physical(&self) -> &PhysicalDigest { + &self.manifest.handoff.physical + } +} +fn error(message: impl Into) -> RunnerError { + RunnerError::new("dataset_cache_corrupt", message) +} +fn is_quarantined(root: &Path) -> RunnerResult { + match std::fs::symlink_metadata(root.join("quarantined")) { + Ok(_) => Ok(true), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(false), + Err(e) => Err(error(e.to_string())), + } +} +fn write_quarantine(root: &Path, directory: &File, why: &str) -> RunnerResult<()> { + let mut options = OpenOptions::new(); + options.write(true).create_new(true); + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + options.custom_flags(nix::libc::O_NOFOLLOW | nix::libc::O_NONBLOCK); + } + match options.open(root.join("quarantined")) { + Ok(mut file) => file + .write_all(why.as_bytes()) + .and_then(|_| file.sync_all()) + .map_err(|e| error(e.to_string()))?, + Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {} + Err(e) => return Err(error(e.to_string())), + } + directory.sync_all().map_err(|e| error(e.to_string())) +} + +/// Inspect the exact frozen input's cache variant without creating or executing anything. +#[cfg(unix)] +pub fn inspect( + plan: &DatasetBuildPlan, + cache: &Path, + binding: Option<&str>, + verify: bool, +) -> CacheInspection { + let mut result = CacheInspection::new(cache, None); + result.source = Some(SourceAvailability::Available); + if let Err(message) = plan.revalidate() { + result.source = Some(SourceAvailability::Invalid); + return result.fail(CacheState::Unknown, "invalid_dataset", message); + } + if let DatasetRecipe::Registered { reference, .. } = &plan.dataset { + let Some(binding) = binding else { + result.source = Some(SourceAvailability::Unbound); + return result.fail( + CacheState::Unknown, + "fixture_binding_missing", + "registered dataset requires --fixture ID=BUNDLE", + ); + }; + if binding + .split_once('=') + .is_none_or(|(id, _)| id != reference.definition.fixture_id) + { + result.source = Some(SourceAvailability::Invalid); + return result.fail( + CacheState::Unknown, + "fixture_binding_invalid", + "expected the registered fixture's ID=BUNDLE binding", + ); + } + if let Some((_, bundle)) = binding.split_once('=') { + for path in [ + PathBuf::from(bundle), + Path::new(bundle).join("fixture-source.json"), + Path::new(bundle).join("root"), + ] { + match std::fs::symlink_metadata(&path) { + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + result.source = Some(SourceAvailability::Missing); + return result.fail( + CacheState::Unknown, + "fixture_source_missing", + e.to_string(), + ); + } + Ok(m) if m.file_type().is_symlink() => { + result.source = Some(SourceAvailability::Invalid); + return result.fail( + CacheState::Unknown, + "fixture_binding_invalid", + "registered source must not be a symlink", + ); + } + Err(e) => { + result.source = Some(SourceAvailability::Invalid); + return result.fail( + CacheState::Unknown, + "fixture_source_unreadable", + e.to_string(), + ); + } + _ => {} + } + } + } + } + let registered = match registered_physical(plan, binding) { + Ok(value) => value, + Err(e) => { + result.source = Some(SourceAvailability::Invalid); + return result.fail(CacheState::Unknown, &e.code, e.message); + } + }; + let (cache, directory) = match inspection_root(cache) { + Ok(Some(value)) => value, + Ok(None) => { + result.cache = CacheState::Missing; + return result; + } + Err(e) => return result.fail(CacheState::Unknown, &e.code, e.message), + }; + let key = match cache_key(plan, &cache, registered.as_ref()) { + Ok(value) => value, + Err(e) => return result.fail(CacheState::Unknown, &e.code, e.message), + }; + result = inspect_entry(&cache.join(&key), Some(plan), verify); + result.source = Some(SourceAvailability::Available); + if let Err(e) = validate_path(&cache, &directory) { + return result.fail(CacheState::Unknown, "dataset_cache_changed", e.message); + } + result +} + +/// List a bounded page of historical entries; no current source or engine is required. +#[cfg(unix)] +pub fn list( + cache: &Path, + limit: usize, + after: Option<&str>, + verify: bool, +) -> RunnerResult { + if !(1..=MAX_INSPECTION_PAGE).contains(&limit) { + return Err(RunnerError::new( + "invalid_cache_page_limit", + "cache page limit must be 1..=100", + )); + } + let mut page = CachePage { + inspection_version: 1, + cache_root: cache.into(), + root_state: CacheState::Missing, + entries: Vec::new(), + next_cursor: None, + }; + let Some((cache, directory)) = inspection_root(cache)? else { + return Ok(page); + }; + page.cache_root = cache.clone(); + page.root_state = CacheState::Present; + let names = bounded_names(&cache)?; + let mut selected = names + .iter() + .filter(|name| after.is_none_or(|cursor| name.as_str() > cursor)); + for name in selected.by_ref().take(limit) { + page.entries + .push(inspect_entry(&cache.join(name), None, verify)); + } + if selected.next().is_some() { + page.next_cursor = page + .entries + .last() + .and_then(|entry| entry.path.file_name()) + .and_then(|name| name.to_str()) + .map(str::to_owned); + } + validate_path(&cache, &directory)?; + Ok(page) +} + +#[cfg(unix)] +fn inspection_root(cache: &Path) -> RunnerResult> { + let canonical = match cache.canonicalize() { + Ok(path) => path, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + return match std::fs::symlink_metadata(cache) { + Err(missing) if missing.kind() == std::io::ErrorKind::NotFound => Ok(None), + Err(other) => Err(RunnerError::new( + "dataset_cache_unreadable", + other.to_string(), + )), + Ok(_) => Err(RunnerError::new("dataset_cache_unreadable", e.to_string())), + }; + } + Err(e) => return Err(RunnerError::new("dataset_cache_unreadable", e.to_string())), + }; + match std::fs::symlink_metadata(&canonical) { + Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None), + Err(e) => return Err(RunnerError::new("dataset_cache_unreadable", e.to_string())), + Ok(m) if !m.is_dir() => { + return Err(RunnerError::new( + "dataset_cache_invalid_root", + "cache root must be a real directory", + )); + } + Ok(_) => {} + } + let directory = open_inspection_directory(&canonical) + .map_err(|e| RunnerError::new("dataset_cache_unreadable", e.to_string()))?; + validate_path(&canonical, &directory)?; + Ok(Some((canonical, directory))) +} + +#[cfg(unix)] +fn open_inspection_directory(path: &Path) -> std::io::Result { + use std::os::unix::fs::OpenOptionsExt; + OpenOptions::new() + .read(true) + .custom_flags(nix::libc::O_NOFOLLOW | nix::libc::O_DIRECTORY) + .open(path) +} + +fn bounded_names(root: &Path) -> RunnerResult> { + let mut names = Vec::new(); + for (index, entry) in std::fs::read_dir(root) + .map_err(|e| error(e.to_string()))? + .enumerate() + { + if index >= MAX_INSPECTION_ENTRIES { + return Err(RunnerError::new( + "dataset_cache_entry_budget", + "cache directory exceeds 100000 entries", + )); + } + let name = entry + .map_err(|e| error(e.to_string()))? + .file_name() + .into_string() + .map_err(|_| error("cache entry name is not UTF-8"))?; + names.push(name); + } + names.sort(); + Ok(names) +} + +#[cfg(unix)] +fn inspect_entry( + root: &Path, + expected: Option<&DatasetBuildPlan>, + verify: bool, +) -> CacheInspection { + use nix::fcntl::{Flock, FlockArg}; + use std::os::unix::fs::OpenOptionsExt; + let key = root + .file_name() + .and_then(|name| name.to_str()) + .filter(|name| valid_digest(name)) + .map(str::to_owned); + let mut result = CacheInspection::new(root, key); + if result.key.is_none() { + return result.fail( + CacheState::Unknown, + "dataset_cache_unrecognized_entry", + "entry name is not a dataset cache key", + ); + } + match std::fs::symlink_metadata(root) { + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + result.cache = CacheState::Missing; + return result; + } + Err(e) => { + return result.fail( + CacheState::Unknown, + "dataset_cache_unreadable", + e.to_string(), + ); + } + Ok(m) if !m.is_dir() => { + return result.fail( + CacheState::Invalid, + "dataset_cache_invalid_entry", + "cache entry must be a real directory", + ); + } + Ok(_) => {} + } + let directory = match open_inspection_directory(root) { + Ok(value) => value, + Err(e) => return result.fail(CacheState::Unknown, "dataset_cache_changed", e.to_string()), + }; + let file = match OpenOptions::new() + .read(true) + .custom_flags(nix::libc::O_NOFOLLOW | nix::libc::O_NONBLOCK) + .open(root.join("lock")) + { + Ok(value) => value, + Err(e) => { + return result.fail( + CacheState::Unknown, + "dataset_cache_lock_unavailable", + e.to_string(), + ); + } + }; + match file.metadata() { + Ok(m) if m.is_file() => {} + _ => { + return result.fail( + CacheState::Invalid, + "dataset_cache_invalid_lock", + "cache lock must be a regular file", + ); + } + } + let lock = match Flock::lock(file, FlockArg::LockSharedNonblock) { + Ok(value) => value, + Err((_, e)) if e == nix::errno::Errno::EWOULDBLOCK => { + return result.fail( + CacheState::Busy, + "dataset_cache_busy", + "dataset cache entry has an exclusive owner", + ); + } + Err((_, e)) => { + return result.fail( + CacheState::Unknown, + "dataset_cache_lock_unavailable", + e.to_string(), + ); + } + }; + if let Err(e) = validate_entry(root, &directory, &lock) { + return result.fail(CacheState::Unknown, "dataset_cache_changed", e.message); + } + result = inspect_owned_entry(result, expected, verify); + if let Err(e) = validate_entry(root, &directory, &lock) { + return result.fail(CacheState::Unknown, "dataset_cache_changed", e.message); + } + result +} + +fn inspect_owned_entry( + mut result: CacheInspection, + expected: Option<&DatasetBuildPlan>, + verify: bool, +) -> CacheInspection { + let root = result.path.clone(); + match is_quarantined(&root) { + Ok(true) => { + return result.fail( + CacheState::Invalid, + "dataset_cache_quarantined", + "cache entry is quarantined", + ); + } + Err(e) => return result.fail(CacheState::Unknown, "dataset_cache_unreadable", e.message), + Ok(false) => {} + } + match std::fs::symlink_metadata(root.join("dataset-build.json")) { + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + return match bounded_names(&root) { + Ok(names) if names.iter().all(|name| name == "lock") => { + result.cache = CacheState::Missing; + result + } + Ok(_) => result.fail( + CacheState::Incomplete, + "dataset_cache_unpublished", + "entry contains unpublished state", + ), + Err(e) => result.fail(CacheState::Unknown, "dataset_cache_unreadable", e.message), + }; + } + Err(e) => { + return result.fail( + CacheState::Unknown, + "dataset_cache_unreadable", + e.to_string(), + ); + } + Ok(_) => {} + } + let manifest: DatasetManifestV1 = match read_json(&root.join("dataset-build.json")) { + Ok(value) => value, + Err(e) => return result.fail(CacheState::Invalid, &e.code, e.message), + }; + let validated = (|| { + validate_manifest_identity( + &manifest, + result.key.as_deref().unwrap_or_default(), + expected, + )?; + validate_manifest_evidence(&manifest).map_err(error)?; + validate_published_paths(&root)?; + validate_descriptor(&root, &manifest)?; + if verify { + reset::verify_metadata_tree( + &root.join("root"), + &manifest.handoff.template_metadata, + TraversalLimits::default(), + ) + .map_err(|e| error(e.to_string()))?; + reset::verify_physical_tree( + &root.join("root"), + &manifest.handoff.physical, + TraversalLimits::default(), + ) + .map_err(|e| error(e.to_string()))?; + } + Ok::<(), RunnerError>(()) + })(); + if let Err(e) = validated { + return result.fail(CacheState::Invalid, &e.code, e.message); + } + result.identity = Some(CacheIdentity { + recipe_sha256: manifest.recipe_sha256, + engine_digest: manifest.engine_digest, + needs_indices: manifest.needs_indices, + reset: manifest.reset, + logical_content_sha256: manifest.handoff.summary.logical_content_sha256, + tree_sha256: manifest.handoff.physical.digest_sha256, + files: manifest.handoff.physical.files, + bytes: manifest.handoff.physical.bytes, + }); + result.cache = if verify { + CacheState::Cached + } else { + CacheState::Present + }; + result +} + +fn validate_manifest_identity( + manifest: &DatasetManifestV1, + key: &str, + plan: Option<&DatasetBuildPlan>, +) -> RunnerResult<()> { + if manifest.format_version != 1 + || manifest.key != key + || !valid_digest(&manifest.recipe_sha256) + || !valid_digest(&manifest.engine_digest) + || plan.is_some_and(|plan| { + manifest.recipe_sha256 != plan.recipe_sha256 + || manifest.engine_digest != GQT_ENGINE_DIGEST + || manifest.needs_indices != plan.needs_indices + || manifest.reset != plan.reset + }) + { + return Err(error("published dataset manifest identity mismatch")); + } + Ok(()) +} + +fn validate_published_paths(root: &Path) -> RunnerResult<()> { + match std::fs::symlink_metadata(root.join("active")) { + Err(e) if e.kind() == std::io::ErrorKind::NotFound => {} + Err(e) => return Err(error(e.to_string())), + Ok(_) => return Err(error("published cache entry has an unretired active store")), + } + if !std::fs::symlink_metadata(root.join("root")) + .map_err(|e| error(e.to_string()))? + .is_dir() + { + return Err(error("published cache template must be a real directory")); + } + Ok(()) +} + +fn validate_descriptor(root: &Path, manifest: &DatasetManifestV1) -> RunnerResult<()> { + let (descriptor, _) = load_source_descriptor(&root.join("fixture-source.json")) + .map_err(|e| error(format!("{e:?}")))?; + let physical = &manifest.handoff.physical; + if descriptor.fixture_id != format!("gqt-{}", manifest.key) + || descriptor.physical.tree_sha256 != physical.digest_sha256 + || descriptor.physical.files != physical.files + || descriptor.physical.bytes != physical.bytes + { + return Err(error( + "registered cache descriptor disagrees with dataset handoff", + )); + } + Ok(()) +} + +fn registered_physical( + plan: &DatasetBuildPlan, + binding: Option<&str>, +) -> RunnerResult> { + let DatasetRecipe::Registered { reference, .. } = &plan.dataset else { + return Ok(None); + }; + let binding = binding.ok_or_else(|| { + RunnerError::new( + "fixture_binding_missing", + "registered dataset requires --fixture ID=BUNDLE", + ) + })?; + let (id, bundle) = binding + .split_once('=') + .ok_or_else(|| RunnerError::new("fixture_binding_invalid", "expected ID=BUNDLE"))?; + if id != reference.definition.fixture_id { + return Err(RunnerError::new( + "fixture_binding_invalid", + "fixture id differs from case reference", + )); + } + let (descriptor, _) = load_source_descriptor(&Path::new(bundle).join("fixture-source.json")) + .map_err(|e| RunnerError::new("fixture_binding_invalid", format!("{e:?}")))?; + if descriptor.fixture_id != reference.definition.fixture_id { + return Err(RunnerError::new( + "fixture_binding_invalid", + "source descriptor fixture ID differs from the reference", + )); + } + let root = std::fs::symlink_metadata(Path::new(bundle).join("root")) + .map_err(|e| RunnerError::new("fixture_binding_invalid", e.to_string()))?; + if !root.is_dir() { + return Err(RunnerError::new( + "fixture_binding_invalid", + "registered root must be a real directory", + )); + } + Ok(Some(descriptor.physical)) +} + +#[cfg(unix)] +pub fn acquire( + plan: &DatasetBuildPlan, + cache: &Path, + executable: &Path, + no_build: bool, + binding: Option<&str>, +) -> RunnerResult { + plan.revalidate() + .map_err(|e| RunnerError::new("invalid_case", e))?; + let registered_physical = registered_physical(plan, binding)?; + std::fs::create_dir_all(cache).map_err(|e| error(e.to_string()))?; + let cache = cache.canonicalize().map_err(|e| error(e.to_string()))?; + let key = cache_key(plan, &cache, registered_physical.as_ref())?; + let root = cache.join(&key); + match std::fs::create_dir(&root) { + Ok(()) => {} + Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {} + Err(e) => return Err(error(e.to_string())), + } + if !std::fs::symlink_metadata(&root) + .map_err(|e| error(e.to_string()))? + .is_dir() + { + return Err(error("cache entry is not a real directory")); + } + use std::os::unix::fs::OpenOptionsExt; + let directory = OpenOptions::new() + .read(true) + .custom_flags(nix::libc::O_NOFOLLOW | nix::libc::O_DIRECTORY) + .open(&root) + .map_err(|e| error(e.to_string()))?; + let lock = lock(&root)?; + validate_entry(&root, &directory, &lock)?; + let active = root.join("active"); + let template = root.join("root"); + let stamp = root.join("dataset-build.json"); + if is_quarantined(&root)? { + return Err(error(format!( + "{} is quarantined; inspect and remove explicitly", + root.display() + ))); + } + let cache_hit = stamp.exists(); + let manifest = if cache_hit { + let m: DatasetManifestV1 = read_json(&stamp)?; + validate_manifest_identity(&m, &key, Some(plan))?; + validate_published_paths(&root)?; + m + } else { + if no_build { + return Err(RunnerError::new( + "dataset_cache_miss", + "--no-build requires a published matching dataset", + )); + } + let leftovers = std::fs::read_dir(&root) + .map_err(|e| error(e.to_string()))? + .collect::, _>>() + .map_err(|e| error(e.to_string()))?; + if leftovers.iter().any(|entry| entry.file_name() != "lock") { + validate_entry(&root, &directory, &lock)?; + write_quarantine( + &root, + &directory, + "unpublished state has no proven process containment", + )?; + return Err(error( + "unpublished dataset state requires explicit inspection and cleanup", + )); + } + validate_entry(&root, &directory, &lock)?; + std::fs::create_dir(&active).map_err(|e| error(e.to_string()))?; + validate_entry(&root, &directory, &lock)?; + let handoff = match crate::dataset_worker::supervise_fixture_build( + executable, + plan, + binding, + &active, + &template, + &root, + Duration::from_secs(3600), + ) { + Ok(h) => h, + Err(mut e) => { + if !contained(&e) + && let Err(marker) = validate_entry(&root, &directory, &lock) + .and_then(|_| write_quarantine(&root, &directory, &e.message)) + { + e.message + .push_str(&format!("; quarantine marker failed: {}", marker.message)); + } + return Err(e); + } + }; + validate_entry(&root, &directory, &lock)?; + if active.exists() { + return Err(error("dataset worker did not retire its active store")); + } + reset::verify_physical_tree(&template, &handoff.physical, TraversalLimits::default()) + .map_err(|e| error(e.to_string()))?; + let descriptor = crate::registered_fixture::RegisteredFixtureSourceV1 { + format_version: 1, + fixture_id: format!("gqt-{key}"), + physical: RegisteredPhysicalTreeV1 { + digest_algorithm: crate::reset::PHYSICAL_TREE_DIGEST_ALGORITHM.into(), + tree_sha256: handoff.physical.digest_sha256.clone(), + files: handoff.physical.files, + bytes: handoff.physical.bytes, + }, + }; + validate_entry(&root, &directory, &lock)?; + let mut descriptor_file = OpenOptions::new() + .write(true) + .create_new(true) + .open(root.join("fixture-source.json")) + .map_err(|e| error(e.to_string()))?; + descriptor_file + .write_all(&serde_json::to_vec(&descriptor).map_err(|e| error(e.to_string()))?) + .and_then(|_| descriptor_file.sync_all()) + .map_err(|e| error(e.to_string()))?; + let m = DatasetManifestV1 { + format_version: 1, + key: key.clone(), + recipe_sha256: plan.recipe_sha256.clone(), + engine_digest: GQT_ENGINE_DIGEST.into(), + needs_indices: plan.needs_indices, + reset: plan.reset, + handoff, + }; + let bytes = serde_json::to_vec(&m).map_err(|e| error(e.to_string()))?; + if bytes.len() > MAX_DATASET_MANIFEST_BYTES { + return Err(error("dataset manifest exceeds 1 MiB")); + } + validate_entry(&root, &directory, &lock)?; + let pending = root.join("dataset-build.pending"); + let mut file = OpenOptions::new() + .write(true) + .create_new(true) + .open(&pending) + .map_err(|e| error(e.to_string()))?; + file.write_all(&bytes) + .and_then(|_| file.sync_all()) + .map_err(|e| error(e.to_string()))?; + validate_entry(&root, &directory, &lock)?; + std::fs::rename(&pending, &stamp).map_err(|e| error(e.to_string()))?; + File::open(&root) + .and_then(|f| f.sync_all()) + .map_err(|e| error(e.to_string()))?; + m + }; + let lease = DatasetLease { + root, + active, + template, + manifest, + cache_hit, + _directory: directory, + _lock: lock, + }; + lease.verify()?; + validate_descriptor(&lease.root, &lease.manifest)?; + reset::verify_physical_tree( + &lease.template, + &lease.manifest.handoff.physical, + TraversalLimits::default(), + ) + .map_err(|e| error(e.to_string()))?; + Ok(lease) +} +fn read_json Deserialize<'de>>(path: &Path) -> RunnerResult { + let mut options = OpenOptions::new(); + options.read(true); + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + options.custom_flags(nix::libc::O_NOFOLLOW | nix::libc::O_NONBLOCK); + } + let f = options.open(path).map_err(|e| error(e.to_string()))?; + let m = f.metadata().map_err(|e| error(e.to_string()))?; + if !m.is_file() || m.len() > MAX_DATASET_MANIFEST_BYTES as u64 { + return Err(error("dataset manifest is not a bounded regular file")); + } + let mut bytes = Vec::new(); + f.take(MAX_DATASET_MANIFEST_BYTES as u64 + 1) + .read_to_end(&mut bytes) + .map_err(|e| error(e.to_string()))?; + serde_json::from_slice(&bytes).map_err(|e| error(e.to_string())) +} +#[cfg(unix)] +fn lock(root: &Path) -> RunnerResult> { + use nix::fcntl::{Flock, FlockArg}; + use std::os::unix::fs::{MetadataExt, OpenOptionsExt}; + let path = root.join("lock"); + let started = Instant::now(); + loop { + if started.elapsed() > Duration::from_secs(3600) { + return Err(error("cache lock path changed until timeout")); + } + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(false) + .custom_flags(nix::libc::O_NOFOLLOW | nix::libc::O_NONBLOCK) + .open(&path) + .map_err(|e| error(e.to_string()))?; + loop { + match Flock::lock(file, FlockArg::LockExclusiveNonblock) { + Ok(lock) => { + let a = lock.metadata().map_err(|e| error(e.to_string()))?; + let b = std::fs::symlink_metadata(&path).map_err(|e| error(e.to_string()))?; + if a.is_file() + && !b.file_type().is_symlink() + && a.dev() == b.dev() + && a.ino() == b.ino() + { + return Ok(lock); + } + drop(lock); + break; + } + Err((returned, e)) if e == nix::errno::Errno::EWOULDBLOCK => file = returned, + Err((_, e)) => return Err(error(e.to_string())), + } + if started.elapsed() > Duration::from_secs(3600) { + return Err(RunnerError::new( + "dataset_lock_timeout", + "dataset cache lock exceeded one hour", + )); + } + std::thread::sleep(Duration::from_millis(20)); + } + } +} +pub fn contained(error: &RunnerError) -> bool { + error + .context + .child_process + .as_ref() + .is_some_and(|e| e.direct_child_reaped && e.process_group_gone && e.stdio_closed_cleanly) +} + +#[cfg(unix)] +fn validate_entry(root: &Path, directory: &File, lock: &File) -> RunnerResult<()> { + validate_path(root, directory)?; + validate_path(&root.join("lock"), lock) +} + +#[cfg(unix)] +fn validate_path(path: &Path, file: &File) -> RunnerResult<()> { + use std::os::unix::fs::MetadataExt; + let a = file.metadata().map_err(|e| error(e.to_string()))?; + let b = std::fs::symlink_metadata(path).map_err(|e| error(e.to_string()))?; + if b.file_type().is_symlink() || a.dev() != b.dev() || a.ino() != b.ino() { + return Err(error( + "cache directory or lock pathname changed while owned", + )); + } + Ok(()) +} + +fn cache_key( + plan: &DatasetBuildPlan, + cache: &Path, + registered: Option<&RegisteredPhysicalTreeV1>, +) -> RunnerResult { + crate::model::typed_sha256(&( + "gqt-dataset-cache-v1", + &plan.recipe_sha256, + GQT_ENGINE_DIGEST, + plan.needs_indices, + &plan.environment.backend, + plan.reset, + cache, + registered, + )) + .map_err(|e| error(e.to_string())) +} +/// Structural handoff checks also apply when validating a durable archive record. +pub(crate) fn validate_manifest_evidence(manifest: &DatasetManifestV1) -> Result<(), String> { + if serde_json::to_vec(manifest) + .map_err(|e| e.to_string())? + .len() + > MAX_DATASET_MANIFEST_BYTES + { + return Err("dataset manifest exceeds 1 MiB".into()); + } + let h = &manifest.handoff; + crate::dataset_identity::validate(&h.summary, h.registered_source_identity.as_deref())?; + for digest in [ + &manifest.key, + &manifest.recipe_sha256, + &manifest.engine_digest, + &h.physical.digest_sha256, + &h.template_metadata.shape_sha256, + &h.template_metadata.state_sha256, + ] { + if !valid_digest(digest) { + return Err("invalid dataset manifest digest".into()); + } + } + let m = &h.template_metadata; + if manifest.format_version != 1 + || manifest.reset == ResetMode::S3Versioning + || h.physical.files == 0 + || h.physical.bytes == 0 + || h.physical.files != m.files + || h.physical.bytes != m.bytes + || m.files.checked_add(m.directories) != Some(m.entries) + { + return Err("invalid dataset physical/metadata handoff".into()); + } + Ok(()) +} + +#[cfg(all(test, unix))] +mod tests { + use super::*; + fn plan() -> DatasetBuildPlan { + let dataset = + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../benchmarks/fixtures/tiny_graph.gqt"); + crate::gqt_case::dataset_file( + &dataset, + None, + crate::case::Backend::LocalFs { + filesystem: crate::case::LocalFilesystem::Xfs, + storage_class: crate::case::LocalStorageClass::NvmeSsd, + }, + ResetMode::PlainCopy, + ) + .unwrap() + } + fn refused(plan: &DatasetBuildPlan, cache: &Path, no_build: bool) -> RunnerError { + match acquire( + plan, + cache, + Path::new("/does-not-exist-worker"), + no_build, + None, + ) { + Ok(_) => panic!("unexpected cache admission"), + Err(e) => e, + } + } + async fn published(plan: &DatasetBuildPlan, cache: &Path) -> PathBuf { + assert_eq!(refused(plan, cache, true).code, "dataset_cache_miss"); + let root = cache.join(cache_key(plan, cache, None).unwrap()); + let active = root.join("active"); + let scratch = root.join("scratch"); + std::fs::create_dir(&scratch).unwrap(); + let (summary, registered_source_identity) = + crate::dataset_worker::build_dataset(plan, active.to_str().unwrap(), &scratch, None) + .await + .unwrap(); + let frozen = reset::freeze_plain_copy_template( + &active, + &root.join("root"), + TraversalLimits::default(), + ) + .unwrap(); + let handoff = FixtureBuildHandoff { + summary, + registered_source_identity, + physical: frozen.physical_digest().clone(), + template_metadata: frozen.metadata_digest().clone(), + }; + std::fs::remove_dir_all(active).unwrap(); + let manifest = DatasetManifestV1 { + format_version: 1, + key: root.file_name().unwrap().to_str().unwrap().into(), + recipe_sha256: plan.recipe_sha256.clone(), + engine_digest: GQT_ENGINE_DIGEST.into(), + needs_indices: plan.needs_indices, + reset: plan.reset, + handoff, + }; + validate_manifest_evidence(&manifest).unwrap(); + let descriptor = crate::registered_fixture::RegisteredFixtureSourceV1 { + format_version: 1, + fixture_id: format!("gqt-{}", manifest.key), + physical: RegisteredPhysicalTreeV1 { + digest_algorithm: reset::PHYSICAL_TREE_DIGEST_ALGORITHM.into(), + tree_sha256: manifest.handoff.physical.digest_sha256.clone(), + files: manifest.handoff.physical.files, + bytes: manifest.handoff.physical.bytes, + }, + }; + std::fs::write( + root.join("fixture-source.json"), + serde_json::to_vec(&descriptor).unwrap(), + ) + .unwrap(); + std::fs::write( + root.join("dataset-build.json"), + serde_json::to_vec(&manifest).unwrap(), + ) + .unwrap(); + root + } + #[test] + fn miss_and_unknown_build_state_never_spawn_or_remove_unproved_work() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().canonicalize().unwrap(); + let plan = plan(); + assert_eq!(refused(&plan, &cache, true).code, "dataset_cache_miss"); + let root = cache.join(cache_key(&plan, &cache, None).unwrap()); + assert_eq!(std::fs::read_dir(&root).unwrap().count(), 1); + std::fs::create_dir(root.join("active")).unwrap(); + std::fs::write(root.join("active/owner"), b"possibly live child").unwrap(); + assert_eq!(refused(&plan, &cache, false).code, "dataset_cache_corrupt"); + assert_eq!( + std::fs::read(root.join("active/owner")).unwrap(), + b"possibly live child" + ); + assert!(root.join("quarantined").is_file()); + } + + #[test] + fn inspection_preserves_missing_roots_entries_locks_and_unpublished_state() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().join("absent"); + let plan = plan(); + assert_eq!( + inspect(&plan, &cache, None, false).cache, + CacheState::Missing + ); + assert_eq!( + list(&cache, 10, None, false).unwrap().root_state, + CacheState::Missing + ); + assert!(!cache.exists()); + std::fs::create_dir(&cache).unwrap(); + let cache = cache.canonicalize().unwrap(); + let status = inspect(&plan, &cache, None, true); + assert_eq!(status.source, Some(SourceAvailability::Available)); + assert_eq!(status.cache, CacheState::Missing); + assert_eq!(std::fs::read_dir(&cache).unwrap().count(), 0); + let root = status.path; + std::fs::create_dir(&root).unwrap(); + assert_eq!( + inspect(&plan, &cache, None, false).cache, + CacheState::Unknown + ); + assert!(!root.join("lock").exists()); + std::fs::write(root.join("lock"), b"").unwrap(); + std::fs::create_dir(root.join("active")).unwrap(); + std::fs::write(root.join("active/owner"), b"possibly live child").unwrap(); + assert_eq!( + inspect(&plan, &cache, None, true).cache, + CacheState::Incomplete + ); + assert_eq!( + std::fs::read(root.join("active/owner")).unwrap(), + b"possibly live child" + ); + assert!(!root.join("quarantined").exists()); + std::fs::write(root.join("quarantined"), b"keep this reason").unwrap(); + assert_eq!( + inspect(&plan, &cache, None, false).cache, + CacheState::Invalid + ); + assert_eq!( + std::fs::read(root.join("quarantined")).unwrap(), + b"keep this reason" + ); + } + + #[test] + fn inspection_reports_busy_without_waiting_for_an_exclusive_owner() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().canonicalize().unwrap(); + let plan = plan(); + let root = cache.join(cache_key(&plan, &cache, None).unwrap()); + std::fs::create_dir(&root).unwrap(); + let owner = lock(&root).unwrap(); + let (sender, receiver) = std::sync::mpsc::channel(); + let inspector = std::thread::spawn(move || { + sender.send(inspect(&plan, &cache, None, false)).unwrap(); + }); + let result = receiver.recv_timeout(Duration::from_secs(5)); + drop(owner); + inspector.join().unwrap(); + assert_eq!(result.unwrap().cache, CacheState::Busy); + } + + #[test] + fn inspection_refuses_symlink_entries_and_locks_without_touching_targets() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().join("cache"); + std::fs::create_dir(&cache).unwrap(); + let cache = cache.canonicalize().unwrap(); + let outside = directory.path().join("outside"); + std::fs::create_dir(&outside).unwrap(); + std::fs::write(outside.join("sentinel"), b"untouched").unwrap(); + let plan = plan(); + let root = cache.join(cache_key(&plan, &cache, None).unwrap()); + let alias = directory.path().join("alias"); + std::os::unix::fs::symlink(&cache, &alias).unwrap(); + for path in [&alias, &alias.join(".")] { + assert_eq!( + inspect(&plan, path, None, false), + inspect(&plan, &cache, None, false) + ); + assert_eq!( + list(path, 10, None, false).unwrap(), + list(&cache, 10, None, false).unwrap() + ); + } + std::os::unix::fs::symlink(&outside, &root).unwrap(); + assert_eq!( + inspect(&plan, &cache, None, false).cache, + CacheState::Invalid + ); + std::fs::remove_file(&root).unwrap(); + std::fs::create_dir(&root).unwrap(); + std::os::unix::fs::symlink(outside.join("absent"), root.join("lock")).unwrap(); + assert_eq!( + inspect(&plan, &cache, None, false).cache, + CacheState::Unknown + ); + assert_eq!(std::fs::read_dir(&outside).unwrap().count(), 1); + assert_eq!( + std::fs::read(outside.join("sentinel")).unwrap(), + b"untouched" + ); + for (name, target) in [ + ("dangling", outside.join("absent")), + ("file", outside.join("sentinel")), + ("loop", directory.path().join("loop")), + ] { + let alias = directory.path().join(name); + std::os::unix::fs::symlink(target, &alias).unwrap(); + assert!(list(&alias, 10, None, false).is_err()); + assert_eq!( + inspect(&plan, &alias, None, false).cache, + CacheState::Unknown + ); + } + assert!(!outside.join("absent").exists()); + } + + #[tokio::test] + async fn inspection_separates_presence_verification_and_historical_identity() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().canonicalize().unwrap(); + let plan = plan(); + let root = published(&plan, &cache).await; + let before = reset::digest_metadata_tree(&root, TraversalLimits::default()).unwrap(); + assert_eq!( + inspect(&plan, &cache, None, false).cache, + CacheState::Present + ); + assert_eq!(inspect(&plan, &cache, None, true).cache, CacheState::Cached); + let aliases = tempfile::tempdir().unwrap(); + let alias = aliases.path().join("cache"); + std::os::unix::fs::symlink(&cache, &alias).unwrap(); + for path in [&alias, &alias.join(".")] { + assert_eq!( + inspect(&plan, path, None, true), + inspect(&plan, &cache, None, true) + ); + assert_eq!( + list(path, 10, None, true).unwrap(), + list(&cache, 10, None, true).unwrap() + ); + } + assert_eq!( + before, + reset::digest_metadata_tree(&root, TraversalLimits::default()).unwrap() + ); + let stamp = root.join("dataset-build.json"); + let mut historical: DatasetManifestV1 = read_json(&stamp).unwrap(); + historical.engine_digest = "0".repeat(64); + std::fs::write(&stamp, serde_json::to_vec(&historical).unwrap()).unwrap(); + assert_eq!( + inspect(&plan, &cache, None, false).cache, + CacheState::Invalid + ); + assert_eq!( + list(&cache, 10, None, true).unwrap().entries[0].cache, + CacheState::Cached + ); + std::fs::write(root.join("root/unexpected"), b"changed").unwrap(); + assert_eq!( + list(&cache, 10, None, true).unwrap().entries[0].cache, + CacheState::Invalid + ); + std::fs::remove_file(root.join("fixture-source.json")).unwrap(); + assert_eq!( + list(&cache, 10, None, false).unwrap().entries[0].cache, + CacheState::Invalid + ); + assert!(!root.join("quarantined").exists()); + } + + #[test] + fn inspection_listing_is_bounded_sorted_and_preserves_unknown_entries() { + let directory = tempfile::tempdir().unwrap(); + for name in ["f".repeat(64), "1".repeat(64), "unrecognized".into()] { + std::fs::create_dir(directory.path().join(name)).unwrap(); + } + let first = list(directory.path(), 1, None, false).unwrap(); + assert_eq!( + first.entries[0].key.as_deref(), + Some("1".repeat(64).as_str()) + ); + assert_eq!(first.entries[0].cache, CacheState::Unknown); + let second = list(directory.path(), 1, first.next_cursor.as_deref(), false).unwrap(); + assert_eq!( + second.entries[0].key.as_deref(), + Some("f".repeat(64).as_str()) + ); + let third = list(directory.path(), 1, second.next_cursor.as_deref(), false).unwrap(); + assert_eq!(third.entries[0].key, None); + assert_eq!(third.entries[0].cache, CacheState::Unknown); + assert_eq!(third.next_cursor, None); + assert!(list(directory.path(), 0, None, false).is_err()); + assert!(list(directory.path(), MAX_INSPECTION_PAGE + 1, None, false).is_err()); + for entry in std::fs::read_dir(directory.path()).unwrap() { + assert_eq!(std::fs::read_dir(entry.unwrap().path()).unwrap().count(), 0); + } + } + + #[test] + fn invalid_frozen_source_never_becomes_a_cache_miss() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().join("absent"); + let mut plan = plan(); + plan.needs_indices = !plan.needs_indices; + let result = inspect(&plan, &cache, None, false); + assert_eq!(result.source, Some(SourceAvailability::Invalid)); + assert_eq!(result.cache, CacheState::Unknown); + assert_eq!(result.key, None); + assert!(!cache.exists()); + } + + #[test] + fn registered_source_availability_is_independent_of_cache_availability() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().join("absent"); + let config = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../benchmarks/benchmarks.yaml"); + let plan = crate::catalog::Catalog::load(&config) + .unwrap() + .plan("finbench-disjoint-merge") + .unwrap() + .dataset_build_plan(); + let DatasetRecipe::Registered { reference, .. } = &plan.dataset else { + panic!("registered fixture required"); + }; + let unbound = inspect(&plan, &cache, None, false); + assert_eq!(unbound.source, Some(SourceAvailability::Unbound)); + assert_eq!(unbound.cache, CacheState::Unknown); + let binding = format!("{}={}", reference.definition.fixture_id, cache.display()); + let missing = inspect(&plan, &cache, Some(&binding), false); + assert_eq!(missing.source, Some(SourceAvailability::Missing)); + assert_eq!(missing.cache, CacheState::Unknown); + let invalid = inspect(&plan, &cache, Some("different-id=missing"), false); + assert_eq!(invalid.source, Some(SourceAvailability::Invalid)); + assert_eq!(invalid.cache, CacheState::Unknown); + assert!(!cache.exists()); + let bundle = directory.path().join("bundle"); + std::fs::create_dir(&bundle).unwrap(); + let source = bundle.join("root"); + std::fs::create_dir(&source).unwrap(); + std::fs::write(source.join("data"), b"source").unwrap(); + let descriptor = crate::registered_fixture::fingerprint_registered_fixture( + reference.definition.fixture_id.clone(), + &source, + ) + .into_result() + .unwrap(); + std::fs::write( + bundle.join("fixture-source.json"), + serde_json::to_vec(&descriptor).unwrap(), + ) + .unwrap(); + let binding = format!("{}={}", reference.definition.fixture_id, bundle.display()); + assert_eq!( + inspect(&plan, &cache, Some(&binding), false).source, + Some(SourceAvailability::Available) + ); + std::fs::rename(&source, bundle.join("saved-root")).unwrap(); + assert_eq!( + inspect(&plan, &cache, Some(&binding), false).source, + Some(SourceAvailability::Missing) + ); + std::os::unix::fs::symlink(bundle.join("saved-root"), &source).unwrap(); + assert_eq!( + inspect(&plan, &cache, Some(&binding), false).source, + Some(SourceAvailability::Invalid) + ); + std::fs::remove_file(&source).unwrap(); + std::fs::rename(bundle.join("saved-root"), &source).unwrap(); + let mut wrong = descriptor; + wrong.fixture_id = "wrong-id".into(); + std::fs::write( + bundle.join("fixture-source.json"), + serde_json::to_vec(&wrong).unwrap(), + ) + .unwrap(); + assert_eq!( + inspect(&plan, &cache, Some(&binding), false).source, + Some(SourceAvailability::Invalid) + ); + assert!(!cache.exists()); + } + #[test] + fn cache_entry_symlink_is_refused_without_touching_its_target() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().join("cache"); + std::fs::create_dir(&cache).unwrap(); + let cache = cache.canonicalize().unwrap(); + let outside = directory.path().join("outside"); + std::fs::create_dir(&outside).unwrap(); + std::fs::write(outside.join("sentinel"), b"untouched").unwrap(); + let plan = plan(); + std::os::unix::fs::symlink( + &outside, + cache.join(cache_key(&plan, &cache, None).unwrap()), + ) + .unwrap(); + assert_eq!(refused(&plan, &cache, false).code, "dataset_cache_corrupt"); + assert_eq!(std::fs::read_dir(outside).unwrap().count(), 1); + } + #[test] + fn quarantine_markers_refuse_reuse_without_following_symlinks() { + for no_build in [false, true] { + for live_target in [false, true] { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().join("cache"); + std::fs::create_dir(&cache).unwrap(); + let cache = cache.canonicalize().unwrap(); + let plan = plan(); + assert_eq!(refused(&plan, &cache, true).code, "dataset_cache_miss"); + let root = cache.join(cache_key(&plan, &cache, None).unwrap()); + let outside = directory.path().join("outside"); + if live_target { + std::fs::write(&outside, b"untouched").unwrap(); + } + std::os::unix::fs::symlink(&outside, root.join("quarantined")).unwrap(); + assert_eq!( + refused(&plan, &cache, no_build).code, + "dataset_cache_corrupt" + ); + if live_target { + assert_eq!(std::fs::read(&outside).unwrap(), b"untouched"); + } else { + assert!(!outside.exists()); + } + } + } + } + #[tokio::test] + async fn published_hit_requires_descriptor_bytes_and_the_original_lock_inode() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().canonicalize().unwrap(); + let plan = plan(); + let root = published(&plan, &cache).await; + let lease = acquire(&plan, &cache, Path::new("/unused-worker"), true, None).unwrap(); + assert!(lease.cache_hit); + lease.restore().unwrap(); + lease.remove_active().unwrap(); + let outside = directory.path().join("outside-marker"); + std::os::unix::fs::symlink(&outside, root.join("quarantined")).unwrap(); + assert!(lease.verify().is_err()); + lease.quarantine("uncertain child").unwrap(); + assert!(!outside.exists()); + std::fs::remove_file(root.join("quarantined")).unwrap(); + lease.quarantine("first reason").unwrap(); + lease.quarantine("second reason").unwrap(); + assert_eq!( + std::fs::read(root.join("quarantined")).unwrap(), + b"first reason" + ); + std::fs::remove_file(root.join("quarantined")).unwrap(); + std::fs::rename(root.join("lock"), root.join("old-lock")).unwrap(); + std::fs::write(root.join("lock"), b"").unwrap(); + assert!(lease.verify().is_err()); + drop(lease); + std::fs::remove_file(root.join("fixture-source.json")).unwrap(); + assert_eq!(refused(&plan, &cache, true).code, "dataset_cache_corrupt"); + } + #[tokio::test] + async fn published_tree_or_logical_receipt_tampering_is_corruption_not_a_miss() { + let directory = tempfile::tempdir().unwrap(); + let cache = directory.path().canonicalize().unwrap(); + let plan = plan(); + let root = published(&plan, &cache).await; + let stamp = root.join("dataset-build.json"); + let original = std::fs::read(&stamp).unwrap(); + let mut oversized: DatasetManifestV1 = serde_json::from_slice(&original).unwrap(); + let logical = &mut oversized.handoff.summary; + let main = logical.branches[0].clone(); + for index in 0..1023 { + let mut branch = main.clone(); + branch.name = format!("{index:04}{}", "x".repeat(1020)); + logical.branches.push(branch); + } + logical.branches.sort_by(|a, b| a.name.cmp(&b.name)); + logical.logical_content_sha256 = crate::model::typed_sha256(&( + crate::dataset_identity::DATASET_LOGICAL_ALGORITHM, + &logical.branches, + )) + .unwrap(); + crate::dataset_identity::validate(logical, None).unwrap(); + assert_eq!( + validate_manifest_evidence(&oversized).unwrap_err(), + "dataset manifest exceeds 1 MiB" + ); + let mut manifest: DatasetManifestV1 = serde_json::from_slice(&original).unwrap(); + manifest.handoff.summary.branches.clear(); + std::fs::write(&stamp, serde_json::to_vec(&manifest).unwrap()).unwrap(); + assert_eq!(refused(&plan, &cache, false).code, "dataset_cache_corrupt"); + std::fs::write(&stamp, original).unwrap(); + std::fs::write(root.join("root/unexpected"), b"changed").unwrap(); + assert_eq!(refused(&plan, &cache, false).code, "dataset_cache_corrupt"); + } +} diff --git a/crates/omnigraph-bench/src/dataset_identity.rs b/crates/omnigraph-bench/src/dataset_identity.rs new file mode 100644 index 000000000..f189b428a --- /dev/null +++ b/crates/omnigraph-bench/src/dataset_identity.rs @@ -0,0 +1,359 @@ +//! Rebuild-stable current-content and lineage-shape witnesses. Historical row +//! images and unkeyed edge identities are outside this equivalence domain. +use crate::gqt_case::sha256_bytes; +use crate::model::typed_sha256; +use omnigraph::db::Omnigraph; +use serde::{Deserialize, Serialize}; +use std::collections::{BTreeMap, BTreeSet}; +use std::io::Write; +use std::path::Path; +pub const DATASET_LOGICAL_ALGORITHM: &str = "omnigraph-gqt-branches-lineage-equivalence-v1"; +pub const REGISTERED_LOGICAL_ALGORITHM: &str = + "omnigraph-gqt-branches-lineage-and-registered-identities-v1"; +const MAX_COMMITS: usize = 1_000_000; +const MAX_BRANCHES: usize = 1024; +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct BranchLogicalV1 { + pub name: String, + pub content_sha256: String, + pub schema_sha256: String, + pub lineage_sha256: String, + pub history_commits: u64, + pub node_tables: Vec, + pub edge_tables: Vec, + pub indexes: Vec, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct DatasetLogicalV1 { + pub algorithm: String, + pub logical_content_sha256: String, + pub branches: Vec, + pub relocation_self_contained: bool, + pub limitations: Vec, +} +pub async fn observe(root: &Path) -> Result { + let db = Omnigraph::open_read_only(root.to_str().ok_or("non-UTF8 dataset path")?) + .await + .map_err(|e| e.to_string())?; + let mut names = db.branch_list().await.map_err(|e| e.to_string())?; + names.sort(); + names.dedup(); + if names.is_empty() || names.len() > MAX_BRANCHES { + return Err("dataset branch inventory exceeds its bound".into()); + } + let mut branches = Vec::new(); + let mut self_contained = true; + for name in &names { + let observed = crate::real_graph::observe_branch(&db, name, names.clone()) + .await + .map_err(|e| e.to_string())?; + let (lineage_sha256, history_commits) = lineage(&db, name).await?; + self_contained &= observed.relocation_self_contained; + branches.push(BranchLogicalV1 { + name: name.clone(), + content_sha256: observed.logical_content.sha256, + schema_sha256: observed.schema_shape.sha256, + lineage_sha256, + history_commits, + node_tables: observed.node_tables, + edge_tables: observed.edge_tables, + indexes: observed.indexes, + }); + } + if db + .branch_list() + .await + .map_err(|e| e.to_string())? + .into_iter() + .collect::>() + != names.into_iter().collect() + { + return Err("dataset branches changed during observation".into()); + } + let logical_content_sha256 = + typed_sha256(&(DATASET_LOGICAL_ALGORITHM, &branches)).map_err(|e| e.to_string())?; + Ok(DatasetLogicalV1 { + algorithm: DATASET_LOGICAL_ALGORITHM.into(), + logical_content_sha256, + branches, + relocation_self_contained: self_contained, + limitations: vec![ + "unkeyed-edge-ids-excluded".into(), + "historical-row-images-not-attested".into(), + ], + }) +} +async fn lineage(db: &Omnigraph, branch: &str) -> Result<(String, u64), String> { + let head = db + .resolve_snapshot(branch) + .await + .map_err(|e| e.to_string())? + .as_str() + .to_owned(); + let mut pending = vec![head.clone()]; + let mut commits = BTreeMap::new(); + while let Some(id) = pending.pop() { + if commits.contains_key(&id) { + continue; + } + if commits.len() >= MAX_COMMITS { + return Err("dataset history exceeds the lineage visit budget".into()); + } + let c = db + .get_commit(&id) + .await + .map_err(|e| format!("required dataset history {id} unavailable: {e}"))?; + if c.graph_commit_id != id { + return Err("history lookup returned another commit identity".into()); + } + for parent in [&c.parent_commit_id, &c.merged_parent_commit_id] + .into_iter() + .flatten() + { + pending.push(parent.clone()) + } + commits.insert(id, c); + } + normalized_lineage(&head, &commits) +} +fn normalized_lineage( + head: &str, + commits: &BTreeMap, +) -> Result<(String, u64), String> { + if commits.is_empty() || commits.len() > MAX_COMMITS || !commits.contains_key(head) { + return Err("lineage head or inventory is unavailable".into()); + } + let mut ordered = commits.values().collect::>(); + ordered.sort_by_key(|c| c.generation); + let mut hashes = BTreeMap::new(); + let mut multiset = Vec::new(); + for c in ordered { + let parent = |id: &Option| -> Result, String> { + id.as_ref() + .map(|id| { + let parent = commits.get(id).ok_or("missing lineage parent")?; + if parent.generation >= c.generation { + return Err("lineage parent generation must be strictly smaller".into()); + } + hashes + .get(id) + .cloned() + .ok_or_else(|| "cyclic or non-increasing commit generation".into()) + }) + .transpose() + }; + let hash = typed_sha256(&( + "omnigraph-lineage-shape-v1", + &c.graph_branch, + c.generation, + &c.actor_id, + parent(&c.parent_commit_id)?, + parent(&c.merged_parent_commit_id)?, + )) + .map_err(|e| e.to_string())?; + hashes.insert(c.graph_commit_id.clone(), hash.clone()); + multiset.push(hash); + } + multiset.sort(); + let hash = typed_sha256(&( + "omnigraph-lineage-dag-shape-v1", + hashes.get(head), + &multiset, + )) + .map_err(|e| e.to_string())?; + Ok((hash, commits.len() as u64)) +} +/// The registered source is fixed: retain IDs as logical identity, before any +/// GQT preparation introduces automatically generated edge IDs. +pub async fn registered_identity(root: &Path) -> Result { + let db = Omnigraph::open_read_only(root.to_str().ok_or("non-UTF8 source path")?) + .await + .map_err(|e| e.to_string())?; + let mut branches = db.branch_list().await.map_err(|e| e.to_string())?; + branches.sort(); + let mut evidence = Vec::new(); + for branch in branches { + let mut sink = IdentitySink::default(); + db.export_jsonl_unordered_to_writer(&branch, &[], &mut sink) + .await + .map_err(|e| e.to_string())?; + if !sink.pending.is_empty() { + return Err("unterminated registered export".into()); + } + evidence.push((branch, sink.rows, sink.sum)); + } + typed_sha256(&("omnigraph-export-identities-multiset-v1", evidence)).map_err(|e| e.to_string()) +} +#[derive(Default)] +struct IdentitySink { + pending: Vec, + sum: [u8; 32], + rows: u64, +} +impl Write for IdentitySink { + fn write(&mut self, bytes: &[u8]) -> std::io::Result { + self.pending.extend_from_slice(bytes); + while let Some(n) = self.pending.iter().position(|b| *b == b'\n') { + if n > 16 * 1024 * 1024 { + return Err(std::io::Error::other("registered export row exceeds bound")); + } + let line = self.pending.drain(..=n).collect::>(); + if n == 0 { + continue; + } + let value: serde_json::Value = + serde_json::from_slice(&line[..n]).map_err(std::io::Error::other)?; + let canonical = + crate::real_graph::canonical_json_bytes(&value).map_err(std::io::Error::other)?; + let hash = sha256_bytes(&canonical); + let mut carry = 0u16; + for (i, pair) in hash.as_bytes().chunks(2).enumerate().rev() { + let part = std::str::from_utf8(pair).map_err(std::io::Error::other)?; + let byte = u8::from_str_radix(part, 16).map_err(std::io::Error::other)?; + let sum = u16::from(self.sum[i]) + u16::from(byte) + carry; + self.sum[i] = sum as u8; + carry = sum >> 8; + } + self.rows = self + .rows + .checked_add(1) + .ok_or_else(|| std::io::Error::other("registered row count overflow"))?; + } + if self.pending.len() > 16 * 1024 * 1024 { + return Err(std::io::Error::other("registered export row exceeds bound")); + } + Ok(bytes.len()) + } + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +pub fn validate(logical: &DatasetLogicalV1, registered: Option<&str>) -> Result<(), String> { + if logical.branches.is_empty() + || logical.branches.len() > MAX_BRANCHES + || logical.branches.windows(2).any(|b| b[0].name >= b[1].name) + || !logical.branches.iter().any(|b| b.name == "main") + { + return Err("invalid canonical dataset branch inventory".into()); + } + for b in &logical.branches { + if b.name.is_empty() + || b.name.len() > 1024 + || b.history_commits == 0 + || b.history_commits > MAX_COMMITS as u64 + { + return Err("invalid branch history witness".into()); + } + for digest in [&b.content_sha256, &b.schema_sha256, &b.lineage_sha256] { + if !crate::gqt_case::digest(digest) { + return Err("invalid branch digest".into()); + } + } + for tables in [&b.node_tables, &b.edge_tables] { + if tables.len() > 4096 + || tables.windows(2).any(|t| t[0].name >= t[1].name) + || tables + .iter() + .any(|t| t.name.is_empty() || t.name.len() > 1024) + { + return Err("invalid canonical dataset table inventory".into()); + } + } + if b.indexes.len() > 16384 || b.indexes.windows(2).any(|i| i[0] >= i[1]) { + return Err("invalid canonical dataset index inventory".into()); + } + } + let base = + typed_sha256(&(DATASET_LOGICAL_ALGORITHM, &logical.branches)).map_err(|e| e.to_string())?; + let expected = match (logical.algorithm.as_str(), registered) { + (DATASET_LOGICAL_ALGORITHM, None) => base, + (REGISTERED_LOGICAL_ALGORITHM, Some(source)) if crate::gqt_case::digest(source) => { + typed_sha256(&(DATASET_LOGICAL_ALGORITHM, &base, source)).map_err(|e| e.to_string())? + } + _ => return Err("unknown dataset logical domain or missing registered witness".into()), + }; + if expected != logical.logical_content_sha256 + || logical.limitations + != [ + "unkeyed-edge-ids-excluded", + "historical-row-images-not-attested", + ] + { + return Err("dataset logical witness digest or limitations mismatch".into()); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn registered_identity_preserves_float_to_edge_id_associations() { + fn digest(rows: &str) -> ([u8; 32], u64) { + let mut sink = IdentitySink::default(); + sink.write_all(rows.as_bytes()).unwrap(); + assert!(sink.pending.is_empty()); + (sink.sum, sink.rows) + } + let first = concat!( + "{\"edge\":\"Transfer\",\"id\":\"e1\",\"from\":\"a\",\"to\":\"b\",\"data\":{\"amount\":0.1000000000001}}\n", + "{\"edge\":\"Transfer\",\"id\":\"e2\",\"from\":\"a\",\"to\":\"b\",\"data\":{\"amount\":0.1000000000002}}\n" + ); + let swapped = first + .replace("e1", "temp") + .replace("e2", "e1") + .replace("temp", "e2"); + assert_ne!(digest(first), digest(&swapped)); + let reordered = first + .lines() + .rev() + .map(|line| { + let value: serde_json::Value = serde_json::from_str(line).unwrap(); + format!("{}\n", serde_json::to_string(&value).unwrap()) + }) + .collect::(); + assert_eq!(digest(first), digest(&reordered)); + assert_eq!(digest(first).1, 2); + } + fn commit(id: &str, generation: u64, parent: Option<&str>) -> omnigraph::db::GraphCommit { + omnigraph::db::GraphCommit { + graph_commit_id: id.into(), + graph_branch: Some("main".into()), + graph_manifest_version: generation, + generation, + parent_commit_id: parent.map(str::to_owned), + merged_parent_commit_id: None, + actor_id: None, + created_at: 0, + } + } + #[test] + fn normalized_history_refuses_missing_or_equal_generation_parents_independent_of_ids() { + for (parent, child) in [("a", "z"), ("z", "a")] { + let malformed = BTreeMap::from([ + (parent.into(), commit(parent, 1, None)), + (child.into(), commit(child, 1, Some(parent))), + ]); + assert!(normalized_lineage(child, &malformed).is_err()); + let missing = BTreeMap::from([(child.into(), commit(child, 2, Some(parent)))]); + assert!(normalized_lineage(child, &missing).is_err()); + } + let first = BTreeMap::from([ + ("a".into(), commit("a", 0, None)), + ("b".into(), commit("b", 1, Some("a"))), + ]); + let mut renamed = BTreeMap::from([ + ("x".into(), commit("x", 0, None)), + ("y".into(), commit("y", 1, Some("x"))), + ]); + renamed.get_mut("y").unwrap().created_at = 500; + renamed.get_mut("y").unwrap().graph_manifest_version = 200; + assert_eq!( + normalized_lineage("b", &first).unwrap(), + normalized_lineage("y", &renamed).unwrap() + ); + } +} diff --git a/crates/omnigraph-bench/src/dataset_worker.rs b/crates/omnigraph-bench/src/dataset_worker.rs new file mode 100644 index 000000000..63f9e1405 --- /dev/null +++ b/crates/omnigraph-bench/src/dataset_worker.rs @@ -0,0 +1,834 @@ +//! Private, bounded process boundary for deterministic fixture construction. +//! +//! Fixture construction performs substantial engine I/O before repetitions +//! begin. Public runs execute it in a dedicated process group so a blocked +//! engine or filesystem operation can be killed and reaped without stranding +//! an in-process task that still owns the disposable store. + +use std::fs::OpenOptions; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use std::process::ExitCode; +#[cfg(unix)] +use std::process::{Command, ExitStatus, Stdio}; +use std::time::Duration; +#[cfg(unix)] +use std::time::Instant; + +use serde::{Deserialize, Serialize}; + +use crate::dataset_identity::DatasetLogicalV1; +use crate::gqt_case::{DatasetBuildPlan, DatasetRecipe}; +use crate::legacy::case::ResetMode; +use crate::reset::{ + MetadataDigest, PhysicalDigest, TraversalLimits, freeze_clonefile_template, + freeze_plain_copy_template, +}; +#[cfg(unix)] +use crate::runner::{ + ChildProcessEvidence, configure_fixture_child_environment, + validate_fixture_child_runtime_overrides, +}; +use crate::runner::{RunnerError, RunnerResult}; + +const FIXTURE_PROTOCOL_VERSION: u32 = 1; +const MAX_FIXTURE_PROTOCOL_BYTES: u64 = 1024 * 1024; +const PROCESS_POLL: Duration = Duration::from_millis(10); +const REAP_DEADLINE: Duration = Duration::from_secs(10); + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct FixtureRequestV1 { + protocol_version: u32, + case: DatasetBuildPlan, + registered_binding: Option, + expected_recipe_sha256: String, + expected_plan_sha256: String, + active_root: PathBuf, + template_root: PathBuf, + fixture_scratch_root: PathBuf, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct FixtureBuildHandoff { + pub summary: DatasetLogicalV1, + pub registered_source_identity: Option, + pub physical: PhysicalDigest, + pub template_metadata: MetadataDigest, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "result", rename_all = "kebab-case", deny_unknown_fields)] +enum FixtureResultV1 { + Complete { + protocol_version: u32, + point_id: String, + case_digest: String, + handoff: Box, + }, + Failed { + protocol_version: u32, + code: String, + message: String, + }, +} + +/// Run the private fixture-builder endpoint using bounded request/result files. +/// +/// Standard streams are deliberately not part of this protocol; the parent +/// redirects both to null, so an untrusted diagnostic burst cannot deadlock or +/// grow parent memory. The result file is create-new and size bounded. +pub async fn run_dataset_worker_files_v1(request_path: &Path, result_path: &Path) -> ExitCode { + let result = run_fixture_worker(request_path).await; + let success = matches!(result, FixtureResultV1::Complete { .. }); + if let Err(error) = write_new_json(result_path, &result) { + eprintln!("fixture worker could not write its bounded result: {error}"); + return ExitCode::from(2); + } + if success { + ExitCode::SUCCESS + } else { + ExitCode::from(1) + } +} + +async fn run_fixture_worker(request_path: &Path) -> FixtureResultV1 { + let request = match read_bounded_json::(request_path) { + Ok(request) if request.protocol_version == FIXTURE_PROTOCOL_VERSION => request, + Ok(request) => { + return failure( + "fixture_protocol_error", + format!( + "fixture request protocol version {} is unsupported; expected {FIXTURE_PROTOCOL_VERSION}", + request.protocol_version + ), + ); + } + Err(error) => return failure("fixture_protocol_error", error), + }; + if let Err(error) = validate_fixture_paths(&request) { + return failure("fixture_protocol_error", error); + } + if let Err(error) = validate_fixture_child_runtime_overrides(&request.fixture_scratch_root) { + return failure(error.code, error.message); + } + execute_fixture_request(request).await +} + +async fn execute_fixture_request(request: FixtureRequestV1) -> FixtureResultV1 { + let case = request.case; + if let Err(e) = case.revalidate() { + return failure("fixture_case_invalid", e); + } + let plan_digest = match case.request_digest() { + Ok(d) => d, + Err(e) => return failure("fixture_case_invalid", e), + }; + if case.recipe_sha256 != request.expected_recipe_sha256 + || plan_digest != request.expected_plan_sha256 + { + return failure( + "fixture_identity_mismatch", + "frozen dataset recipe differs from request", + ); + } + let Some(active_uri) = request.active_root.to_str() else { + return failure("non_utf8_path", "active root is not UTF-8"); + }; + let parsed = match &case.dataset { + DatasetRecipe::Gqt { source } => source.parse(), + DatasetRecipe::Registered { preparation, .. } => preparation.parse(), + }; + let timeout = match parsed { + Ok(c) => Duration::from_millis(c.runner.timeout_ms), + Err(e) => return failure("fixture_case_invalid", e), + }; + let (summary, registered_source_identity) = match tokio::time::timeout( + timeout, + build_dataset( + &case, + active_uri, + &request.fixture_scratch_root, + request.registered_binding.as_deref(), + ), + ) + .await + { + Ok(Ok(s)) => s, + Ok(Err(e)) => return failure("fixture_build_failed", e), + Err(_) => { + return failure( + "fixture_build_timeout", + "dataset whole-file timeout exceeded", + ); + } + }; + let limits = TraversalLimits::default(); + let (physical, template_metadata) = match case.reset { + ResetMode::LocalClonefile => { + let frozen = match freeze_clonefile_template( + &request.active_root, + &request.template_root, + limits, + ) { + Ok(frozen) => frozen, + Err(error) => return failure("fixture_freeze_failed", error.to_string()), + }; + ( + frozen.physical_digest().clone(), + frozen.metadata_digest().clone(), + ) + } + ResetMode::PlainCopy => { + let frozen = match freeze_plain_copy_template( + &request.active_root, + &request.template_root, + limits, + ) { + Ok(frozen) => frozen, + Err(error) => return failure("fixture_freeze_failed", error.to_string()), + }; + ( + frozen.physical_digest().clone(), + frozen.metadata_digest().clone(), + ) + } + ResetMode::S3Versioning => { + return failure( + "unsupported_runner_axis", + "local fixture worker cannot freeze an S3 reset template", + ); + } + }; + if let Err(error) = remove_active_tree(&request.active_root) { + return failure("fixture_active_remove_failed", error); + } + FixtureResultV1::Complete { + protocol_version: FIXTURE_PROTOCOL_VERSION, + point_id: case.recipe_sha256, + case_digest: plan_digest, + handoff: Box::new(FixtureBuildHandoff { + summary, + registered_source_identity, + physical, + template_metadata, + }), + } +} + +fn validate_fixture_paths(request: &FixtureRequestV1) -> Result<(), String> { + if !request.active_root.is_absolute() + || !request.template_root.is_absolute() + || !request.fixture_scratch_root.is_absolute() + { + return Err("fixture protocol paths must be absolute".to_string()); + } + if request + .fixture_scratch_root + .file_name() + .and_then(|name| name.to_str()) + != Some("fixture-scratch-v1") + { + return Err("fixture scratch root has an invalid protocol name".to_string()); + } + let active_metadata = std::fs::symlink_metadata(&request.active_root) + .map_err(|error| format!("could not inspect fixture active root: {error}"))?; + let scratch_metadata = std::fs::symlink_metadata(&request.fixture_scratch_root) + .map_err(|error| format!("could not inspect fixture scratch root: {error}"))?; + if active_metadata.file_type().is_symlink() || !active_metadata.is_dir() { + return Err("fixture active root must be a real directory".to_string()); + } + if scratch_metadata.file_type().is_symlink() || !scratch_metadata.is_dir() { + return Err("fixture scratch root must be a real directory".to_string()); + } + match std::fs::symlink_metadata(&request.template_root) { + Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} + Ok(_) => return Err("fixture template root must not exist before construction".to_string()), + Err(error) => { + return Err(format!( + "could not inspect fixture template destination: {error}" + )); + } + } + let active = std::fs::canonicalize(&request.active_root) + .map_err(|error| format!("could not resolve fixture active root: {error}"))?; + let scratch = std::fs::canonicalize(&request.fixture_scratch_root) + .map_err(|error| format!("could not resolve fixture scratch root: {error}"))?; + if active.parent() != scratch.parent() + || request.template_root.parent() != request.fixture_scratch_root.parent() + { + return Err( + "fixture active, template, and scratch roots must be siblings on the verified backend" + .to_string(), + ); + } + let mut entries = std::fs::read_dir(&scratch) + .map_err(|error| format!("could not inspect fixture scratch contents: {error}"))?; + if entries + .next() + .transpose() + .map_err(|error| format!("could not inspect fixture scratch entry: {error}"))? + .is_some() + { + return Err("fixture scratch root must be empty before construction".to_string()); + } + Ok(()) +} + +fn failure(code: impl Into, message: impl Into) -> FixtureResultV1 { + FixtureResultV1::Failed { + protocol_version: FIXTURE_PROTOCOL_VERSION, + code: code.into(), + message: message.into(), + } +} + +/// Build, byte-digest, clone-freeze, and retire one active fixture in a +/// contained child process, then return only its checked handoff facts. +#[cfg(unix)] +pub(crate) fn supervise_fixture_build( + executable: &Path, + case: &DatasetBuildPlan, + registered_binding: Option<&str>, + active_root: &Path, + template_root: &Path, + workspace_root: &Path, + watchdog: Duration, +) -> RunnerResult { + supervise_fixture_build_with_hook( + executable, + case, + registered_binding, + active_root, + template_root, + workspace_root, + watchdog, + |_| {}, + ) +} + +#[cfg(unix)] +fn supervise_fixture_build_with_hook( + executable: &Path, + case: &DatasetBuildPlan, + registered_binding: Option<&str>, + active_root: &Path, + template_root: &Path, + workspace_root: &Path, + watchdog: Duration, + after_spawn: F, +) -> RunnerResult +where + F: FnOnce(i32), +{ + let request_path = workspace_root.join("fixture-request-v1.json"); + let result_path = workspace_root.join("fixture-result-v1.json"); + let fixture_scratch_root = workspace_root.join("fixture-scratch-v1"); + std::fs::create_dir(&fixture_scratch_root).map_err(|error| { + RunnerError::new( + "fixture_scratch_directory_error", + format!( + "could not create harness-owned fixture scratch directory {}: {error}", + fixture_scratch_root.display() + ), + ) + })?; + let request = FixtureRequestV1 { + protocol_version: FIXTURE_PROTOCOL_VERSION, + case: case.clone(), + registered_binding: registered_binding.map(str::to_owned), + expected_recipe_sha256: case.recipe_sha256.clone(), + expected_plan_sha256: case + .request_digest() + .map_err(|e| RunnerError::new("fixture_case_invalid", e))?, + active_root: active_root.to_path_buf(), + template_root: template_root.to_path_buf(), + fixture_scratch_root: fixture_scratch_root.clone(), + }; + write_new_json(&request_path, &request) + .map_err(|error| RunnerError::new("fixture_protocol_error", error))?; + + let mut command = Command::new(executable); + configure_fixture_child_environment(&mut command, &fixture_scratch_root); + command + .arg("__dataset-worker-v1") + .arg(&request_path) + .arg(&result_path) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()); + configure_child_process_group(&mut command); + let started = Instant::now(); + let mut child = command.spawn().map_err(|error| { + RunnerError::new( + "fixture_worker_spawn_failed", + format!( + "could not spawn fixture worker {}: {error}", + executable.display() + ), + ) + })?; + let process_group = match i32::try_from(child.id()) { + Ok(process_group) => process_group, + Err(_) => { + let _ = child.kill(); + let status = child.wait().ok(); + return Err(RunnerError::new( + "fixture_worker_pid_overflow", + "fixture worker identifier does not fit the process-group API", + ) + .with_child_process(fixture_evidence( + "fixture-spawn", + watchdog, + started.elapsed(), + "direct-child-kill", + status, + false, + ))); + } + }; + + let mut child = FixtureProcess::new(child, process_group); + after_spawn(process_group); + + let status = loop { + match child.try_wait() { + Ok(Some(status)) => break status, + Ok(None) if started.elapsed() < watchdog => std::thread::sleep(PROCESS_POLL), + Ok(None) => { + let _ = kill_process_group(process_group); + let status = child.wait_for_exit(REAP_DEADLINE); + let group_gone = + wait_for_process_group_gone(process_group, REAP_DEADLINE).unwrap_or(false); + return Err(RunnerError::new( + "fixture_build_watchdog_exceeded", + format!( + "fixture construction did not finish within {} seconds; its process group was killed", + watchdog.as_secs() + ), + ) + .with_child_process(fixture_evidence( + "fixture-build-timeout", + watchdog, + started.elapsed(), + "sigkill", + status, + group_gone, + ))); + } + Err(error) => { + let _ = kill_process_group(process_group); + let status = child.wait_for_exit(REAP_DEADLINE); + let group_gone = + wait_for_process_group_gone(process_group, REAP_DEADLINE).unwrap_or(false); + return Err(RunnerError::new( + "fixture_worker_reap_failed", + format!("could not wait for fixture worker: {error}"), + ) + .with_child_process(fixture_evidence( + "fixture-build-wait", + watchdog, + started.elapsed(), + "sigkill", + status, + group_gone, + ))); + } + } + }; + + let group_gone = process_group_is_gone(process_group).unwrap_or(false); + if !group_gone { + let _ = kill_process_group(process_group); + let group_gone = wait_for_process_group_gone(process_group, REAP_DEADLINE).unwrap_or(false); + return Err(RunnerError::new( + "fixture_worker_descendant_leaked", + "fixture worker exited while a descendant remained in its process group", + ) + .with_child_process(fixture_evidence( + "fixture-build-exit", + watchdog, + started.elapsed(), + "sigkill-descendants", + Some(status), + group_gone, + ))); + } + + let result = read_bounded_json::(&result_path).map_err(|error| { + RunnerError::new("fixture_protocol_error", error).with_child_process(fixture_evidence( + "fixture-build-result", + watchdog, + started.elapsed(), + "worker-exited", + Some(status), + true, + )) + })?; + let evidence = || { + fixture_evidence( + "fixture-build-result", + watchdog, + started.elapsed(), + "worker-exited", + Some(status), + true, + ) + }; + match result { + FixtureResultV1::Complete { + protocol_version, + point_id, + case_digest, + handoff, + } if status.success() + && protocol_version == FIXTURE_PROTOCOL_VERSION + && point_id == case.recipe_sha256 + && case_digest == request.expected_plan_sha256 => + { + validate_handoff_summary(case, &handoff.summary) + .map_err(|error| error.with_child_process(evidence()))?; + remove_owned_tree(&fixture_scratch_root, "fixture scratch").map_err(|message| { + RunnerError::new("fixture_scratch_cleanup_failed", message) + .with_child_process(evidence()) + })?; + Ok(*handoff) + } + FixtureResultV1::Failed { + protocol_version, + code, + message, + } if !status.success() && protocol_version == FIXTURE_PROTOCOL_VERSION => { + Err(RunnerError::new(code, message).with_child_process(evidence())) + } + result => Err(RunnerError::new( + "fixture_protocol_error", + format!("fixture worker status/result mismatch: status={status}, result={result:?}"), + ) + .with_child_process(evidence())), + } +} + +#[cfg(not(unix))] +pub(crate) fn supervise_fixture_build( + _executable: &Path, + _case: &DatasetBuildPlan, + _registered_binding: Option<&str>, + _active_root: &Path, + _template_root: &Path, + _workspace_root: &Path, + _watchdog: Duration, +) -> RunnerResult { + Err(RunnerError::new( + "unsupported_fixture_worker_platform", + "contained fixture construction requires a Unix process group", + )) +} + +fn validate_handoff_summary( + _case: &DatasetBuildPlan, + observed: &DatasetLogicalV1, +) -> RunnerResult<()> { + if !crate::gqt_case::digest(&observed.logical_content_sha256) || observed.branches.is_empty() { + return Err(RunnerError::new( + "fixture_protocol_error", + "invalid dataset logical handoff", + )); + } + Ok(()) +} + +fn remove_active_tree(active_root: &Path) -> Result<(), String> { + remove_owned_tree(active_root, "active fixture") +} + +fn remove_owned_tree(root: &Path, label: &str) -> Result<(), String> { + let metadata = std::fs::symlink_metadata(root).map_err(|error| { + format!( + "could not inspect {label} {} before removal: {error}", + root.display() + ) + })?; + if metadata.file_type().is_symlink() || !metadata.is_dir() { + return Err(format!( + "{label} path is not a real directory: {}", + root.display() + )); + } + std::fs::remove_dir_all(root) + .map_err(|error| format!("could not remove {label} {}: {error}", root.display())) +} + +fn write_new_json(path: &Path, value: &impl Serialize) -> Result<(), String> { + let encoded = serde_json::to_vec(value).map_err(|error| error.to_string())?; + if encoded.len() as u64 > MAX_FIXTURE_PROTOCOL_BYTES { + return Err(format!( + "fixture protocol payload has {} bytes; limit is {MAX_FIXTURE_PROTOCOL_BYTES}", + encoded.len() + )); + } + let mut file = OpenOptions::new() + .write(true) + .create_new(true) + .open(path) + .map_err(|error| format!("could not create {}: {error}", path.display()))?; + file.write_all(&encoded) + .and_then(|()| file.sync_all()) + .map_err(|error| format!("could not durably write {}: {error}", path.display())) +} + +fn read_bounded_json Deserialize<'de>>(path: &Path) -> Result { + let mut options = OpenOptions::new(); + options.read(true); + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + + options.custom_flags(nix::libc::O_NONBLOCK | nix::libc::O_NOFOLLOW); + } + let file = options + .open(path) + .map_err(|error| format!("could not open {}: {error}", path.display()))?; + let metadata = file + .metadata() + .map_err(|error| format!("could not stat {}: {error}", path.display()))?; + if !metadata.is_file() { + return Err(format!( + "fixture protocol path is not a regular file: {}", + path.display() + )); + } + let length = metadata.len(); + if length > MAX_FIXTURE_PROTOCOL_BYTES { + return Err(format!( + "fixture protocol file {} has {length} bytes; limit is {MAX_FIXTURE_PROTOCOL_BYTES}", + path.display() + )); + } + let mut encoded = Vec::with_capacity(usize::try_from(length).unwrap_or(0)); + file.take(MAX_FIXTURE_PROTOCOL_BYTES + 1) + .read_to_end(&mut encoded) + .map_err(|error| format!("could not read {}: {error}", path.display()))?; + if encoded.len() as u64 > MAX_FIXTURE_PROTOCOL_BYTES { + return Err(format!( + "fixture protocol file {} grew beyond {MAX_FIXTURE_PROTOCOL_BYTES} bytes", + path.display() + )); + } + serde_json::from_slice(&encoded) + .map_err(|error| format!("could not decode {}: {error}", path.display())) +} + +#[cfg(unix)] +fn configure_child_process_group(command: &mut Command) { + use std::os::unix::process::CommandExt; + command.process_group(0); +} + +#[cfg(unix)] +fn kill_process_group(process_group: i32) -> Result<(), String> { + use nix::errno::Errno; + use nix::sys::signal::{Signal, kill}; + use nix::unistd::Pid; + + match kill(Pid::from_raw(-process_group), Signal::SIGKILL) { + Ok(()) | Err(Errno::ESRCH) => Ok(()), + Err(error) => Err(error.to_string()), + } +} + +#[cfg(unix)] +fn process_group_is_gone(process_group: i32) -> Result { + use nix::errno::Errno; + use nix::sys::signal::kill; + use nix::unistd::Pid; + + match kill(Pid::from_raw(-process_group), None) { + Ok(()) => Ok(false), + Err(Errno::ESRCH) => Ok(true), + Err(error) => Err(error.to_string()), + } +} + +#[cfg(unix)] +fn wait_for_process_group_gone(process_group: i32, timeout: Duration) -> Result { + let started = Instant::now(); + loop { + if process_group_is_gone(process_group)? { + return Ok(true); + } + if started.elapsed() >= timeout { + return Ok(false); + } + std::thread::sleep(PROCESS_POLL); + } +} + +#[cfg(unix)] +struct FixtureProcess { + child: std::process::Child, + process_group: i32, + reaped: Option, +} + +#[cfg(unix)] +impl FixtureProcess { + fn new(child: std::process::Child, process_group: i32) -> Self { + Self { + child, + process_group, + reaped: None, + } + } + + fn try_wait(&mut self) -> std::io::Result> { + if self.reaped.is_some() { + return Ok(self.reaped); + } + let status = self.child.try_wait()?; + if status.is_some() { + self.reaped = status; + } + Ok(status) + } + + fn wait_for_exit(&mut self, timeout: Duration) -> Option { + let started = Instant::now(); + loop { + match self.try_wait() { + Ok(Some(status)) => return Some(status), + Ok(None) if started.elapsed() < timeout => std::thread::sleep(PROCESS_POLL), + Ok(None) | Err(_) => return None, + } + } + } +} + +#[cfg(unix)] +impl Drop for FixtureProcess { + fn drop(&mut self) { + let group_gone = process_group_is_gone(self.process_group).unwrap_or(false); + if self.reaped.is_none() || !group_gone { + let _ = kill_process_group(self.process_group); + let _ = self.wait_for_exit(REAP_DEADLINE); + let _ = wait_for_process_group_gone(self.process_group, REAP_DEADLINE); + } + } +} + +#[cfg(unix)] +fn fixture_evidence( + stage: &str, + watchdog: Duration, + elapsed: Duration, + termination: &str, + status: Option, + process_group_gone: bool, +) -> ChildProcessEvidence { + use std::os::unix::process::ExitStatusExt; + + ChildProcessEvidence { + stage: stage.to_string(), + measurement_watchdog_us: duration_us(watchdog), + supervisor_elapsed_us: duration_us(elapsed), + termination: termination.to_string(), + exit_code: status.as_ref().and_then(ExitStatus::code), + signal: status.as_ref().and_then(ExitStatusExt::signal), + direct_child_reaped: status.is_some(), + process_group_gone, + stdio_closed_cleanly: true, + ..ChildProcessEvidence::default() + } +} + +fn duration_us(duration: Duration) -> u64 { + u64::try_from(duration.as_micros()).unwrap_or(u64::MAX) +} + +pub(crate) async fn build_dataset( + plan: &DatasetBuildPlan, + uri: &str, + scratch: &Path, + binding: Option<&str>, +) -> Result<(DatasetLogicalV1, Option), String> { + use omnigraph::db::Omnigraph; + use omnigraph_compiler::settings::Engine; + use omnigraph_gqt_core::{PlainHost, case_session, execute_steps, seed_case}; + let (session, case, registered_identity) = match &plan.dataset { + DatasetRecipe::Gqt { source } => { + let case = source.parse()?; + let fixture = case.fixture.as_ref().ok_or("dataset requires schema")?; + let db = Omnigraph::init(uri, &fixture.schema) + .await + .map_err(|e| e.to_string())?; + let session = case_session(db, &case, Engine::V2)?; + seed_case(&session, &fixture.seed, plan.needs_indices).await?; + (session, case, None) + } + DatasetRecipe::Registered { + reference, + preparation, + } => { + let binding = binding.ok_or("registered dataset requires --fixture ID=BUNDLE")?; + let staged = + crate::registered_fixture::stage_registered_fixture_binding(binding, Some(scratch)) + .into_result() + .map_err(|e| format!("{e:?}"))?; + if staged.receipt().fixture_id != reference.definition.fixture_id { + return Err("registered binding fixture ID mismatch".into()); + } + let observed = crate::real_graph::observe_real_graph(staged.root()) + .await + .map_err(|e| e.to_string())?; + crate::real_graph::validate_real_graph_reference(reference, &observed) + .map_err(|e| e.to_string())?; + let exact = crate::dataset_identity::registered_identity(staged.root()).await?; + staged.verify_unchanged().map_err(|e| e.message)?; + std::fs::remove_dir(uri).map_err(|e| e.to_string())?; + let physical = + crate::reset::digest_physical_tree(staged.root(), TraversalLimits::default()) + .map_err(|e| e.to_string())?; + crate::reset::copy_verified( + staged.root(), + Path::new(uri), + &physical, + TraversalLimits::default(), + ) + .map_err(|e| e.to_string())?; + let case = preparation.parse()?; + let session = case_session( + Omnigraph::open(uri).await.map_err(|e| e.to_string())?, + &case, + Engine::V2, + )?; + if plan.needs_indices { + session.ensure_indices().await.map_err(|e| e.to_string())?; + } + (session, case, Some(exact)) + } + }; + let session = execute_steps( + &case, + Path::new("frozen-dataset.gqt"), + false, + session, + uri, + None, + &PlainHost, + ) + .await?; + drop(session); + let mut logical = crate::dataset_identity::observe(Path::new(uri)).await?; + if let Some(exact) = ®istered_identity { + logical.logical_content_sha256 = crate::model::typed_sha256(&( + &logical.algorithm, + &logical.logical_content_sha256, + exact, + )) + .map_err(|e| e.to_string())?; + logical.algorithm = crate::dataset_identity::REGISTERED_LOGICAL_ALGORITHM.into(); + } + crate::dataset_identity::validate(&logical, registered_identity.as_deref())?; + Ok((logical, registered_identity)) +} diff --git a/crates/omnigraph-bench/src/discovery.rs b/crates/omnigraph-bench/src/discovery.rs new file mode 100644 index 000000000..81ff8342e --- /dev/null +++ b/crates/omnigraph-bench/src/discovery.rs @@ -0,0 +1,360 @@ +//! Read-only inventory derived from config references and bounded content folders. +use std::collections::{BTreeMap, BTreeSet}; +use std::fs; +use std::path::{Path, PathBuf}; + +use serde::Serialize; + +use crate::catalog::{Catalog, FixtureInput, Scenario}; +use crate::fixture_reference::load_fixture_reference; +use crate::gqt_case::{GqtFixture, MAX_SOURCE_BYTES}; +use crate::model::{Diagnostic, read_text_file}; +use omnigraph_gqt_core::parse_case; + +const MAX_ENTRIES: usize = 10_000; +const MAX_DEPTH: usize = 16; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum SourceState { + Available, + Missing, + Invalid, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum SourceKind { + Fixture, + Workload, + Preparation, + RegisteredReference, +} +impl std::fmt::Display for SourceKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::Fixture => "fixture", + Self::Workload => "workload", + Self::Preparation => "preparation", + Self::RegisteredReference => "registered-reference", + }) + } +} + +#[derive(Debug, Serialize)] +pub struct SourceEntry { + pub path: PathBuf, + pub kind: SourceKind, + pub source: SourceState, + pub scenarios: Vec, + pub diagnostics: Vec, +} + +#[derive(Debug, Serialize)] +pub struct SourceInventory { + pub config: PathBuf, + pub entries: Vec, +} + +pub fn sources(catalog: &Catalog, fixtures: bool) -> Result> { + let mut paths: BTreeMap)> = BTreeMap::new(); + for scenario in &catalog.definition.scenarios { + let inputs = if fixtures { + match scenario.fixture.definition() { + GqtFixture::Dataset { path } => vec![(path, SourceKind::Fixture)], + GqtFixture::Registered { + reference, + preparation, + } => vec![ + (reference, SourceKind::RegisteredReference), + (preparation, SourceKind::Preparation), + ], + } + } else { + vec![(scenario.workload.clone(), SourceKind::Workload)] + }; + for (path, kind) in inputs { + paths + .entry(path) + .or_insert_with(|| (kind, BTreeSet::new())) + .1 + .insert(scenario.id.clone()); + } + } + let content = catalog + .root + .join(if fixtures { "fixtures" } else { "workloads" }); + let mut remaining = MAX_ENTRIES; + scan( + &catalog.root, + &content, + 0, + &mut remaining, + fixtures, + &mut paths, + )?; + if paths.len() > MAX_ENTRIES { + return Err(vec![diagnostic( + "inventory_limit", + "inventory exceeds 10000 sources", + )]); + } + let entries = paths + .into_iter() + .map(|(path, (kind, scenarios))| { + let (kind, source, diagnostics) = + inspect_source(&catalog.root, &path, kind, scenarios.is_empty()); + SourceEntry { + path, + kind, + source, + scenarios: scenarios.into_iter().collect(), + diagnostics, + } + }) + .collect(); + Ok(SourceInventory { + config: catalog.path.clone(), + entries, + }) +} + +type InventoryPaths = BTreeMap)>; +fn scan( + root: &Path, + directory: &Path, + depth: usize, + remaining: &mut usize, + fixtures: bool, + paths: &mut InventoryPaths, +) -> Result<(), Vec> { + let metadata = match fs::symlink_metadata(directory) { + Ok(metadata) => metadata, + Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(()), + Err(error) => return Err(vec![diagnostic("inventory_read_error", error.to_string())]), + }; + if !metadata.is_dir() { + return Err(vec![diagnostic( + "invalid_content_root", + format!("{} must be a directory, not a symlink", directory.display()), + )]); + } + if depth > MAX_DEPTH { + return Err(vec![diagnostic( + "inventory_limit", + "content nesting exceeds 16 directories", + )]); + } + for entry in fs::read_dir(directory) + .map_err(|e| vec![diagnostic("inventory_read_error", e.to_string())])? + { + if *remaining == 0 { + return Err(vec![diagnostic( + "inventory_limit", + "content folders exceed 10000 entries", + )]); + } + *remaining -= 1; + let entry = entry.map_err(|e| vec![diagnostic("inventory_read_error", e.to_string())])?; + let path = entry.path(); + let kind = entry + .file_type() + .map_err(|e| vec![diagnostic("inventory_read_error", e.to_string())])?; + if kind.is_dir() { + scan(root, &path, depth + 1, remaining, fixtures, paths)?; + } else if path.extension().is_some_and(|e| e == "gqt") + || (fixtures + && path + .file_name() + .and_then(|n| n.to_str()) + .is_some_and(|n| n.ends_with(".fixture-reference-v1.yaml"))) + { + let relative = path + .strip_prefix(root) + .map_err(|e| vec![diagnostic("inventory_path_error", e.to_string())])? + .to_path_buf(); + let kind = if path.extension().is_some_and(|e| e == "yaml") { + SourceKind::RegisteredReference + } else if fixtures { + SourceKind::Fixture + } else { + SourceKind::Workload + }; + paths + .entry(relative) + .or_insert_with(|| (kind, BTreeSet::new())); + } + } + Ok(()) +} + +fn inspect_source( + root: &Path, + path: &Path, + mut kind: SourceKind, + discover_preparation: bool, +) -> (SourceKind, SourceState, Vec) { + let joined = root.join(path); + let canonical = match joined.canonicalize() { + Ok(path) => path, + Err(error) if error.kind() == std::io::ErrorKind::NotFound => { + return ( + kind, + SourceState::Missing, + vec![Diagnostic::error( + "source_missing", + path.display().to_string(), + "source file is missing", + )], + ); + } + Err(error) => { + return ( + kind, + SourceState::Invalid, + vec![Diagnostic::error( + "source_unreadable", + path.display().to_string(), + error.to_string(), + )], + ); + } + }; + if !canonical.starts_with(root) { + return ( + kind, + SourceState::Invalid, + vec![Diagnostic::error( + "source_outside_root", + path.display().to_string(), + "source resolves outside the config directory", + )], + ); + } + let result = match kind { + SourceKind::RegisteredReference => { + load_fixture_reference(&canonical).into_result().map(|_| ()) + } + SourceKind::Fixture | SourceKind::Workload | SourceKind::Preparation => { + let parsed = read_text_file(&canonical, MAX_SOURCE_BYTES, "GQT") + .map_err(|e| e.message) + .and_then(|text| { + let stem = canonical + .file_stem() + .and_then(|s| s.to_str()) + .ok_or("GQT filename must be UTF-8")?; + parse_case(stem, &text) + }); + parsed + .and_then(|case| { + if discover_preparation && kind == SourceKind::Fixture && case.fixture.is_none() + { + kind = SourceKind::Preparation; + } + if (kind == SourceKind::Fixture) != case.fixture.is_some() { + Err(if kind == SourceKind::Fixture { + "fixture requires schema and seed" + } else { + "workload/preparation must omit schema and seed" + } + .into()) + } else { + Ok(()) + } + }) + .map_err(|e| { + vec![Diagnostic::error( + "invalid_source", + path.display().to_string(), + e, + )] + }) + } + }; + match result { + Ok(()) => (kind, SourceState::Available, Vec::new()), + Err(diagnostics) => (kind, SourceState::Invalid, diagnostics), + } +} + +#[derive(Debug, Serialize)] +pub struct ScenarioEntry { + pub id: String, + pub fixture: FixtureInput, + pub workload: PathBuf, + pub groups: Vec, + pub repetitions: u32, + pub source: SourceState, + pub diagnostics: Vec, +} +#[derive(Debug, Serialize)] +pub struct ScenarioInventory { + pub config: PathBuf, + pub groups: BTreeMap>, + pub run: Vec, + pub entries: Vec, +} +pub fn scenario(catalog: &Catalog, scenario: &Scenario) -> ScenarioEntry { + let mut state = SourceState::Available; + let mut diagnostics = Vec::new(); + let fixture = scenario.fixture.definition(); + let mut sources = match &fixture { + GqtFixture::Dataset { path } => vec![(path.as_path(), SourceKind::Fixture)], + GqtFixture::Registered { + reference, + preparation, + } => vec![ + (reference.as_path(), SourceKind::RegisteredReference), + (preparation.as_path(), SourceKind::Preparation), + ], + }; + sources.push((&scenario.workload, SourceKind::Workload)); + for (path, kind) in sources { + let (_, source, errors) = inspect_source(&catalog.root, path, kind, false); + if source == SourceState::Invalid + || (state != SourceState::Invalid && source == SourceState::Missing) + { + state = source; + } + diagnostics.extend(errors); + } + if diagnostics.is_empty() + && let Err(errors) = catalog.plan(&scenario.id) + { + state = SourceState::Invalid; + diagnostics.extend(errors); + } + ScenarioEntry { + id: scenario.id.clone(), + fixture: scenario.fixture.clone(), + workload: scenario.workload.clone(), + groups: catalog + .definition + .groups + .iter() + .filter(|(_, members)| members.contains(&scenario.id)) + .map(|(id, _)| id.clone()) + .collect(), + repetitions: scenario.expand(&catalog.definition.defaults).1, + source: state, + diagnostics, + } +} +pub fn scenarios(catalog: &Catalog) -> ScenarioInventory { + let mut entries: Vec<_> = catalog + .definition + .scenarios + .iter() + .map(|entry| scenario(catalog, entry)) + .collect(); + entries.sort_by(|a, b| a.id.cmp(&b.id)); + ScenarioInventory { + config: catalog.path.clone(), + groups: catalog.definition.groups.clone(), + run: catalog.definition.run.clone(), + entries, + } +} +fn diagnostic(code: &str, message: impl Into) -> Diagnostic { + Diagnostic::error(code, "$", message) +} diff --git a/crates/omnigraph-bench/src/fixture_reference.rs b/crates/omnigraph-bench/src/fixture_reference.rs index 0c2539220..1fb328e2a 100644 --- a/crates/omnigraph-bench/src/fixture_reference.rs +++ b/crates/omnigraph-bench/src/fixture_reference.rs @@ -221,7 +221,7 @@ pub struct ExpectedLogicalContentV1 { } /// A normalized declaration and its complete, version-bearing audit digest. -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct NormalizedFixtureReferenceV1 { pub definition: FixtureReferenceV1, diff --git a/crates/omnigraph-bench/src/fixture_worker.rs b/crates/omnigraph-bench/src/fixture_worker.rs index 30dfe80b8..2fb047a81 100644 --- a/crates/omnigraph-bench/src/fixture_worker.rs +++ b/crates/omnigraph-bench/src/fixture_worker.rs @@ -18,7 +18,8 @@ use std::time::Instant; use serde::{Deserialize, Serialize}; use crate::branch_merge::{BranchMergePlan, FixtureBuildSummary, initialize_local_fixture}; -use crate::case::{CaseV1, ResetMode}; +use crate::legacy::case::{CaseV1, ResetMode}; +use crate::legacy::case::{ValidatedCase, validate_case}; use crate::reset::{ MetadataDigest, PhysicalDigest, TraversalLimits, freeze_clonefile_template, freeze_plain_copy_template, @@ -33,7 +34,6 @@ use crate::runner::{ validate_fixture_child_runtime_overrides, }; use crate::runner::{RunnerError, RunnerResult}; -use crate::{ValidatedCase, validate_case}; const FIXTURE_PROTOCOL_VERSION: u32 = 2; const MAX_FIXTURE_PROTOCOL_BYTES: u64 = 1024 * 1024; @@ -766,13 +766,13 @@ fn duration_us(duration: Duration) -> u64 { mod tests { use std::os::unix::fs::PermissionsExt; - use crate::parse_case; + use crate::legacy::case::parse_case; use super::*; fn test_case() -> ValidatedCase { parse_case(include_str!( - "../../../benchmarks/cases/branch-merge-d50-warm.case-v1.yaml" + "../tests/fixtures/legacy/branch-merge-d50-warm.case-v1.yaml" )) .into_result() .unwrap() @@ -791,15 +791,17 @@ mod tests { } fn aged_case(mut definition: CaseV1) -> ValidatedCase { - definition.fixture.preparation = - Some(crate::case::FixturePreparation::ReversibleUpdatesV1 { + definition.fixture.preparation = Some( + crate::legacy::case::FixturePreparation::ReversibleUpdatesV1 { additional_commits: 8, rows_per_commit: 3, seed: 42, - maintenance: crate::case::PreparationMaintenance::None, - }); - definition.fixture.state.aging = crate::case::Aging::SmallCommits; - definition.fixture.state.deletion_history = crate::case::DeletionHistory::ReversibleUpdates; + maintenance: crate::legacy::case::PreparationMaintenance::None, + }, + ); + definition.fixture.state.aging = crate::legacy::case::Aging::SmallCommits; + definition.fixture.state.deletion_history = + crate::legacy::case::DeletionHistory::ReversibleUpdates; definition.fixture.state.history_depth += 8; validate_case(definition).into_result().unwrap() } diff --git a/crates/omnigraph-bench/src/gqt_case.rs b/crates/omnigraph-bench/src/gqt_case.rs new file mode 100644 index 000000000..5a286cec1 --- /dev/null +++ b/crates/omnigraph-bench/src/gqt_case.rs @@ -0,0 +1,763 @@ +//! Authored GQT experiments. Recipe identity is resolved before I/O; point +//! identity is bound only after the dataset's logical evidence is verified. +use crate::case::{ + Backend, CacheCondition, EnginePreparation, PageCacheCondition, ProcessLifecycle, Protocol, + ResetMode, Schedule, WarmupProgram, +}; +use crate::model::{read_text_file, typed_sha256, valid_kebab_id}; +use omnigraph_gqt_core::{Case, ExecutionHost, Item, PlainHost, Step, StepDescriptor, StepKind}; +use serde::{Deserialize, Serialize}; +use std::path::{Path, PathBuf}; + +pub const MAX_SOURCE_BYTES: usize = 512 * 1024; +pub const MAX_EXPANDED_STEPS: usize = 4096; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GqtScenario { + #[serde(rename = "gqt-v1")] + GqtV1, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtCaseV1 { + pub version: u32, + pub id: String, + pub scenario: GqtScenario, + pub fixture: GqtFixture, + pub workload: GqtWorkload, + pub environment: GqtEnvironment, + pub protocol: Protocol, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "kind", rename_all = "kebab-case", deny_unknown_fields)] +pub enum GqtFixture { + Dataset { + path: PathBuf, + }, + Registered { + reference: PathBuf, + preparation: PathBuf, + }, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtWorkload { + pub queries: PathBuf, + pub measured_step: MeasuredStep, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct MeasuredStep { + pub ordinal: usize, + pub text: String, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtEnvironment { + pub backend: Backend, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct FrozenSource { + pub stem: String, + pub text: String, + pub sha256: String, +} +impl FrozenSource { + pub fn parse(&self) -> Result { + if self.text.len() > MAX_SOURCE_BYTES || sha256_bytes(self.text.as_bytes()) != self.sha256 { + return Err("GQT source digest or size does not match frozen input".into()); + } + omnigraph_gqt_core::parse_case(&self.stem, &self.text) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "kind", rename_all = "kebab-case", deny_unknown_fields)] +pub enum DatasetRecipe { + Gqt { + source: FrozenSource, + }, + Registered { + reference: Box, + preparation: FrozenSource, + }, +} +/// A real dataset build request; optional queries contribute only index requirements. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct DatasetBuildPlan { + pub dataset: DatasetRecipe, + pub index_queries: Option, + pub recipe_sha256: String, + pub environment: GqtEnvironment, + pub reset: ResetMode, + pub needs_indices: bool, +} +impl DatasetBuildPlan { + pub fn revalidate(&self) -> Result<(), String> { + let dataset = validate_recipe(&self.dataset)?; + let query_indices = match &self.index_queries { + Some(source) => { + let case = source.parse()?; + admit_environment(&case)?; + if case.fixture.is_some() { + return Err("index-requirement queries must be schema-less".into()); + } + case.needs_indices + } + None => false, + }; + validate_backend_reset(&self.environment.backend, self.reset)?; + if self.needs_indices != (dataset.needs_indices || query_indices) + || self.recipe_sha256 != recipe_hash(&self.dataset)? + { + return Err("dataset recipe or index requirements differ from frozen input".into()); + } + if serde_json::to_vec(self).map_err(|e| e.to_string())?.len() > 256 * 1024 { + return Err("frozen dataset build plan exceeds 256 KiB".into()); + } + Ok(()) + } + pub fn request_digest(&self) -> Result { + typed_sha256(self).map_err(|e| e.to_string()) + } +} +fn validate_recipe(recipe: &DatasetRecipe) -> Result { + let case = match recipe { + DatasetRecipe::Gqt { source } => { + let c = source.parse()?; + if c.fixture.is_none() { + return Err("dataset requires schema and seed".into()); + } + c + } + DatasetRecipe::Registered { + reference, + preparation, + } => { + let normalized = + crate::fixture_reference::normalize_fixture_reference(reference.definition.clone()) + .into_result() + .map_err(|e| format!("invalid registered reference: {e:?}"))?; + if normalized != **reference { + return Err("registered reference is not canonical".into()); + } + let c = preparation.parse()?; + if c.fixture.is_some() { + return Err("registered preparation must be schema-less".into()); + } + c + } + }; + admit_environment(&case)?; + Ok(case) +} +pub fn dataset_file( + path: &Path, + queries: Option<&Path>, + backend: Backend, + reset: ResetMode, +) -> Result { + let dataset = DatasetRecipe::Gqt { + source: read_source(path)?, + }; + let index_queries = queries.map(read_source).transpose()?; + let needs_indices = validate_recipe(&dataset)?.needs_indices + || index_queries + .as_ref() + .map(|s| s.parse().map(|c| c.needs_indices)) + .transpose()? + .unwrap_or(false); + let plan = DatasetBuildPlan { + recipe_sha256: recipe_hash(&dataset)?, + dataset, + index_queries, + environment: GqtEnvironment { backend }, + reset, + needs_indices, + }; + plan.revalidate()?; + Ok(plan) +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PlannedGqt { + pub definition: GqtCaseV1, + pub dataset: DatasetRecipe, + pub queries: FrozenSource, + pub recipe_sha256: String, + pub case_digest: String, + pub planned_sha256: String, + pub cache_condition: CacheCondition, + pub needs_indices: bool, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtPointIdentityV1 { + pub identity_version: u32, + pub scenario: GqtScenario, + pub dataset_recipe_sha256: String, + pub dataset_logical_digest: String, + pub dataset_identity_algorithm: String, + pub queries_sha256: String, + pub measured_step: MeasuredStep, + pub cache_condition: CacheCondition, + pub environment: GqtEnvironment, + pub protocol: Protocol, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct BoundGqt { + pub plan: PlannedGqt, + pub identity: GqtPointIdentityV1, + pub point_id: String, + pub point_name: String, +} +impl PlannedGqt { + pub fn dataset_build_plan(&self) -> DatasetBuildPlan { + DatasetBuildPlan { + dataset: self.dataset.clone(), + index_queries: Some(self.queries.clone()), + recipe_sha256: self.recipe_sha256.clone(), + environment: self.definition.environment.clone(), + reset: self.definition.protocol.reset, + needs_indices: self.needs_indices, + } + } + pub fn planned_hash(&self) -> Result { + typed_sha256(&( + &self.recipe_sha256, + &self.queries.sha256, + &self.definition.workload.measured_step, + &self.cache_condition, + &self.definition.environment, + &self.definition.protocol, + )) + .map_err(|e| e.to_string()) + } + + pub fn bind(&self, logical: &str, algorithm: &str) -> Result { + if !digest(logical) { + return Err("invalid dataset logical digest".into()); + } + let identity = GqtPointIdentityV1 { + identity_version: 1, + scenario: GqtScenario::GqtV1, + dataset_recipe_sha256: self.recipe_sha256.clone(), + dataset_logical_digest: logical.into(), + dataset_identity_algorithm: algorithm.into(), + queries_sha256: self.queries.sha256.clone(), + measured_step: self.definition.workload.measured_step.clone(), + cache_condition: self.cache_condition.clone(), + environment: self.definition.environment.clone(), + protocol: self.definition.protocol.clone(), + }; + validate_point_spec(&identity)?; + let point_id = typed_sha256(&identity).map_err(|e| e.to_string())?; + Ok(BoundGqt { + plan: self.clone(), + point_name: format!( + "gqt-{}-{}", + self.cache_condition.display_label(), + &point_id[..12] + ), + identity, + point_id, + }) + } + pub fn revalidate(&self) -> Result<(), String> { + validate_definition(&self.definition)?; + let queries = self.queries.parse()?; + let dataset = validate_recipe(&self.dataset)?; + let condition = admit_queries(&queries, &self.definition.workload.measured_step)?; + if condition != self.cache_condition + || (dataset.needs_indices || queries.needs_indices) != self.needs_indices + { + return Err("derived GQT treatment differs from frozen plan".into()); + } + if self.planned_hash()? != self.planned_sha256 + || recipe_hash(&self.dataset)? != self.recipe_sha256 + || typed_sha256(&self.definition).map_err(|e| e.to_string())? != self.case_digest + { + return Err("frozen case/recipe identity mismatch".into()); + } + if serde_json::to_vec(self).map_err(|e| e.to_string())?.len() > 256 * 1024 { + return Err("frozen GQT plan exceeds 256 KiB".into()); + } + let bound = self.bind( + &"0".repeat(64), + crate::dataset_identity::DATASET_LOGICAL_ALGORITHM, + )?; + if serde_json::to_vec(&bound).map_err(|e| e.to_string())?.len() > 512 * 1024 { + return Err("bound GQT request exceeds reserved frame budget".into()); + } + Ok(()) + } +} +impl BoundGqt { + pub fn revalidate(&self) -> Result<(), String> { + self.plan.revalidate()?; + if self.plan.bind( + &self.identity.dataset_logical_digest, + &self.identity.dataset_identity_algorithm, + )? != *self + { + return Err("bound point identity mismatch".into()); + } + Ok(()) + } +} +pub fn validate_definition(c: &GqtCaseV1) -> Result<(), String> { + if c.version != 1 || !valid_kebab_id(&c.id) || c.id.len() > 128 { + return Err("gqt-v1 requires version 1 and a bounded kebab-case id".into()); + } + if c.protocol.schedule != Schedule::Manual + || c.protocol.reset == ResetMode::S3Versioning + || c.protocol + .deadline_seconds + .is_some_and(|x| x == 0 || x > 3600) + { + return Err( + "gqt-v1 requires a manual local reset and a null or 1..=3600 second deadline".into(), + ); + } + if !matches!(c.environment.backend, Backend::LocalFs { .. }) { + return Err("gqt-v1 supports local-filesystem only".into()); + } + if c.workload.measured_step.ordinal == 0 + || c.workload.measured_step.text.trim().is_empty() + || c.workload.measured_step.text.len() > 16 * 1024 + { + return Err("measured_step requires a positive ordinal and exact operation text".into()); + } + Ok(()) +} +fn recipe_hash(recipe: &DatasetRecipe) -> Result { + let identity = match recipe { + DatasetRecipe::Gqt { source } => { + serde_json::json!({"format":"gqt-dataset-recipe-v1","dataset_sha256":source.sha256}) + } + DatasetRecipe::Registered { + reference, + preparation, + } => { + serde_json::json!({"format":"gqt-registered-recipe-v1","logical":reference.definition.logical,"expected":reference.definition.expected,"preparation_sha256":preparation.sha256}) + } + }; + typed_sha256(&identity).map_err(|e| e.to_string()) +} +pub fn load(path: &Path, definition: GqtCaseV1) -> Result { + validate_definition(&definition)?; + let parent = path.parent().ok_or("case path has no parent")?; + let catalog = parent + .ancestors() + .find(|p| p.file_name().is_some_and(|n| n == "cases")) + .and_then(Path::parent) + .unwrap_or(parent) + .canonicalize() + .map_err(|e| e.to_string())?; + load_with_root(path, definition, &catalog) +} + +/// Resolve config-relative inputs within the caller's explicit catalog boundary. +pub fn load_with_root( + path: &Path, + definition: GqtCaseV1, + root: &Path, +) -> Result { + validate_definition(&definition)?; + let parent = path.parent().ok_or("config path has no parent")?; + let catalog = root.canonicalize().map_err(|e| e.to_string())?; + let queries = read_source(&resolve(parent, &definition.workload.queries, &catalog)?)?; + let dataset = match &definition.fixture { + GqtFixture::Dataset { path } => DatasetRecipe::Gqt { + source: read_source(&resolve(parent, path, &catalog)?)?, + }, + GqtFixture::Registered { + reference, + preparation, + } => DatasetRecipe::Registered { + reference: Box::new( + crate::fixture_reference::load_fixture_reference(&resolve( + parent, reference, &catalog, + )?) + .into_result() + .map_err(|e| format!("{e:?}"))?, + ), + preparation: read_source(&resolve(parent, preparation, &catalog)?)?, + }, + }; + let parsed_queries = queries.parse()?; + let parsed_dataset = match &dataset { + DatasetRecipe::Gqt { source } => source.parse()?, + DatasetRecipe::Registered { preparation, .. } => preparation.parse()?, + }; + let mut plan = PlannedGqt { + planned_sha256: String::new(), + case_digest: typed_sha256(&definition).map_err(|e| e.to_string())?, + recipe_sha256: recipe_hash(&dataset)?, + cache_condition: admit_queries(&parsed_queries, &definition.workload.measured_step)?, + needs_indices: parsed_queries.needs_indices || parsed_dataset.needs_indices, + definition, + dataset, + queries, + }; + plan.planned_sha256 = plan.planned_hash()?; + plan.revalidate()?; + if serde_json::to_vec(&plan).map_err(|e| e.to_string())?.len() > 256 * 1024 { + return Err("frozen GQT inputs exceed the bounded worker protocol budget".into()); + } + Ok(plan) +} +pub fn read_source(path: &Path) -> Result { + let text = read_text_file(path, MAX_SOURCE_BYTES, "GQT").map_err(|e| e.message)?; + let stem = path + .file_stem() + .and_then(|x| x.to_str()) + .ok_or("GQT filename must be UTF-8")? + .into(); + let source = FrozenSource { + stem, + sha256: sha256_bytes(text.as_bytes()), + text, + }; + source.parse()?; + Ok(source) +} +fn resolve(parent: &Path, path: &Path, root: &Path) -> Result { + if path.is_absolute() { + return Err("catalog sources must use relative paths".into()); + } + let resolved = parent + .join(path) + .canonicalize() + .map_err(|e| format!("{}: {e}", path.display()))?; + if !resolved.starts_with(root) { + return Err("GQT source escapes the catalog".into()); + } + Ok(resolved) +} +/// Inspect parser descriptors only after bounding workload expansion. +pub fn workload_steps(case: &Case) -> Result, String> { + let count = case.items.iter().try_fold(0usize, |total, item| { + let count = match item { + Item::Step(_) => Some(1), + Item::Loop { steps, values, .. } => steps.len().checked_mul(values.len()), + }?; + total.checked_add(count) + }); + if count.is_none_or(|count| count > MAX_EXPANDED_STEPS) { + return Err(format!( + "workload exceeds {MAX_EXPANDED_STEPS} expanded steps" + )); + } + Ok(case.steps()) +} +pub fn admit_queries(case: &Case, selected: &MeasuredStep) -> Result { + admit_environment(case)?; + if case.fixture.is_some() { + return Err("queries must omit schema and seed".into()); + } + let descriptors = workload_steps(case)?; + let step = descriptors + .iter() + .find(|s| s.ordinal == selected.ordinal) + .ok_or("measured ordinal does not exist")?; + if step.in_loop || step.source.trim() != selected.text.trim() { + return Err("measured step moved, its text changed, or it is inside a loop".into()); + } + if matches!( + step.kind, + StepKind::Settings | StepKind::Show | StepKind::Concurrent + ) { + return Err( + "selected step must execute one query, load, or control/mutation operation".into(), + ); + } + let mut reads = 0u32; + let mut reopened = false; + let mut suffix = 0usize; + for item in &case.items { + let (steps, times) = match item { + Item::Step(s) => (std::slice::from_ref(s), 1usize), + Item::Loop { steps, values, .. } => (steps.as_slice(), values.len()), + }; + for s in steps { + if s.ordinal() == selected.ordinal { + if let Step::Load(load) = s { + if load.call_count() != 1 { + return Err( + "measured generated load must contain exactly one loader call".into(), + ); + } + } + continue; + } + if s.ordinal() > selected.ordinal { + if explicit_verification(s.operation_kind()) { + suffix += times; + } + continue; + } + match s.operation_kind() { + StepKind::Query | StepKind::BranchList => { + if reopened { + return Err( + "reads after preparation restart are not post-reopen treatment".into(), + ); + } + reads = reads + .checked_add(u32::try_from(times).map_err(|_| "warmup count overflow")?) + .ok_or("warmup count overflow")?; + } + StepKind::Settings | StepKind::Show => {} + StepKind::Restart => { + if reopened || reads == 0 || times != 1 { + return Err( + "post-reopen requires reads followed by exactly one restart".into() + ); + } + reopened = true; + } + _ => { + return Err( + "writes before the measured step are forbidden; move them into the dataset" + .into(), + ); + } + } + } + } + if suffix == 0 { + return Err( + "queries require explicit verification steps after the measured operation".into(), + ); + } + Ok(CacheCondition { + process: ProcessLifecycle::FreshPerRepetition, + engine: if reopened { + EnginePreparation::ReopenedAfterProgram + } else if reads > 0 { + EnginePreparation::WarmedByProgram + } else { + EnginePreparation::PreparationOnly + }, + page_cache: if reads > 0 { + PageCacheCondition::ProgramConditioned + } else { + PageCacheCondition::Uncontrolled + }, + program: if reads > 0 { + WarmupProgram::GqtReadSetV1 + } else { + WarmupProgram::None + }, + iterations: reads, + }) +} +pub fn digest(s: &str) -> bool { + s.len() == 64 + && s.bytes() + .all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b)) +} + +pub fn sha256_bytes(bytes: &[u8]) -> String { + use sha2::{Digest, Sha256}; + format!("{:x}", Sha256::digest(bytes)) +} + +/// Explicit CLI inputs are frozen by their supplied paths and need not live in a catalog. +pub fn override_sources( + mut plan: PlannedGqt, + dataset: Option<&Path>, + queries: Option<&Path>, +) -> Result { + if let Some(path) = dataset { + plan.dataset = DatasetRecipe::Gqt { + source: read_source(path)?, + }; + plan.definition.fixture = GqtFixture::Dataset { + path: path.to_path_buf(), + }; + } + if let Some(path) = queries { + plan.queries = read_source(path)?; + plan.definition.workload.queries = path.to_path_buf(); + } + let parsed = plan.queries.parse()?; + let dataset = match &plan.dataset { + DatasetRecipe::Gqt { source } => source.parse()?, + DatasetRecipe::Registered { preparation, .. } => preparation.parse()?, + }; + plan.cache_condition = admit_queries(&parsed, &plan.definition.workload.measured_step)?; + plan.needs_indices = dataset.needs_indices || parsed.needs_indices; + plan.recipe_sha256 = recipe_hash(&plan.dataset)?; + plan.case_digest = typed_sha256(&plan.definition).map_err(|e| e.to_string())?; + plan.planned_sha256 = plan.planned_hash()?; + plan.revalidate()?; + if serde_json::to_vec(&plan).map_err(|e| e.to_string())?.len() > 256 * 1024 { + return Err("frozen inputs exceed 256 KiB protocol budget".into()); + } + Ok(plan) +} + +pub fn explicit_verification(kind: StepKind) -> bool { + !matches!( + kind, + StepKind::Restart | StepKind::Settings | StepKind::Concurrent + ) +} +pub fn admit_environment(case: &Case) -> Result<(), String> { + PlainHost.admit_case(case)?; + if !case.runner.environments.iter().any(|e| { + matches!( + e.execution, + omnigraph_gqt_core::Execution::Engine { + storage: omnigraph_gqt_core::runner_config::Storage::LocalFilesystem + } + ) + }) { + return Err( + "benchmark requires an admitted direct-engine/local-filesystem environment".into(), + ); + } + Ok(()) +} +pub fn validate_point_spec(spec: &GqtPointIdentityV1) -> Result<(), String> { + let synthetic = GqtCaseV1 { + version: 1, + id: "point-validation".into(), + scenario: GqtScenario::GqtV1, + fixture: GqtFixture::Dataset { + path: "dataset.gqt".into(), + }, + workload: GqtWorkload { + queries: "queries.gqt".into(), + measured_step: spec.measured_step.clone(), + }, + environment: spec.environment.clone(), + protocol: spec.protocol.clone(), + }; + validate_definition(&synthetic)?; + validate_backend_reset(&spec.environment.backend, spec.protocol.reset)?; + let c = &spec.cache_condition; + let valid = c.process == ProcessLifecycle::FreshPerRepetition + && matches!( + (c.engine, c.page_cache, c.program, c.iterations), + ( + EnginePreparation::PreparationOnly, + PageCacheCondition::Uncontrolled, + WarmupProgram::None, + 0, + ) | ( + EnginePreparation::WarmedByProgram | EnginePreparation::ReopenedAfterProgram, + PageCacheCondition::ProgramConditioned, + WarmupProgram::GqtReadSetV1, + 1..=4096, + ) + ); + if !valid { + return Err("invalid GQT cache condition tuple".into()); + } + for d in [ + &spec.dataset_recipe_sha256, + &spec.dataset_logical_digest, + &spec.queries_sha256, + ] { + if !digest(d) { + return Err("invalid point content digest".into()); + } + } + if spec.identity_version != 1 + || !matches!( + spec.dataset_identity_algorithm.as_str(), + crate::dataset_identity::DATASET_LOGICAL_ALGORITHM + | crate::dataset_identity::REGISTERED_LOGICAL_ALGORITHM + ) + { + return Err("unsupported GQT point identity version or logical domain".into()); + } + let run_spec_json = serde_json::to_string(spec).map_err(|e| e.to_string())?; + let projected = serde_json::json!({"point_id":"0".repeat(64),"point_name":"gqt-post-reopen-000000000000","point_identity_version":1,"scenario":"gqt-v1","run_spec_json":run_spec_json}); + if serde_json::to_vec(&projected) + .map_err(|e| e.to_string())? + .len() + > 64 * 1024 + { + return Err("point identity exceeds projection row budget".into()); + } + Ok(()) +} + +pub fn explicit_pair( + dataset: &Path, + queries: &Path, + selected: MeasuredStep, + backend: Backend, + reset: ResetMode, + deadline_seconds: Option, +) -> Result { + let dataset_source = read_source(dataset)?; + let query_source = read_source(queries)?; + let definition = GqtCaseV1 { + version: 1, + id: "explicit-gqt-pair".into(), + scenario: GqtScenario::GqtV1, + fixture: GqtFixture::Dataset { + path: dataset.to_path_buf(), + }, + workload: GqtWorkload { + queries: queries.to_path_buf(), + measured_step: selected, + }, + environment: GqtEnvironment { backend }, + protocol: Protocol { + deadline_seconds, + attribution: crate::case::Attribution::PerPhase, + schedule: Schedule::Manual, + reset, + timer: crate::case::Timer::Monotonic, + }, + }; + let query_case = query_source.parse()?; + let dataset_case = dataset_source.parse()?; + let recipe = DatasetRecipe::Gqt { + source: dataset_source, + }; + let mut plan = PlannedGqt { + case_digest: typed_sha256(&definition).map_err(|e| e.to_string())?, + recipe_sha256: recipe_hash(&recipe)?, + planned_sha256: String::new(), + cache_condition: admit_queries(&query_case, &definition.workload.measured_step)?, + needs_indices: query_case.needs_indices || dataset_case.needs_indices, + definition, + dataset: recipe, + queries: query_source, + }; + plan.planned_sha256 = plan.planned_hash()?; + plan.revalidate()?; + Ok(plan) +} + +fn validate_backend_reset(backend: &Backend, reset: ResetMode) -> Result<(), String> { + use crate::case::{LocalFilesystem, LocalStorageClass}; + if !matches!( + (backend, reset), + ( + Backend::LocalFs { + filesystem: LocalFilesystem::Apfs, + storage_class: LocalStorageClass::NvmeSsd + }, + ResetMode::LocalClonefile + ) | ( + Backend::LocalFs { + filesystem: LocalFilesystem::Xfs, + storage_class: LocalStorageClass::NvmeSsd + }, + ResetMode::PlainCopy + ) + ) { + return Err("reset and declared backend do not match an admitted local environment".into()); + } + Ok(()) +} diff --git a/crates/omnigraph-bench/src/gqt_protocol.rs b/crates/omnigraph-bench/src/gqt_protocol.rs new file mode 100644 index 000000000..588ac533a --- /dev/null +++ b/crates/omnigraph-bench/src/gqt_protocol.rs @@ -0,0 +1,406 @@ +//! Private, versioned protocol between the benchmark supervisor and one +//! repetition worker process. +//! +//! Standard output is reserved exclusively for these frames. Human diagnostics +//! belong on standard error so a supervisor can reject malformed or unexpected +//! output rather than guessing where one message ends. + +use std::error::Error; +use std::fmt::{Display, Formatter}; +use std::fs::{File, OpenOptions}; +use std::io::{self, BufRead, Seek, Write}; +use std::path::{Path, PathBuf}; + +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; + +use crate::gqt_case::BoundGqt as CaseV1; +use crate::gqt_runner::GqtRepObservation as RepObservation; +use crate::machine::MachineIdentityV1; +use crate::reset::{MetadataDigest, PhysicalDigest}; +use crate::runner::EffectiveEnvironmentValue; +/// Attested build facts reported by an honest worker from its own process. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct WorkerBuildV1 { + pub source_commit: String, + /// `None` is an explicit failed build-time probe and is never admissible + /// for a measured worker. Keeping the absence typed lets the parent fail + /// closed instead of accepting a fabricated clean/dirty value. + pub source_tree_dirty: Option, + pub cargo_profile: String, + /// Cargo's profile-level observation, not proof against direct target + /// rustc arguments. + pub cargo_opt_level: String, + pub debug_assertions: bool, + /// Effective Lance memory-pool setting inherited by the measured worker. + /// This is retained until the complete typed engine-environment registry + /// below replaces the one-setting representation. + pub effective_lance_mem_pool_size: Box, + pub target_triple: String, + pub rustc_version: String, + pub declared_release_lto: String, + pub declared_release_codegen_units: Option, + pub declared_release_strip: Option, + pub cargo_encoded_rustflags_present: Option, + pub release_profile_environment_overrides_supported: Option, + /// False until a controlled build wrapper supplies the final target rustc + /// command line in a digest-bound external receipt. + pub effective_codegen_options_proved: bool, + /// Canonical Cargo feature names reported by the linked + /// `omnigraph-engine` artifact itself, not inferred from this CLI crate. + pub engine_feature_flags: Vec, + /// Canonical non-Cargo engine techniques enabled for this execution. + /// Runner-v1 has no such controls and therefore admits only an empty set. + pub enabled_techniques: Vec, + pub executable_sha256: String, +} + +/// The only worker protocol understood by this build. +pub const WORKER_PROTOCOL_VERSION: u32 = 1; + +/// Maximum compact JSON payload bytes in one frame, excluding its newline. +/// +/// Case documents are independently bounded well below this value. Keeping a +/// framing bound here also prevents corrupt or unexpected worker output from +/// growing the supervisor's memory without limit. +pub const MAX_WORKER_FRAME_BYTES: usize = 1024 * 1024; +const MAX_WORKER_EXECUTABLE_BYTES: u64 = 2 * 1024 * 1024 * 1024; +const EXECUTABLE_DIGEST_BUFFER_BYTES: usize = 1024 * 1024; + +/// Complete, immutable input for one worker process. +/// +/// The worker revalidates `case` and compares the derived identities with the +/// expected values. It must not reload a case file that could change between +/// parent planning and repetition execution. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct WorkerRequestV1 { + pub repetition: u32, + pub case: CaseV1, + pub expected_point_id: String, + pub expected_case_digest: String, + pub repetition_root: PathBuf, + /// Harness-owned empty sibling directory on the verified scratch backend. + /// Both generic process-temporary spill and OmniGraph merge staging must + /// resolve through this exact protocol field. + pub worker_scratch_root: PathBuf, + pub expected_physical_digest: PhysicalDigest, + pub expected_metadata_digest: MetadataDigest, +} + +/// Frames sent by the supervising parent. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "frame", rename_all = "kebab-case", deny_unknown_fields)] +pub enum ParentFrameV1 { + /// Supplies the complete repetition input. This is always the first frame. + Request { + protocol_version: u32, + request: Box, + }, + /// Releases a prepared worker into the selected operation. + Begin { + protocol_version: u32, + repetition: u32, + }, +} + +impl ParentFrameV1 { + pub fn protocol_version(&self) -> u32 { + match self { + Self::Request { + protocol_version, .. + } + | Self::Begin { + protocol_version, .. + } => *protocol_version, + } + } +} + +/// Stable worker stage attached to a structured failure. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum WorkerStageV1 { + Bootstrap, + Prepare, + Measure, + Verify, + Finalize, + Protocol, +} + +/// Frames sent by one repetition worker. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "frame", rename_all = "kebab-case", deny_unknown_fields)] +pub enum ChildFrameV1 { + /// Open, cache preparation, identity, and pre-measurement checks completed. + Ready { + protocol_version: u32, + repetition: u32, + point_id: String, + case_digest: String, + worker_build: Box, + /// Process-effective identity captured by this child immediately + /// before it declared itself ready for measurement. + machine: Box, + physical_digest: PhysicalDigest, + metadata_digest: MetadataDigest, + }, + /// The operation returned; subsequent assertions cannot extend its clock. + Settled { + protocol_version: u32, + repetition: u32, + elapsed_us: u64, + }, + /// Verification completed and the worker produced an admissible sample. + Complete { + protocol_version: u32, + point_id: String, + case_digest: String, + sample: Box, + }, + /// Failure evidence can retain a closed operation clock without admitting a successful sample. + Failed { + protocol_version: u32, + stage: WorkerStageV1, + code: String, + message: String, + #[serde(skip_serializing_if = "Option::is_none")] + settled_sample: Option>, + }, +} + +/// SHA-256 one bounded regular worker executable. +pub fn digest_worker_executable(path: &Path) -> io::Result { + open_and_digest_worker_executable(path).map(|(_file, _bytes, digest)| digest) +} + +/// Open and SHA-256 one bounded regular worker executable through the same +/// file descriptor. Callers that must survive a later path replacement can +/// retain the returned descriptor and stage those exact bytes elsewhere. +pub(crate) fn open_and_digest_worker_executable(path: &Path) -> io::Result<(File, u64, String)> { + let mut options = OpenOptions::new(); + options.read(true); + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + + options.custom_flags(nix::libc::O_NONBLOCK | nix::libc::O_NOFOLLOW); + } + let mut file = options.open(path)?; + let metadata = file.metadata()?; + if !metadata.is_file() || metadata.len() == 0 { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!( + "worker executable is not a non-empty regular file: {}", + path.display() + ), + )); + } + if metadata.len() > MAX_WORKER_EXECUTABLE_BYTES { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!( + "worker executable has {} bytes; the limit is {MAX_WORKER_EXECUTABLE_BYTES}", + metadata.len() + ), + )); + } + file.rewind()?; + let mut digest = Sha256::new(); + let mut buffer = vec![0_u8; EXECUTABLE_DIGEST_BUFFER_BYTES]; + let mut observed = 0_u64; + loop { + let read = std::io::Read::read(&mut file, &mut buffer)?; + if read == 0 { + break; + } + observed = observed + .checked_add(u64::try_from(read).map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidData, + "worker executable read overflow", + ) + })?) + .ok_or_else(|| { + io::Error::new( + io::ErrorKind::InvalidData, + "worker executable size overflow", + ) + })?; + if observed > MAX_WORKER_EXECUTABLE_BYTES { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "worker executable grew beyond its digest bound while reading", + )); + } + digest.update(&buffer[..read]); + } + if observed != metadata.len() { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!( + "worker executable changed length while reading: metadata={} observed={observed}", + metadata.len() + ), + )); + } + file.rewind()?; + Ok((file, observed, format!("{:x}", digest.finalize()))) +} + +impl ChildFrameV1 { + pub fn protocol_version(&self) -> u32 { + match self { + Self::Ready { + protocol_version, .. + } + | Self::Settled { + protocol_version, .. + } + | Self::Complete { + protocol_version, .. + } + | Self::Failed { + protocol_version, .. + } => *protocol_version, + } + } +} + +#[derive(Debug)] +pub enum WorkerProtocolError { + Io(io::Error), + Encode(serde_json::Error), + Decode(serde_json::Error), + EmptyFrame, + UnterminatedFrame { bytes: usize }, + FrameTooLarge { observed: usize, limit: usize }, + UnsupportedVersion { expected: u32, observed: u32 }, +} + +impl Display for WorkerProtocolError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Io(error) => write!(formatter, "worker protocol I/O failed: {error}"), + Self::Encode(error) => write!(formatter, "could not encode worker frame: {error}"), + Self::Decode(error) => write!(formatter, "could not decode worker frame: {error}"), + Self::EmptyFrame => write!(formatter, "worker protocol contained an empty frame"), + Self::UnterminatedFrame { bytes } => write!( + formatter, + "worker protocol reached EOF after {bytes} unterminated frame bytes" + ), + Self::FrameTooLarge { observed, limit } => write!( + formatter, + "worker protocol frame has at least {observed} bytes; the limit is {limit}" + ), + Self::UnsupportedVersion { expected, observed } => write!( + formatter, + "unsupported worker protocol version {observed}; this build supports {expected}" + ), + } + } +} + +impl Error for WorkerProtocolError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + Self::Io(error) => Some(error), + Self::Encode(error) | Self::Decode(error) => Some(error), + Self::EmptyFrame + | Self::UnterminatedFrame { .. } + | Self::FrameTooLarge { .. } + | Self::UnsupportedVersion { .. } => None, + } + } +} + +/// Encode and flush one compact NDJSON frame. +pub fn write_frame(writer: &mut W, frame: &T) -> Result<(), WorkerProtocolError> +where + W: Write, + T: Serialize, +{ + let encoded = serde_json::to_vec(frame).map_err(WorkerProtocolError::Encode)?; + if encoded.len() > MAX_WORKER_FRAME_BYTES { + return Err(WorkerProtocolError::FrameTooLarge { + observed: encoded.len(), + limit: MAX_WORKER_FRAME_BYTES, + }); + } + writer + .write_all(&encoded) + .and_then(|()| writer.write_all(b"\n")) + .and_then(|()| writer.flush()) + .map_err(WorkerProtocolError::Io) +} + +/// Decode one bounded NDJSON frame. +/// +/// Clean EOF between frames returns `Ok(None)`. EOF after any bytes, an empty +/// line, malformed JSON, and an oversized line are distinct protocol errors. +/// The caller owns frame ordering and must reject a valid frame in an invalid +/// state. +pub fn read_frame(reader: &mut R) -> Result, WorkerProtocolError> +where + R: BufRead, + T: DeserializeOwned, +{ + let mut encoded = Vec::new(); + loop { + let available = reader.fill_buf().map_err(WorkerProtocolError::Io)?; + if available.is_empty() { + return if encoded.is_empty() { + Ok(None) + } else { + Err(WorkerProtocolError::UnterminatedFrame { + bytes: encoded.len(), + }) + }; + } + + if let Some(newline) = available.iter().position(|byte| *byte == b'\n') { + let observed = encoded.len().saturating_add(newline); + if observed > MAX_WORKER_FRAME_BYTES { + return Err(WorkerProtocolError::FrameTooLarge { + observed, + limit: MAX_WORKER_FRAME_BYTES, + }); + } + encoded.extend_from_slice(&available[..newline]); + reader.consume(newline + 1); + if encoded.is_empty() { + return Err(WorkerProtocolError::EmptyFrame); + } + return serde_json::from_slice(&encoded) + .map(Some) + .map_err(WorkerProtocolError::Decode); + } + + let chunk_len = available.len(); + let observed = encoded.len().saturating_add(chunk_len); + if observed > MAX_WORKER_FRAME_BYTES { + return Err(WorkerProtocolError::FrameTooLarge { + observed, + limit: MAX_WORKER_FRAME_BYTES, + }); + } + encoded.extend_from_slice(available); + reader.consume(chunk_len); + } +} + +/// Reject a frame from any worker protocol version other than this build's. +pub fn validate_protocol_version(observed: u32) -> Result<(), WorkerProtocolError> { + if observed == WORKER_PROTOCOL_VERSION { + Ok(()) + } else { + Err(WorkerProtocolError::UnsupportedVersion { + expected: WORKER_PROTOCOL_VERSION, + observed, + }) + } +} diff --git a/crates/omnigraph-bench/src/gqt_record.rs b/crates/omnigraph-bench/src/gqt_record.rs new file mode 100644 index 000000000..993d7f417 --- /dev/null +++ b/crates/omnigraph-bench/src/gqt_record.rs @@ -0,0 +1,381 @@ +//! Scenario-specific GQT authority records; legacy serializers stay unchanged. +use crate::gqt_case::GqtPointIdentityV1; +use crate::gqt_runner::{GqtRepObservation, RunExecution}; +use crate::record::*; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtRunIdentityV1 { + pub point_identity_version: u32, + pub point_id: String, + pub point_name: String, + pub case_id: String, + pub case_digest: String, + pub run_spec: GqtPointIdentityV1, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtMeasurementsV1 { + pub wall_clock: WallClockSummaryV1, + pub raw_samples: Vec, + pub layer_presence: MeasurementLayerPresenceV1, + pub claim_policy: ClaimPolicyV1, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtRunRecordV1 { + pub format_version: u32, + pub invocation: InvocationIdentityV1, + pub run: GqtRunIdentityV1, + pub sut: SutIdentityV1, + pub machine: crate::machine::MachineIdentityV1, + pub backend: ObservedBackendV1, + pub fixture: crate::dataset_cache::DatasetManifestV1, + pub dataset_cache_hit: bool, + pub acquisition: AcquisitionV1, + pub measurements: GqtMeasurementsV1, +} +impl GqtRunRecordV1 { + pub fn invocation(&self) -> &InvocationIdentityV1 { + &self.invocation + } + pub fn point_id(&self) -> &str { + &self.run.point_id + } + pub fn claim_eligible(&self) -> bool { + self.acquisition.is_complete() && self.sut.build.effective_codegen_options_proved + } +} +fn error(message: impl std::fmt::Display) -> RecordError { + RecordError::new("invalid_gqt_record", "$", message.to_string()) +} +pub fn build( + execution: &RunExecution, + invocation: InvocationIdentityV1, + terminal: Option, +) -> RecordResult { + execution.bound.revalidate().map_err(error)?; + for sample in &execution.samples { + crate::gqt_runner::validate_sample( + sample, + &execution.bound, + sample.repetition, + &execution.fixture.handoff.physical, + sample.elapsed_us, + true, + ) + .map_err(error)?; + } + let crate::case::Backend::LocalFs { + filesystem, + storage_class, + } = execution.bound.identity.environment.backend + else { + return Err(error("unsupported backend")); + }; + let record = GqtRunRecordV1 { + format_version: 1, + invocation, + run: GqtRunIdentityV1 { + point_identity_version: 1, + point_id: execution.point_id.clone(), + point_name: execution.point_name.clone(), + case_id: execution.case_id.clone(), + case_digest: execution.bound.plan.case_digest.clone(), + run_spec: execution.bound.identity.clone(), + }, + sut: sut_identity_for_build(&execution.build)?, + machine: execution.machine.clone(), + backend: ObservedBackendV1::LocalFs { + filesystem, + storage_class, + storage_protocol: execution.environment.storage_protocol.clone(), + probe: execution.environment.probe.into(), + }, + fixture: execution.fixture.clone(), + dataset_cache_hit: execution.dataset_cache_hit, + acquisition: AcquisitionV1 { + status: if terminal.is_some() { + AcquisitionStatusV1::Censored + } else { + AcquisitionStatusV1::Complete + }, + requested_repetitions: execution.requested_repetitions, + observed_repetitions: execution.samples.len() as u32, + terminal, + }, + measurements: GqtMeasurementsV1 { + wall_clock: summarize(&execution.samples)?, + raw_samples: execution.samples.clone(), + layer_presence: v1_layer_presence(), + claim_policy: ClaimPolicyV1 { + floor_multiplier_millis: DEFAULT_FLOOR_MULTIPLIER_MILLIS, + }, + }, + }; + validate(&record)?; + Ok(record) +} +fn summarize(samples: &[GqtRepObservation]) -> RecordResult { + if samples.is_empty() { + return Err(error("empty acquisition")); + } + let mut times: Vec<_> = samples.iter().map(|s| s.elapsed_us).collect(); + times.sort_unstable(); + let n = times.len(); + let supported = n >= 20; + Ok(WallClockSummaryV1 { + min_us: times[0], + p50_us: times[(n - 1) / 2], + max_us: times[n - 1], + p95_us: supported.then(|| times[(n * 95).div_ceil(100) - 1]), + p95_supported: supported, + evidence: if supported { + EvidenceStrengthV1::DistributionSupported + } else { + EvidenceStrengthV1::Directional + }, + }) +} +pub fn validate(r: &GqtRunRecordV1) -> RecordResult<()> { + crate::machine::validate_machine_identity(&r.machine).map_err(error)?; + validate_invocation(&r.invocation)?; + validate_sut(&r.sut)?; + validate_backend(&r.run.run_spec.environment.backend, &r.backend)?; + let point = crate::model::typed_sha256(&r.run.run_spec).map_err(error)?; + let spec = &r.run.run_spec; + crate::gqt_case::validate_point_spec(spec).map_err(error)?; + crate::dataset_cache::validate_manifest_evidence(&r.fixture).map_err(error)?; + let fixture = &r.fixture; + if r.format_version != 1 + || r.run.point_identity_version != 1 + || spec.identity_version != 1 + || point != r.run.point_id + || r.run.point_name + != format!( + "gqt-{}-{}", + spec.cache_condition.display_label(), + &point[..12] + ) + || fixture.format_version != 1 + || fixture.recipe_sha256 != spec.dataset_recipe_sha256 + || fixture.handoff.summary.logical_content_sha256 != spec.dataset_logical_digest + || fixture.handoff.summary.algorithm != spec.dataset_identity_algorithm + || fixture.reset != spec.protocol.reset + { + return Err(error("point or dataset binding mismatch")); + } + for digest in [ + &r.run.case_digest, + &fixture.engine_digest, + &fixture.key, + &fixture.handoff.physical.digest_sha256, + &spec.queries_sha256, + &spec.dataset_recipe_sha256, + &spec.dataset_logical_digest, + ] { + validate_sha256(digest, "digest")?; + } + if !crate::model::valid_kebab_id(&r.run.case_id) + || r.run.case_id.len() > 128 + || spec.measured_step.ordinal == 0 + || spec.measured_step.text.trim().is_empty() + { + return Err(error("invalid authored identity")); + } + let n = r.measurements.raw_samples.len(); + if n == 0 + || n > 10_000 + || r.acquisition.observed_repetitions as usize != n + || r.acquisition.requested_repetitions == 0 + || r.acquisition.requested_repetitions > 10_000 + { + return Err(error("invalid acquisition sample count")); + } + match (&r.acquisition.status, &r.acquisition.terminal) { + (AcquisitionStatusV1::Complete, None) + if n == r.acquisition.requested_repetitions as usize => {} + (AcquisitionStatusV1::Censored, Some(t)) + if n < r.acquisition.requested_repetitions as usize + && t.failed_repetition == n as u32 => + { + validate_acquisition_error_code(&t.code, "terminal.code")? + } + _ => return Err(error("invalid acquisition terminal")), + } + if r.measurements.wall_clock != summarize(&r.measurements.raw_samples)? + || r.measurements.layer_presence != v1_layer_presence() + || r.measurements.claim_policy.floor_multiplier_millis != DEFAULT_FLOOR_MULTIPLIER_MILLIS + { + return Err(error("measurement summary or presence mismatch")); + } + for (i, s) in r.measurements.raw_samples.iter().enumerate() { + validate_call_totals( + i, + s.logical_store_calls.manifest, + s.logical_store_calls.table, + &s.control_store_calls, + )?; + let selected_kind = selected_kind(&spec.measured_step.text)?; + crate::gqt_runner::validate_merge_evidence( + s.merge.as_ref(), + selected_kind, + spec.protocol.attribution, + ) + .map_err(error)?; + crate::gqt_runner::validate_receipt_treatment( + &s.steps, + spec.measured_step.ordinal, + &spec.cache_condition, + ) + .map_err(error)?; + let selected: Vec<_> = s + .steps + .iter() + .filter(|step| step.ordinal == spec.measured_step.ordinal) + .collect(); + if s.repetition != i as u32 + 1 + || s.input_physical_digest_sha256 != fixture.handoff.physical.digest_sha256 + || s.peak_rss_bytes.is_none_or(|n| n == 0) + || s.outcome != "expectations-passed" + || s.logical_store_calls.physical_attempts_observed + || selected.len() != 1 + || selected[0].occurrence != 1 + || selected[0].kind != selected_kind.into() + || selected[0].elapsed_us != s.elapsed_us + || s.steps.len() > crate::gqt_case::MAX_EXPANDED_STEPS + || !s.verification.selected_assertion_passed + || s.verification.following_assertions == 0 + || s.verification.assertions_passed < 2 + || s.verification.assertions_passed as usize > crate::gqt_case::MAX_EXPANDED_STEPS + || s.verification.following_assertions >= s.verification.assertions_passed + { + return Err(error("invalid GQT sample")); + } + let mut seen = std::collections::BTreeMap::new(); + for step in &s.steps { + let occurrence = seen.entry(step.ordinal).or_insert(0); + *occurrence += 1; + if step.ordinal == 0 || *occurrence != step.occurrence { + return Err(error("invalid operation receipt sequence")); + } + } + } + Ok(()) +} +/// Closed archive dispatch keeps the exact historical field ordering intact. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AnyRunRecordV1 { + Legacy(RunRecordV1), + Gqt(GqtRunRecordV1), +} +impl AnyRunRecordV1 { + pub fn invocation(&self) -> &InvocationIdentityV1 { + match self { + Self::Legacy(r) => &r.invocation, + Self::Gqt(r) => &r.invocation, + } + } + pub fn point_id(&self) -> &str { + match self { + Self::Legacy(r) => &r.run.point_id, + Self::Gqt(r) => &r.run.point_id, + } + } + pub fn validate(&self) -> RecordResult<()> { + match self { + Self::Legacy(r) => validate_run_record(r), + Self::Gqt(r) => validate(r), + } + } +} +pub trait AuthorityRecord: Serialize { + fn invocation(&self) -> &InvocationIdentityV1; + fn validate_authority(&self) -> RecordResult<()>; +} +impl AuthorityRecord for RunRecordV1 { + fn invocation(&self) -> &InvocationIdentityV1 { + &self.invocation + } + fn validate_authority(&self) -> RecordResult<()> { + validate_run_record(self) + } +} +impl AuthorityRecord for GqtRunRecordV1 { + fn invocation(&self) -> &InvocationIdentityV1 { + &self.invocation + } + fn validate_authority(&self) -> RecordResult<()> { + validate(self) + } +} +impl AuthorityRecord for AnyRunRecordV1 { + fn invocation(&self) -> &InvocationIdentityV1 { + self.invocation() + } + fn validate_authority(&self) -> RecordResult<()> { + self.validate() + } +} +pub fn canonical_bytes(record: &R) -> RecordResult> { + record.validate_authority()?; + let bytes = serde_json::to_vec(record).map_err(error)?; + if bytes.len() > MAX_RECORD_BYTES { + return Err(error("record exceeds byte budget")); + } + Ok(bytes) +} +pub fn parse(bytes: &[u8]) -> RecordResult { + if bytes.len() > MAX_RECORD_BYTES { + return Err(error("record exceeds byte budget")); + } + let record: AnyRunRecordV1 = serde_json::from_slice(bytes).map_err(error)?; + if canonical_bytes(&record)? != bytes { + return Err(error("record is not canonical")); + } + Ok(record) +} +impl From for AnyRunRecordV1 { + fn from(r: RunRecordV1) -> Self { + Self::Legacy(r) + } +} +impl From for AnyRunRecordV1 { + fn from(r: GqtRunRecordV1) -> Self { + Self::Gqt(r) + } +} + +fn selected_kind(text: &str) -> RecordResult { + use omnigraph_gqt_core::{Item, Step, StepKind}; + let suffix = if text.trim() == "--- restart" { + "" + } else { + "\n--- expect error: descriptor-only validation\n" + }; + let input = format!( + "# issue: none\n# notes: Durable selected operation syntax.\n--- runner\ntimeout_ms: 10000\nenvironments:\n - target: omnigraph-engine\n storage: local-filesystem\n{text}{suffix}" + ); + let case = + omnigraph_gqt_core::parse_case("record_selected_operation", &input).map_err(error)?; + let descriptors = case.steps(); + let [selected] = descriptors.as_slice() else { + return Err(error("selected echo must contain one operation")); + }; + if selected.source != text.trim() + || selected.in_loop + || matches!( + selected.kind, + StepKind::Show | StepKind::Settings | StepKind::Concurrent + ) + { + return Err(error("selected echo is not an admitted engine operation")); + } + if let Some(Item::Step(Step::Load(load))) = case.items.first() { + if load.call_count() != 1 { + return Err(error("selected load must make one engine call")); + } + } + Ok(selected.kind) +} diff --git a/crates/omnigraph-bench/src/gqt_runner.rs b/crates/omnigraph-bench/src/gqt_runner.rs new file mode 100644 index 000000000..0f8819c02 --- /dev/null +++ b/crates/omnigraph-bench/src/gqt_runner.rs @@ -0,0 +1,1112 @@ +//! One engine operation selected from a frozen GQT program. Dataset building, +//! process supervision, result assertions and archive work are outside its clock. +use crate::case::Backend; +use crate::counting::LogicalCallCounter; +use crate::dataset_cache::DatasetManifestV1; +use crate::gqt_case::{BoundGqt, DatasetBuildPlan, PlannedGqt}; +use crate::preparation::{PreparationWriteGate, guard_preparation_writes}; +use crate::reset::{MetadataDigest, PhysicalDigest, TraversalLimits, verify_metadata_shape}; +use crate::runner::{ + BuildEvidence, ControlCallObservation, ControlSnapshot, LogicalStoreCallObservation, + MeasurementSignals, RunnerError, RunnerResult, WallClockSummary, +}; +use futures::{FutureExt, future::BoxFuture}; +use lance::io::WrappingObjectStore; +use omnigraph::db::Omnigraph; +use omnigraph::error::OmniError; +use omnigraph::instrumentation::{ + CountingStorageAdapter, MergeWriteProbes, QueryIoProbes, StorageReadCounts, + with_merge_write_probes, with_query_io_probes, +}; +use omnigraph::storage::StorageAdapter; +use omnigraph_compiler::settings::Engine; +use omnigraph_gqt_core::runner_config::SeamDirective; +use omnigraph_gqt_core::{ExecutionHost, Step, StepKind, case_session, execute_steps}; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, Instant}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GqtOperationKind { + Query, + Mutate, + Load, + BranchCreate, + BranchDelete, + BranchMerge, + BranchList, + Settings, + Show, + Restart, + Concurrent, +} +impl From for GqtOperationKind { + fn from(kind: StepKind) -> Self { + match kind { + StepKind::Query => Self::Query, + StepKind::Mutate => Self::Mutate, + StepKind::Load => Self::Load, + StepKind::BranchCreate => Self::BranchCreate, + StepKind::BranchDelete => Self::BranchDelete, + StepKind::BranchMerge => Self::BranchMerge, + StepKind::BranchList => Self::BranchList, + StepKind::Settings => Self::Settings, + StepKind::Show => Self::Show, + StepKind::Restart => Self::Restart, + StepKind::Concurrent => Self::Concurrent, + } + } +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtStepObservation { + pub ordinal: usize, + pub occurrence: u32, + pub kind: GqtOperationKind, + pub elapsed_us: u64, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtVerification { + pub selected_assertion_passed: bool, + pub assertions_passed: u32, + pub following_assertions: u32, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtMergeEvidence { + pub phases: Vec, + pub route: crate::runner::MergeRouteObservation, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GqtRepObservation { + pub repetition: u32, + pub input_physical_digest_sha256: String, + pub elapsed_us: u64, + pub peak_rss_bytes: Option, + pub outcome: String, + pub logical_store_calls: LogicalStoreCallObservation, + pub control_store_calls: ControlCallObservation, + pub steps: Vec, + pub verification: GqtVerification, + pub merge: Option, +} +#[derive(Debug, Clone, Default)] +pub struct RunOptions { + pub scratch_root: Option, + pub worker_executable: Option, + pub dataset_cache: Option, + pub no_build: bool, + pub fixture_bindings: Vec, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct RunExecution { + pub runner_output_version: u32, + pub case_id: String, + pub case_path: PathBuf, + pub point_id: String, + pub point_name: String, + pub requested_repetitions: u32, + pub bound: BoundGqt, + pub build: BuildEvidence, + pub machine: crate::machine::MachineIdentityV1, + pub environment: crate::environment::LocalEnvironmentEvidence, + pub fixture: DatasetManifestV1, + pub dataset_cache_hit: bool, + pub samples: Vec, + pub wall_clock: WallClockSummary, + pub durable_record: bool, +} +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct SuiteExecution { + pub runner_output_version: u32, + pub suite: String, + pub suite_path: PathBuf, + pub runs: Vec, +} +struct Generation { + storage: Arc, + counts: Arc, + gate: Option, +} +fn generation(uri: &str, guarded: bool) -> RunnerResult { + let storage = omnigraph::storage::storage_for_uri(uri).map_err(|e| failure(e.to_string()))?; + let (storage, gate) = if guarded { + let (s, g) = guard_preparation_writes(storage, uri); + (s, Some(g)) + } else { + (storage, None) + }; + let (storage, counts) = CountingStorageAdapter::new(storage); + Ok(Generation { + storage, + counts, + gate, + }) +} +struct HostState { + generation: Generation, + current: usize, + started: Option<(usize, Instant)>, + baseline: Option, + elapsed: Option, + logical: Option, + control: Option, + steps: Vec, + occurrences: BTreeMap, + prefix_reads: u32, + assertions: u32, + following: u32, + selected_assertion: bool, + error: Option, + ready: bool, + settled: bool, + merge: Option, +} +struct BenchHost<'a, S> { + signals: Mutex<&'a mut S>, + state: Mutex, + selected: usize, + kinds: BTreeMap, + root: &'a Path, + uri: &'a str, + metadata: &'a MetadataDigest, + expected_reads: u32, + manifest: LogicalCallCounter, + table: LogicalCallCounter, + merge_probes: MergeWriteProbes, + attribution: crate::case::Attribution, +} +fn failure(message: impl std::fmt::Display) -> RunnerError { + RunnerError::new("gqt_prepare_failed", message.to_string()) +} +impl BenchHost<'_, S> { + fn start(&self, ordinal: usize) -> RunnerResult<()> { + let mut state = self.state.lock().unwrap(); + let kind = self + .kinds + .get(&ordinal) + .ok_or_else(|| failure("unknown operation ordinal"))?; + if state.started.is_some() { + return Err(failure("overlapping operation callbacks")); + } + if *kind == StepKind::Restart { + if state.elapsed.is_none() { + state + .generation + .gate + .as_ref() + .ok_or_else(|| failure("missing preparation gate"))? + .validate_preparation() + .map_err(failure)?; + } + state.generation = generation(self.uri, state.elapsed.is_none())?; + } + if ordinal == self.selected { + if state.elapsed.is_some() { + return Err(failure("selected operation executed more than once")); + } + if state.prefix_reads != self.expected_reads { + return Err(failure( + "prefix read did not execute an engine operation; cache treatment is unproved", + )); + } + verify_metadata_shape(self.root, self.metadata, TraversalLimits::default()) + .map_err(|e| failure(e.to_string()))?; + self.signals.lock().unwrap().ready()?; + state.ready = true; + if self.manifest.take().has_mutations() || self.table.take().has_mutations() { + return Err(failure("Lance mutation occurred before selected operation")); + } + state.baseline = Some(ControlSnapshot::read(&state.generation.counts)); + if *kind != StepKind::Restart { + state + .generation + .gate + .as_ref() + .ok_or_else(|| failure("missing preparation gate"))? + .begin_measurement() + .map_err(failure)?; + } + } else if ordinal < self.selected && matches!(kind, StepKind::Query | StepKind::BranchList) + { + state.prefix_reads += 1; + } + state.started = Some((ordinal, Instant::now())); + Ok(()) + } + fn finish(&self, ordinal: usize) -> RunnerResult<()> { + let ended = Instant::now(); + let mut state = self.state.lock().unwrap(); + let (started_ordinal, started) = state + .started + .take() + .ok_or_else(|| failure("operation finished without starting"))?; + if started_ordinal != ordinal { + return Err(failure("operation callback ordinal mismatch")); + } + let elapsed = u64::try_from(ended.duration_since(started).as_micros()) + .map_err(|_| failure("operation duration overflow"))?; + let occurrence = { + let n = state.occurrences.entry(ordinal).or_default(); + *n += 1; + *n + }; + state.steps.push(GqtStepObservation { + ordinal, + occurrence, + kind: self.kinds[&ordinal].into(), + elapsed_us: elapsed, + }); + if ordinal == self.selected { + state.elapsed = Some(elapsed); + state.logical = Some(LogicalStoreCallObservation { + manifest: self.manifest.take(), + table: self.table.take(), + physical_attempts_observed: false, + }); + state.control = Some( + state + .baseline + .take() + .ok_or_else(|| failure("missing counter baseline"))? + .delta(ControlSnapshot::read(&state.generation.counts))?, + ); + if self.kinds[&ordinal] == StepKind::BranchMerge + && self.attribution == crate::case::Attribution::PerPhase + { + state.merge = Some(GqtMergeEvidence { + phases: crate::runner::phase_observations( + self.merge_probes.merge_timing_snapshot(), + ), + route: crate::runner::MergeRouteObservation::from_probes(&self.merge_probes), + }); + } + self.signals.lock().unwrap().settled(elapsed)?; + state.settled = true; + if self.kinds[&ordinal] == StepKind::Restart { + state + .generation + .gate + .as_ref() + .ok_or_else(|| failure("missing reopen gate"))? + .begin_measurement() + .map_err(failure)?; + } + } + Ok(()) + } + fn callback(&self, result: RunnerResult<()>) -> Result<(), String> { + result.map_err(|error| { + let message = error.to_string(); + let mut state = self.state.lock().unwrap(); + state.error = Some(RunnerError::new(stage_code(&state), message.clone())); + message + }) + } +} +impl ExecutionHost for BenchHost<'_, S> { + type StepGuard = (); + fn arm_seams(&self, seams: &[SeamDirective], _: &Step) -> Result<(), String> { + if seams.is_empty() { + Ok(()) + } else { + Err("benchmark does not support seams".into()) + } + } + fn finish_seams(&self, _: ()) -> Result<(), String> { + Ok(()) + } + fn operation_started(&self, ordinal: usize) -> Result<(), String> { + self.callback(self.start(ordinal)) + } + fn operation_finished(&self, ordinal: usize) -> Result<(), String> { + self.callback(self.finish(ordinal)) + } + fn begin_operation(&self, value: impl FnOnce() -> serde_json::Value) { + self.state.lock().unwrap().current = value()["ordinal"].as_u64().unwrap_or(0) as usize; + } + fn record(&self, kind: &str, value: impl FnOnce() -> serde_json::Value) { + if kind == "assertion" && value()["status"] == "passed" { + let mut s = self.state.lock().unwrap(); + s.assertions += 1; + if s.current == self.selected { + s.selected_assertion = true + } + if s.current > self.selected + && crate::gqt_case::explicit_verification(self.kinds[&s.current]) + { + s.following += 1 + } + } + } + fn reopen<'a>( + &'a self, + uri: &'a str, + _: Option>, + ) -> BoxFuture<'a, Result> { + let storage = self.state.lock().unwrap().generation.storage.clone(); + async move { Omnigraph::open_with_storage(uri, storage).await }.boxed() + } +} +pub(crate) async fn execute_gqt_rep_signaled( + repetition: u32, + root: &Path, + input: &PhysicalDigest, + metadata: &MetadataDigest, + bound: &BoundGqt, + signals: &mut S, +) -> RunnerResult { + bound.revalidate().map_err(failure)?; + let case = bound.plan.queries.parse().map_err(failure)?; + let uri = root + .to_str() + .ok_or_else(|| failure("non-UTF8 store path"))?; + let whole_file_started = Instant::now(); + let manifest = LogicalCallCounter::default(); + let table = LogicalCallCounter::default(); + let probes = QueryIoProbes { + manifest_wrapper: Some(Arc::new(manifest.clone()) as Arc), + table_wrapper: Some(Arc::new(table.clone()) as Arc), + ..Default::default() + }; + with_query_io_probes(probes, async { + let generation = generation(uri, true)?; + let db = tokio::time::timeout( + Duration::from_millis(case.runner.timeout_ms), + Omnigraph::open_with_storage(uri, generation.storage.clone()), + ) + .await + .map_err(|_| failure("whole-file timeout during open"))? + .map_err(failure)?; + let merge_probes = MergeWriteProbes::default(); + let session = case_session(db, &case, Engine::V2).map_err(failure)?; + let host = BenchHost { + signals: Mutex::new(signals), + selected: bound.plan.definition.workload.measured_step.ordinal, + kinds: case + .steps() + .into_iter() + .map(|s| (s.ordinal, s.kind)) + .collect(), + root, + uri, + metadata, + expected_reads: bound.plan.cache_condition.iterations, + manifest, + table, + merge_probes: merge_probes.clone(), + attribution: bound.plan.definition.protocol.attribution, + state: Mutex::new(HostState { + generation, + current: 0, + started: None, + baseline: None, + elapsed: None, + logical: None, + control: None, + steps: Vec::new(), + occurrences: BTreeMap::new(), + prefix_reads: 0, + assertions: 0, + following: 0, + selected_assertion: false, + error: None, + ready: false, + settled: false, + merge: None, + }), + }; + let executed = execute_steps( + &case, + Path::new(&bound.plan.queries.stem), + false, + session, + uri, + None, + &host, + ); + let executed = if host.kinds[&host.selected] == StepKind::BranchMerge + && host.attribution == crate::case::Attribution::PerPhase + { + with_merge_write_probes(merge_probes, executed).boxed() + } else { + executed + }; + let result = tokio::time::timeout( + Duration::from_millis(case.runner.timeout_ms) + .saturating_sub(whole_file_started.elapsed()), + executed, + ) + .await + .unwrap_or_else(|_| Err("queries whole-file timeout exceeded".into())); + + let mut state = host.state.lock().unwrap(); + let error = state.error.take().or_else(|| { + result + .as_ref() + .err() + .map(|message| RunnerError::new(stage_code(&state), message)) + }); + drop(result); + if let Some(mut error) = error { + if state.settled { + if let (Some(elapsed), Some(logical), Some(control)) = + (state.elapsed, state.logical.take(), state.control.take()) + { + error.context.gqt_settled_sample = Some(Box::new(GqtRepObservation { + repetition, + input_physical_digest_sha256: input.digest_sha256.clone(), + elapsed_us: elapsed, + peak_rss_bytes: None, + outcome: "verification-failed".into(), + logical_store_calls: logical, + control_store_calls: control, + steps: std::mem::take(&mut state.steps), + verification: GqtVerification { + selected_assertion_passed: state.selected_assertion, + assertions_passed: state.assertions, + following_assertions: state.following, + }, + merge: state.merge.take(), + })); + } + } + return Err(error); + } + let sample = GqtRepObservation { + repetition, + input_physical_digest_sha256: input.digest_sha256.clone(), + elapsed_us: state + .elapsed + .ok_or_else(|| failure("selected operation never reached the engine"))?, + peak_rss_bytes: None, + outcome: "expectations-passed".into(), + logical_store_calls: state + .logical + .take() + .ok_or_else(|| failure("missing logical counters"))?, + control_store_calls: state + .control + .take() + .ok_or_else(|| failure("missing control counters"))?, + steps: std::mem::take(&mut state.steps), + merge: state.merge.take(), + verification: GqtVerification { + selected_assertion_passed: state.selected_assertion, + assertions_passed: state.assertions, + following_assertions: state.following, + }, + }; + if let Err(error) = + validate_sample(&sample, bound, repetition, input, sample.elapsed_us, false) + { + let mut sample = sample; + sample.outcome = "verification-failed".into(); + return Err( + RunnerError::new("gqt_verification_failed", error.to_string()) + .with_gqt_settled_sample(sample), + ); + } + Ok(sample) + }) + .await +} +pub(crate) fn validate_sample( + sample: &GqtRepObservation, + bound: &BoundGqt, + repetition: u32, + input: &PhysicalDigest, + elapsed: u64, + parent: bool, +) -> RunnerResult<()> { + validate_evidence(sample, bound, repetition, input, elapsed, parent, false) +} +pub(crate) fn validate_failed_sample( + sample: &GqtRepObservation, + bound: &BoundGqt, + repetition: u32, + input: &PhysicalDigest, + elapsed: u64, +) -> RunnerResult<()> { + validate_evidence(sample, bound, repetition, input, elapsed, false, true) +} +fn validate_evidence( + sample: &GqtRepObservation, + bound: &BoundGqt, + repetition: u32, + input: &PhysicalDigest, + elapsed: u64, + parent: bool, + failed: bool, +) -> RunnerResult<()> { + let selected = bound.plan.definition.workload.measured_step.ordinal; + let receipts: Vec<_> = sample + .steps + .iter() + .filter(|s| s.ordinal == selected) + .collect(); + if sample.repetition != repetition + || sample.input_physical_digest_sha256 != input.digest_sha256 + || sample.elapsed_us != elapsed + || sample.outcome + != if failed { + "verification-failed" + } else { + "expectations-passed" + } + || receipts.len() != 1 + || receipts[0].elapsed_us != elapsed + || receipts[0].occurrence != 1 + || (!failed + && (!sample.verification.selected_assertion_passed + || sample.verification.following_assertions == 0 + || sample.verification.assertions_passed < 2)) + || sample.logical_store_calls.physical_attempts_observed + || sample.peak_rss_bytes.is_some() != parent + { + return Err(failure( + "GQT sample evidence disagrees with the admitted operation", + )); + } + let case = bound.plan.queries.parse().map_err(failure)?; + let kinds: BTreeMap<_, _> = case + .steps() + .into_iter() + .map(|s| (s.ordinal, s.kind)) + .collect(); + crate::record::validate_call_totals( + repetition as usize, + sample.logical_store_calls.manifest, + sample.logical_store_calls.table, + &sample.control_store_calls, + ) + .map_err(failure)?; + validate_merge_evidence( + sample.merge.as_ref(), + kinds[&selected], + bound.plan.definition.protocol.attribution, + ) + .map_err(failure)?; + validate_receipt_treatment(&sample.steps, selected, &bound.identity.cache_condition) + .map_err(failure)?; + let mut occurrences = BTreeMap::new(); + if sample.steps.len() > crate::gqt_case::MAX_EXPANDED_STEPS { + return Err(failure("too many operation receipts")); + } + for step in &sample.steps { + if kinds + .get(&step.ordinal) + .is_none_or(|kind| GqtOperationKind::from(*kind) != step.kind) + { + return Err(failure("unknown receipt ordinal")); + } + let n = occurrences.entry(step.ordinal).or_insert(0); + *n += 1; + if *n != step.occurrence { + return Err(failure("receipt occurrence sequence mismatch")); + } + } + Ok(()) +} + +pub async fn execute_suite( + suite: &crate::suite::ResolvedSuite, + options: &RunOptions, +) -> RunnerResult { + let mut runs = Vec::new(); + let mut identities = std::collections::BTreeSet::new(); + for run in &suite.runs { + let executed = execute_run(run, options).await?; + if !identities.insert(executed.point_id.clone()) { + return Err(failure("suite contains duplicate bound point identity")); + } + runs.push(executed) + } + Ok(SuiteExecution { + runner_output_version: 1, + suite: suite.definition.name.clone(), + suite_path: suite.suite_path.clone(), + runs, + }) +} +/// Canonical bytes: manifest <=1 MiB, run identity <512 KiB, SUT <=8 KiB, +/// machine <32 KiB, backend <16 KiB and remaining bounded fields <8 KiB. +/// Each component is admitted by record validation; pretty diagnostics are excluded. +pub(crate) const GQT_RECORD_ENVELOPE_RESERVE: usize = 2 * 1024 * 1024; + +pub(crate) fn sample_byte_upper_bound(plan: &PlannedGqt) -> RunnerResult { + let case = plan.queries.parse().map_err(failure)?; + let selected = plan.definition.workload.measured_step.ordinal; + let selected_kind = case + .steps() + .into_iter() + .find(|s| s.ordinal == selected) + .ok_or_else(|| failure("selected operation is missing"))? + .kind; + let mut steps = Vec::new(); + for item in &case.items { + let (body, times) = match item { + omnigraph_gqt_core::Item::Step(step) => (std::slice::from_ref(step), 1), + omnigraph_gqt_core::Item::Loop { steps, values, .. } => { + (steps.as_slice(), values.len()) + } + }; + let count = body + .len() + .checked_mul(times) + .and_then(|n| n.checked_add(steps.len())) + .ok_or_else(|| failure("receipt count overflow"))?; + if count > crate::gqt_case::MAX_EXPANDED_STEPS { + return Err(failure("receipt count exceeds admitted program bound")); + } + for _ in 0..times { + for step in body { + steps.push(GqtStepObservation { + ordinal: step.ordinal(), + occurrence: u32::MAX, + kind: step.operation_kind().into(), + elapsed_us: u64::MAX, + }); + } + } + } + let counts = crate::counting::LogicalCallCounts { + get: u64::MAX, + put: u64::MAX, + put_part: u64::MAX, + head: u64::MAX, + list: u64::MAX, + delete: u64::MAX, + copy: u64::MAX, + rename: u64::MAX, + multipart_complete: u64::MAX, + multipart_abort: u64::MAX, + }; + let merge = if selected_kind == StepKind::BranchMerge + && plan.definition.protocol.attribution == crate::case::Attribution::PerPhase + { + let mut phases = + crate::runner::phase_observations(MergeWriteProbes::default().merge_timing_snapshot()); + for p in &mut phases { + p.total_us = u64::MAX; + p.max_us = u64::MAX; + p.interval_count = u64::MAX; + } + Some(GqtMergeEvidence { + phases, + route: crate::runner::MergeRouteObservation { + table_walk_intervals: u64::MAX, + stage_merge_insert_calls: u64::MAX, + stage_merge_insert_rows: u64::MAX, + stage_known_present_update_calls: u64::MAX, + stage_known_present_update_rows: u64::MAX, + stage_fenced_insert_calls: u64::MAX, + stage_fenced_insert_rows: u64::MAX, + strict_insert_preflight_calls: u64::MAX, + }, + }) + } else { + None + }; + let sample = GqtRepObservation { + repetition: u32::MAX, + input_physical_digest_sha256: "0".repeat(64), + elapsed_us: u64::MAX, + peak_rss_bytes: Some(u64::MAX), + outcome: "expectations-passed".into(), + logical_store_calls: LogicalStoreCallObservation { + manifest: counts, + table: counts, + physical_attempts_observed: false, + }, + control_store_calls: ControlCallObservation { + read_text: u64::MAX, + read_text_if_exists: u64::MAX, + read_text_versioned: u64::MAX, + exists: u64::MAX, + list_dir: u64::MAX, + mutation_calls: u64::MAX, + write_text: u64::MAX, + delete: u64::MAX, + }, + steps, + verification: GqtVerification { + selected_assertion_passed: false, + assertions_passed: u32::MAX, + following_assertions: u32::MAX, + }, + merge, + }; + serde_json::to_vec(&sample) + .map(|v| v.len()) + .map_err(failure) +} + +pub(crate) fn preflight_acquisition_budget( + plan: &PlannedGqt, + repetitions: u32, +) -> RunnerResult<()> { + let sample = sample_byte_upper_bound(plan)?; + let bytes = sample + .checked_add(1) + .and_then(|n| n.checked_mul(repetitions as usize)) + .and_then(|n| n.checked_add(GQT_RECORD_ENVELOPE_RESERVE)) + .ok_or_else(|| { + RunnerError::new("gqt_record_budget_exceeded", "receipt byte bound overflow") + })?; + if bytes > crate::record::MAX_RECORD_BYTES { + return Err(RunnerError::new( + "gqt_record_budget_exceeded", + format!( + "{repetitions} repetitions require a worst-case canonical receipt budget of {bytes} bytes; limit is {}; reduce repetitions", + crate::record::MAX_RECORD_BYTES + ), + )); + } + Ok(()) +} + +pub async fn execute_run( + run: &crate::suite::ResolvedRun, + options: &RunOptions, +) -> RunnerResult { + crate::runner::enforce_release_build().map_err(|mut error| { + error.context.case_id = Some(run.case.id().to_owned()); + error + })?; + crate::runner::refuse_unmodeled_runtime_overrides()?; + let plan = run.case.gqt().map_err(failure)?.clone(); + plan.revalidate().map_err(failure)?; + if run.repetitions == 0 || run.repetitions > crate::suite::MAX_REPETITIONS_PER_CASE { + return Err(failure("invalid repetition count")); + } + preflight_acquisition_budget(&plan, run.repetitions)?; + let run = run.clone(); + let options = options.clone(); + tokio::task::spawn_blocking(move || { + std::thread::Builder::new() + .name("gqt-run-owner".into()) + .stack_size(64 * 1024 * 1024) + .spawn(move || execute_owned(run, plan, options)) + .map_err(|e| failure(e.to_string()))? + .join() + .map_err(|_| failure("run owner panicked"))? + }) + .await + .map_err(|e| failure(e.to_string()))? +} +fn execute_owned( + run: crate::suite::ResolvedRun, + plan: PlannedGqt, + options: RunOptions, +) -> RunnerResult { + let cache = options + .dataset_cache + .clone() + .or_else(|| options.scratch_root.as_ref().map(|p| p.join("datasets"))) + .ok_or_else(|| failure("--dataset-cache or --scratch-root is required"))?; + std::fs::create_dir_all(&cache).map_err(|e| failure(e.to_string()))?; + let Backend::LocalFs { + filesystem, + storage_class, + } = plan.definition.environment.backend + else { + return Err(failure("local backend required")); + }; + let environment = + crate::environment::verify_local_environment(&cache, filesystem, storage_class) + .map_err(failure)?; + let workspace = tempfile::Builder::new() + .prefix("gqt-run-") + .tempdir_in(&cache) + .map_err(|e| failure(e.to_string()))?; + let source = crate::runner::resolve_bound_worker( + options + .worker_executable + .as_deref() + .ok_or_else(|| failure("worker executable required"))?, + )?; + let worker = crate::runner::stage_bound_worker(source, workspace.path())?; + crate::gqt_supervisor::preflight_plan(&plan, &cache.canonicalize().map_err(failure)?)?; + let binding = binding(&plan.dataset, &options.fixture_bindings)?; + let lease = crate::dataset_cache::acquire( + &plan.dataset_build_plan(), + &cache, + &worker.executable, + options.no_build, + binding, + )?; + let bound = plan + .bind( + &lease.manifest.handoff.summary.logical_content_sha256, + &lease.manifest.handoff.summary.algorithm, + ) + .map_err(failure)?; + let mut samples = Vec::new(); + let mut machine = None; + let mut build = None; + let acquisition = (|| -> RunnerResult<()> { + for repetition in 1..=run.repetitions { + let metadata = lease.restore()?; + let scratch = lease.root.join(format!("worker-scratch-{repetition:08}")); + std::fs::create_dir(&scratch).map_err(|e| failure(e.to_string()))?; + let input = crate::gqt_supervisor::SupervisionInput { + worker_executable: worker.executable.clone(), + expected_worker_executable_sha256: worker.executable_sha256.clone(), + expected_machine: machine.clone(), + fixture_manifest_sha256: crate::model::typed_sha256(&lease.manifest) + .map_err(|e| failure(e.to_string()))?, + repetition, + case: bound.clone(), + repetition_root: lease.active.clone(), + worker_scratch_root: scratch.clone(), + physical_digest: lease.physical().clone(), + metadata_digest: metadata, + deadline: plan + .definition + .protocol + .deadline_seconds + .map(Duration::from_secs), + #[cfg(test)] + auxiliary_deadline_override: None, + }; + match crate::gqt_supervisor::supervise_repetition(input) { + Ok(observed) => { + validate_sample( + &observed.sample, + &bound, + repetition, + lease.physical(), + observed.sample.elapsed_us, + true, + )?; + machine = Some(observed.machine); + build = Some(observed.worker_build); + samples.push(observed.sample); + lease.remove_active()?; + std::fs::remove_dir_all(&scratch).map_err(|e| failure(e.to_string()))?; + } + Err(mut error) => { + if crate::dataset_cache::contained(&error) { + lease.remove_active()?; + let _ = std::fs::remove_dir_all(&scratch); + } else { + let marker = lease.quarantine(&error.message); + let _ = workspace.keep(); + if let Err(marker) = marker { + error.message.push_str(&format!( + "; quarantine marker failed: {}", + marker.message + )); + } + } + return Err(error); + } + } + } + lease.verify()?; + Ok(()) + })(); + if samples.is_empty() { + return Err(acquisition + .err() + .unwrap_or_else(|| failure("empty acquisition"))); + } + let mut times: Vec<_> = samples.iter().map(|s| s.elapsed_us).collect(); + times.sort_unstable(); + let count = times.len(); + let p95_supported = count >= 20; + let wall_clock = WallClockSummary { + observed_repetitions: count as u32, + min_us: times[0], + p50_us: times[(count - 1) / 2], + max_us: times[count - 1], + p95_us: p95_supported.then(|| times[(count * 95).div_ceil(100) - 1]), + p95_supported, + }; + let execution = RunExecution { + runner_output_version: 1, + case_id: plan.definition.id.clone(), + case_path: run.case_path, + point_id: bound.point_id.clone(), + point_name: bound.point_name.clone(), + requested_repetitions: run.repetitions, + bound, + build: crate::runner::build_evidence(build.as_ref())?, + machine: machine.ok_or_else(|| failure("no worker identity"))?, + environment, + fixture: lease.manifest.clone(), + dataset_cache_hit: lease.cache_hit, + samples, + wall_clock, + durable_record: false, + }; + match acquisition { + Ok(()) => Ok(execution), + Err(mut error) => { + error.context.gqt_partial_run = Some(Box::new(execution)); + Err(error) + } + } +} +fn binding<'a>( + recipe: &crate::gqt_case::DatasetRecipe, + bindings: &'a [String], +) -> RunnerResult> { + if let crate::gqt_case::DatasetRecipe::Registered { reference, .. } = recipe { + let matches: Vec<_> = bindings + .iter() + .filter(|b| { + b.split_once('=') + .is_some_and(|(id, _)| id == reference.definition.fixture_id) + }) + .collect(); + if matches.len() != 1 { + return Err(failure( + "registered dataset requires exactly one matching --fixture ID=BUNDLE", + )); + } + Ok(Some(matches[0])) + } else { + if !bindings.is_empty() { + return Err(failure("--fixture supplied for an authored dataset")); + } + Ok(None) + } +} +pub async fn build_dataset( + plan: &DatasetBuildPlan, + options: &RunOptions, +) -> RunnerResult { + crate::runner::enforce_release_build()?; + crate::runner::refuse_unmodeled_runtime_overrides()?; + plan.revalidate().map_err(failure)?; + let plan = plan.clone(); + let options = options.clone(); + tokio::task::spawn_blocking(move || { + let cache = options + .dataset_cache + .as_deref() + .ok_or_else(|| failure("--dataset-cache is required"))?; + std::fs::create_dir_all(cache).map_err(|e| failure(e.to_string()))?; + let Backend::LocalFs { + filesystem, + storage_class, + } = plan.environment.backend + else { + return Err(failure("local backend required")); + }; + crate::environment::verify_local_environment(cache, filesystem, storage_class) + .map_err(failure)?; + let workspace = tempfile::Builder::new() + .prefix("gqt-build-") + .tempdir_in(cache) + .map_err(|e| failure(e.to_string()))?; + let worker = crate::runner::stage_bound_worker( + crate::runner::resolve_bound_worker( + options + .worker_executable + .as_deref() + .ok_or_else(|| failure("worker executable required"))?, + )?, + workspace.path(), + )?; + let binding = binding(&plan.dataset, &options.fixture_bindings)?; + crate::dataset_cache::acquire(&plan, cache, &worker.executable, options.no_build, binding) + .map(|lease| lease.manifest.clone()) + }) + .await + .map_err(|e| failure(e.to_string()))? +} + +fn stage_code(state: &HostState) -> &'static str { + if state.settled { + "gqt_verification_failed" + } else if state.ready { + "gqt_measure_failed" + } else { + "gqt_prepare_failed" + } +} +pub(crate) fn validate_merge_evidence( + evidence: Option<&GqtMergeEvidence>, + kind: StepKind, + attribution: crate::case::Attribution, +) -> Result<(), String> { + if kind != StepKind::BranchMerge || attribution == crate::case::Attribution::Off { + if evidence.is_some() { + return Err("unrequested merge phase evidence".into()); + } + return Ok(()); + } + let evidence = evidence.ok_or("missing selected merge phase snapshot")?; + let mut names = std::collections::BTreeSet::new(); + for phase in &evidence.phases { + if phase.phase.is_empty() + || phase.phase.len() > 128 + || !names.insert(&phase.phase) + || phase.max_us > phase.total_us + || (phase.interval_count == 0 && (phase.total_us != 0 || phase.max_us != 0)) + { + return Err("invalid merge phase snapshot".into()); + } + } + if evidence.phases.len() > 64 { + return Err("merge phase inventory exceeds bound".into()); + } + Ok(()) +} + +/// Durable receipts independently attest the cache preparation actually executed. +pub(crate) fn validate_receipt_treatment( + steps: &[GqtStepObservation], + selected: usize, + condition: &crate::case::CacheCondition, +) -> Result<(), String> { + use crate::case::EnginePreparation; + let selected_at = steps + .iter() + .position(|s| s.ordinal == selected) + .ok_or("missing selected receipt")?; + let mut reads = 0u32; + let mut reopened = false; + for step in &steps[..selected_at] { + if step.ordinal >= selected { + return Err("prefix receipt crosses selected ordinal".into()); + } + match step.kind { + GqtOperationKind::Query | GqtOperationKind::BranchList if !reopened => { + reads = reads + .checked_add(1) + .ok_or("prefix receipt count overflow")? + } + GqtOperationKind::Restart if reads > 0 && !reopened => reopened = true, + GqtOperationKind::Show | GqtOperationKind::Settings => {} + _ => { + return Err("receipt prefix contains an inadmissible preparation operation".into()); + } + } + } + if steps[selected_at + 1..] + .iter() + .any(|s| s.ordinal <= selected) + { + return Err("suffix receipt precedes or repeats selected ordinal".into()); + } + let engine = if reopened { + EnginePreparation::ReopenedAfterProgram + } else if reads > 0 { + EnginePreparation::WarmedByProgram + } else { + EnginePreparation::PreparationOnly + }; + if reads != condition.iterations || engine != condition.engine { + return Err("operation receipts disagree with derived cache preparation".into()); + } + Ok(()) +} diff --git a/crates/omnigraph-bench/src/gqt_supervisor.rs b/crates/omnigraph-bench/src/gqt_supervisor.rs new file mode 100644 index 000000000..ef588217d --- /dev/null +++ b/crates/omnigraph-bench/src/gqt_supervisor.rs @@ -0,0 +1,1305 @@ +//! Synchronous containment supervisor for one measured repetition worker. +//! +//! The caller runs this module from `spawn_blocking` and transfers ownership of +//! the disposable workspace into that blocking task. A canceled async caller +//! therefore cannot drop the store while a child mutation is still live. + +use std::collections::VecDeque; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use std::process::{Child, Command, ExitStatus, Stdio}; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{self, Receiver, RecvTimeoutError, SyncSender, TrySendError}; +use std::thread::JoinHandle; +use std::time::{Duration, Instant}; + +use crate::gqt_case::BoundGqt as ValidatedCase; +use crate::gqt_runner::GqtRepObservation as RepObservation; + +use crate::gqt_protocol::{ + ChildFrameV1, MAX_WORKER_FRAME_BYTES, ParentFrameV1, WORKER_PROTOCOL_VERSION, WorkerBuildV1, + WorkerRequestV1, WorkerStageV1, write_frame, +}; +use crate::machine::MachineIdentityV1; +use crate::reset::{MetadataDigest, PhysicalDigest}; +use crate::runner::{ + ChildProcessEvidence, RunnerError, RunnerResult, configure_benchmark_worker_environment, + validate_worker_build_attestation, +}; + +const AUXILIARY_DEADLINE_FLOOR: Duration = Duration::from_secs(300); +const UNDECLARED_MEASUREMENT_WATCHDOG: Duration = Duration::from_secs(3_600); +const PROTOCOL_WRITE_DEADLINE: Duration = Duration::from_secs(30); +const REAP_DEADLINE: Duration = Duration::from_secs(10); +const PROCESS_GROUP_POLL: Duration = Duration::from_millis(10); +const PIPE_POLL: Duration = Duration::from_millis(10); +const PIPE_DRAIN_DEADLINE: Duration = Duration::from_secs(2); +const PIPE_STOP_DEADLINE: Duration = Duration::from_secs(1); +const MAX_CHILD_FRAMES: usize = 8; +const STDERR_TAIL_BYTES: usize = 64 * 1024; + +#[derive(Debug, Clone)] +pub(crate) struct SupervisionInput { + pub worker_executable: PathBuf, + pub expected_worker_executable_sha256: String, + /// The first worker establishes this identity. Later workers must report + /// it exactly before the supervisor sends Begin. + pub expected_machine: Option, + pub fixture_manifest_sha256: String, + pub repetition: u32, + pub case: ValidatedCase, + pub repetition_root: PathBuf, + pub worker_scratch_root: PathBuf, + pub physical_digest: PhysicalDigest, + pub metadata_digest: MetadataDigest, + pub deadline: Option, + #[cfg(test)] + pub auxiliary_deadline_override: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct SupervisedRepetition { + pub sample: RepObservation, + pub worker_build: WorkerBuildV1, + pub machine: MachineIdentityV1, +} + +/// Supervise one fresh worker process through exactly one selected operation. +#[cfg(unix)] +pub(crate) fn supervise_repetition(input: SupervisionInput) -> RunnerResult { + if !lower_sha256(&input.fixture_manifest_sha256) { + return Err(RunnerError::new( + "fixture_stamp_invalid", + "repetition input does not carry a canonical pre-measurement fixture stamp digest", + ) + .with_repetition(input.repetition)); + } + let request = ParentFrameV1::Request { + protocol_version: WORKER_PROTOCOL_VERSION, + request: Box::new(WorkerRequestV1 { + repetition: input.repetition, + case: input.case.clone(), + expected_point_id: input.case.point_id.clone(), + expected_case_digest: input.case.plan.case_digest.clone(), + repetition_root: input.repetition_root.clone(), + worker_scratch_root: input.worker_scratch_root.clone(), + expected_physical_digest: input.physical_digest.clone(), + expected_metadata_digest: input.metadata_digest.clone(), + }), + }; + crate::gqt_protocol::write_frame(&mut std::io::sink(), &request) + .map_err(|e| RunnerError::new("worker_protocol_error", e.to_string()))?; + let measurement_watchdog = measurement_watchdog(&input); + let mut command = Command::new(&input.worker_executable); + configure_benchmark_worker_environment(&mut command, &input.worker_scratch_root); + command + .arg("__gqt-worker-v1") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + configure_child_process_group(&mut command); + let mut child = command.spawn().map_err(|error| { + RunnerError::new( + "worker_spawn_failed", + format!( + "could not spawn repetition worker {}: {error}", + input.worker_executable.display() + ), + ) + .with_repetition(input.repetition) + })?; + let process_group = i32::try_from(child.id()).map_err(|_| { + let _ = child.kill(); + let _ = child.wait(); + RunnerError::new( + "worker_pid_overflow", + "worker process identifier does not fit the process-group API", + ) + .with_repetition(input.repetition) + })?; + let (_, empty_frames) = mpsc::channel(); + let mut worker = WorkerProcess { + child, + stdin_commands: None, + stdin_stop: None, + stdin_done: None, + stdin_thread: None, + frames: empty_frames, + stdout_stop: None, + stdout_done: None, + stdout_thread: None, + stderr_stop: None, + stderr_result: None, + stderr_thread: None, + process_group, + repetition: input.repetition, + declared_deadline: input.deadline, + measurement_watchdog, + started: Instant::now(), + reaped: None, + settled_elapsed_us: None, + }; + let Some(stdin) = worker.child.stdin.take() else { + return worker.kill_error( + "pipe-setup", + "worker_pipe_failed", + "worker stdin was not piped", + ); + }; + let stdin_writer = match spawn_stdin_writer(stdin) { + Ok(writer) => writer, + Err(error) => { + return worker.kill_error( + "writer-setup", + "worker_writer_spawn_failed", + format!("could not start worker stdin writer: {error}"), + ); + } + }; + worker.stdin_commands = Some(stdin_writer.commands); + worker.stdin_stop = Some(stdin_writer.stop); + worker.stdin_done = Some(stdin_writer.done); + worker.stdin_thread = Some(stdin_writer.thread); + let Some(stdout) = worker.child.stdout.take() else { + return worker.kill_error( + "pipe-setup", + "worker_pipe_failed", + "worker stdout was not piped", + ); + }; + let Some(stderr) = worker.child.stderr.take() else { + return worker.kill_error( + "pipe-setup", + "worker_pipe_failed", + "worker stderr was not piped", + ); + }; + let frame_reader = match spawn_frame_reader(stdout) { + Ok(reader) => reader, + Err(error) => { + return worker.kill_error( + "reader-setup", + "worker_reader_spawn_failed", + format!("could not start worker stdout reader: {error}"), + ); + } + }; + worker.frames = frame_reader.frames; + worker.stdout_stop = Some(frame_reader.stop); + worker.stdout_done = Some(frame_reader.done); + worker.stdout_thread = Some(frame_reader.thread); + let (stderr_stop, stderr_result, stderr_thread) = match spawn_stderr_reader(stderr) { + Ok(reader) => reader, + Err(error) => { + return worker.kill_error( + "reader-setup", + "worker_reader_spawn_failed", + format!("could not start worker stderr reader: {error}"), + ); + } + }; + worker.stderr_stop = Some(stderr_stop); + worker.stderr_result = Some(stderr_result); + worker.stderr_thread = Some(stderr_thread); + + if let Err(error) = worker.write(&request, PROTOCOL_WRITE_DEADLINE) { + return worker.kill_error("request-write", "worker_protocol_error", error); + } + + let auxiliary_deadline = auxiliary_deadline(&input); + let ready = match worker.receive(auxiliary_deadline) { + Ok(frame) => frame, + Err(ReceiveFailure::Timeout) => { + return worker.kill_error( + "prepare-timeout", + "worker_prepare_timeout", + format!( + "repetition {} did not finish open/cache preparation within {} seconds", + input.repetition, + auxiliary_deadline.as_secs() + ), + ); + } + Err(ReceiveFailure::Protocol(message)) => { + return worker.kill_error("prepare-protocol", "worker_protocol_error", message); + } + }; + let (worker_build, machine) = match ready { + ChildFrameV1::Ready { + protocol_version, + repetition, + point_id, + case_digest, + worker_build, + machine, + physical_digest, + metadata_digest, + } if protocol_version == WORKER_PROTOCOL_VERSION + && repetition == input.repetition + && point_id == input.case.point_id + && case_digest == input.case.plan.case_digest + && physical_digest == input.physical_digest + && metadata_digest == input.metadata_digest => + { + if let Err(error) = validate_worker_build_attestation( + &worker_build, + &input.expected_worker_executable_sha256, + ) { + return worker.kill_error( + "prepare-protocol", + "worker_protocol_error", + format!("worker build attestation was invalid: {}", error.message), + ); + } + if let Err(error) = machine.validate() { + return worker.kill_error( + "prepare-protocol", + "worker_protocol_error", + format!("worker machine identity was invalid: {error}"), + ); + } + if input + .expected_machine + .as_ref() + .is_some_and(|expected| expected != machine.as_ref()) + { + return worker.kill_error( + "prepare-protocol", + "worker_machine_identity_changed", + "repetition worker machine identity differs from the first worker in this run", + ); + } + (*worker_build, *machine) + } + ChildFrameV1::Failed { + stage, + code, + message, + settled_sample, + .. + } => { + if settled_sample.is_some() + || !matches!( + stage, + WorkerStageV1::Bootstrap + | WorkerStageV1::Prepare + | WorkerStageV1::Finalize + | WorkerStageV1::Protocol + ) + { + return worker.kill_error( + "prepare-protocol", + "worker_protocol_error", + format!("worker sent an out-of-order {stage:?} failure before Ready"), + ); + } + return worker.structured_failure(stage, code, message, settled_sample); + } + frame => { + return worker.kill_error( + "prepare-protocol", + "worker_protocol_error", + format!("worker sent an invalid ready frame: {frame:?}"), + ); + } + }; + + let begin = ParentFrameV1::Begin { + protocol_version: WORKER_PROTOCOL_VERSION, + repetition: input.repetition, + }; + let measured_started = Instant::now(); + if let Err(error) = worker.write( + &begin, + remaining(measurement_watchdog, measured_started.elapsed()), + ) { + return worker.kill_error("begin-write", "worker_protocol_error", error); + } + let settled = match worker.receive(remaining(measurement_watchdog, measured_started.elapsed())) + { + Ok(frame) => frame, + Err(ReceiveFailure::Timeout) => { + let (code, message) = + measurement_timeout_failure(&input, "did not settle before the supervisor ceiling"); + return worker.kill_error("measure-timeout", code, message); + } + Err(ReceiveFailure::Protocol(message)) => { + return worker.kill_error("measure-protocol", "worker_protocol_error", message); + } + }; + let supervisor_settled_elapsed = measured_started.elapsed(); + if supervisor_settled_elapsed > measurement_watchdog { + let (code, message) = measurement_timeout_failure( + &input, + "was not observed settled before the supervisor ceiling", + ); + return worker.kill_error("measure-timeout", code, message); + } + let settled_elapsed_us = match settled { + ChildFrameV1::Settled { + protocol_version, + repetition, + elapsed_us, + } if protocol_version == WORKER_PROTOCOL_VERSION && repetition == input.repetition => { + elapsed_us + } + ChildFrameV1::Failed { + stage, + code, + message, + settled_sample, + .. + } => { + if settled_sample.is_some() + || !matches!( + stage, + WorkerStageV1::Prepare + | WorkerStageV1::Measure + | WorkerStageV1::Finalize + | WorkerStageV1::Protocol + ) + { + return worker.kill_error( + "measure-protocol", + "worker_protocol_error", + format!("worker sent an out-of-order {stage:?} failure before Settled"), + ); + } + return worker.structured_failure(stage, code, message, settled_sample); + } + frame => { + return worker.kill_error( + "measure-protocol", + "worker_protocol_error", + format!("worker sent an invalid settled frame: {frame:?}"), + ); + } + }; + worker.settled_elapsed_us = Some(settled_elapsed_us); + let supervisor_settled_elapsed_us = duration_us(supervisor_settled_elapsed); + if settled_elapsed_us > supervisor_settled_elapsed_us { + return worker.kill_error( + "measure-protocol", + "worker_protocol_error", + format!( + "worker reported elapsed_us={settled_elapsed_us}, but the parent observed only {supervisor_settled_elapsed_us}us from before Begin through Settled" + ), + ); + } + + let complete = match worker.receive(auxiliary_deadline) { + Ok(frame) => frame, + Err(ReceiveFailure::Timeout) => { + return worker.kill_error( + "verify-timeout", + "worker_verification_timeout", + format!( + "repetition {} settled but did not finish exact verification within {} seconds", + input.repetition, + auxiliary_deadline.as_secs() + ), + ); + } + Err(ReceiveFailure::Protocol(message)) => { + return worker.kill_error("verify-protocol", "worker_protocol_error", message); + } + }; + let mut sample = match complete { + ChildFrameV1::Complete { + protocol_version, + point_id, + case_digest, + sample, + } if protocol_version == WORKER_PROTOCOL_VERSION + && point_id == input.case.point_id + && case_digest == input.case.plan.case_digest => + { + *sample + } + ChildFrameV1::Failed { + stage, + code, + message, + settled_sample, + .. + } => { + if !matches!( + stage, + WorkerStageV1::Measure + | WorkerStageV1::Verify + | WorkerStageV1::Finalize + | WorkerStageV1::Protocol + ) { + return worker.kill_error( + "verify-protocol", + "worker_protocol_error", + format!("worker sent an out-of-order {stage:?} failure after Settled"), + ); + } + if let Some(sample) = settled_sample.as_deref() + && let Err(message) = crate::gqt_runner::validate_failed_sample( + sample, + &input.case, + input.repetition, + &input.physical_digest, + settled_elapsed_us, + ) + { + return worker.kill_error( + "verify-protocol", + "worker_protocol_error", + format!( + "worker failure carried invalid rejected-operation evidence: {message}" + ), + ); + } + return worker.structured_failure(stage, code, message, settled_sample); + } + frame => { + return worker.kill_error( + "verify-protocol", + "worker_protocol_error", + format!("worker sent an invalid completion frame: {frame:?}"), + ); + } + }; + if let Err(message) = validate_sample_admission(&sample, &input, settled_elapsed_us) { + return worker.kill_error("finalize-protocol", "worker_protocol_error", message); + } + + let child_exit = match worker.wait_for_exit(auxiliary_deadline) { + Ok(child_exit) => child_exit, + Err(message) => { + return worker.kill_error("exit-timeout", "worker_exit_timeout", message); + } + }; + let group_gone = match process_group_is_gone(process_group) { + Ok(gone) => gone, + Err(error) => { + return worker.kill_error( + "group-proof", + "worker_group_probe_failed", + error.to_string(), + ); + } + }; + if !child_exit.status.success() || !group_gone { + return worker.kill_error( + "finalize-exit", + "worker_exit_failed", + format!( + "worker reported completion but exited with {}; process_group_gone={group_gone}", + child_exit.status + ), + ); + } + let capture = worker.finish_capture(); + let trailing_output = worker + .frames + .try_iter() + .map(|frame| match frame { + Ok(frame) => format!("unexpected trailing frame {frame:?}"), + Err(error) => error, + }) + .collect::>(); + if !capture.threads_stopped + || !capture.stdout_clean_eof + || !capture.stderr.clean_eof + || !trailing_output.is_empty() + { + let detail = if trailing_output.is_empty() { + "worker stdio did not close cleanly".to_string() + } else { + trailing_output.join("; ") + }; + return Err(RunnerError::new( + "worker_protocol_error", + format!("worker completion was followed by invalid output: {detail}"), + ) + .with_gqt_settled_elapsed(settled_elapsed_us) + .with_repetition(input.repetition) + .with_child_process(process_evidence( + "finalize-protocol".to_string(), + input.deadline, + measurement_watchdog, + worker.started.elapsed(), + "worker-completed".to_string(), + Some(&child_exit), + group_gone, + capture, + ))); + } + + sample.peak_rss_bytes = Some(child_exit.peak_rss_bytes); + + if let Some(deadline) = input.deadline { + let deadline_us = duration_us(deadline); + if settled_elapsed_us > deadline_us { + return Err(RunnerError::new( + "operation_deadline_exceeded", + format!( + "repetition {} settled in {}us, beyond the declared {}us deadline", + input.repetition, settled_elapsed_us, deadline_us + ), + ) + .with_repetition(input.repetition) + .with_gqt_settled_sample(sample)); + } + } + Ok(SupervisedRepetition { + sample, + worker_build, + machine, + }) +} + +fn lower_sha256(value: &str) -> bool { + value.len() == 64 + && value + .bytes() + .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) +} + +#[cfg(not(unix))] +pub(crate) fn supervise_repetition(input: SupervisionInput) -> RunnerResult { + Err(RunnerError::new( + "unsupported_worker_platform", + format!( + "process-isolated repetition supervision is unavailable on this platform for repetition {}", + input.repetition + ), + )) +} + +#[cfg(unix)] +struct WorkerProcess { + child: Child, + stdin_commands: Option>, + stdin_stop: Option>, + stdin_done: Option>, + stdin_thread: Option>, + frames: Receiver>, + stdout_stop: Option>, + stdout_done: Option>>, + stdout_thread: Option>, + stderr_stop: Option>, + stderr_result: Option>, + stderr_thread: Option>, + process_group: i32, + repetition: u32, + declared_deadline: Option, + measurement_watchdog: Duration, + started: Instant, + reaped: Option, + settled_elapsed_us: Option, +} + +#[cfg(unix)] +#[derive(Debug, Clone)] +struct ReapedChild { + status: ExitStatus, + peak_rss_bytes: u64, +} + +#[cfg(unix)] +impl WorkerProcess { + fn write(&mut self, frame: &ParentFrameV1, timeout: Duration) -> Result<(), String> { + let mut encoded = Vec::new(); + write_frame(&mut encoded, frame).map_err(|error| error.to_string())?; + let commands = self + .stdin_commands + .as_ref() + .ok_or_else(|| "worker stdin is already closed".to_string())?; + let (completed, completion) = mpsc::sync_channel(1); + match commands.try_send(StdinWrite { encoded, completed }) { + Ok(()) => {} + Err(TrySendError::Full(_)) => { + return Err("worker stdin already has a pending protocol write".to_string()); + } + Err(TrySendError::Disconnected(_)) => { + return Err("worker stdin writer stopped unexpectedly".to_string()); + } + } + match completion.recv_timeout(timeout) { + Ok(result) => result, + Err(RecvTimeoutError::Timeout) => Err(format!( + "worker stdin write did not complete within {}ms", + timeout.as_millis() + )), + Err(RecvTimeoutError::Disconnected) => { + Err("worker stdin writer stopped before acknowledging the frame".to_string()) + } + } + } + + fn receive(&self, timeout: Duration) -> Result { + match self.frames.recv_timeout(timeout) { + Ok(Ok(frame)) if frame.protocol_version() == WORKER_PROTOCOL_VERSION => Ok(frame), + Ok(Ok(frame)) => Err(ReceiveFailure::Protocol(format!( + "worker sent protocol version {}, expected {}", + frame.protocol_version(), + WORKER_PROTOCOL_VERSION + ))), + Ok(Err(message)) => Err(ReceiveFailure::Protocol(message)), + Err(RecvTimeoutError::Timeout) => Err(ReceiveFailure::Timeout), + Err(RecvTimeoutError::Disconnected) => Err(ReceiveFailure::Protocol( + "worker stdout closed before the expected frame".to_string(), + )), + } + } + + fn wait_for_exit(&mut self, timeout: Duration) -> Result { + if let Some(reaped) = &self.reaped { + return Ok(reaped.clone()); + } + let started = Instant::now(); + loop { + match wait4_nonblocking(self.process_group) { + Ok(Some(reaped)) => { + self.reaped = Some(reaped.clone()); + return Ok(reaped); + } + Ok(None) if started.elapsed() < timeout => { + std::thread::sleep(PROCESS_GROUP_POLL); + } + Ok(None) => { + return Err(format!( + "worker did not exit within {} seconds after its terminal frame", + timeout.as_secs() + )); + } + Err(error) => return Err(format!("could not wait for worker: {error}")), + } + } + } + + fn structured_failure( + mut self, + stage: WorkerStageV1, + code: String, + message: String, + settled_sample: Option>, + ) -> RunnerResult { + let status = self.wait_for_exit(REAP_DEADLINE).ok(); + let group_gone = process_group_is_gone(self.process_group).unwrap_or(false); + if status.is_none() || !group_gone { + return self.kill_error( + "structured-failure-reap", + "worker_reap_failed", + format!( + "worker sent {stage:?} failure `{code}` but did not exit cleanly enough to release its store" + ), + ); + } + let capture = self.finish_capture(); + let mut error = RunnerError::new(code, message) + .with_repetition(self.repetition) + .with_child_process(process_evidence( + format!("{stage:?}"), + self.declared_deadline, + self.measurement_watchdog, + self.started.elapsed(), + "worker-failed".to_string(), + status.as_ref(), + group_gone, + capture, + )); + error.context.gqt_settled_elapsed_us = self.settled_elapsed_us; + if let Some(sample) = settled_sample { + error = error.with_gqt_settled_sample(*sample); + } + Err(error) + } + + fn kill_error( + mut self, + stage: &str, + code: &str, + message: impl Into, + ) -> RunnerResult { + let message = message.into(); + let kill_result = kill_process_group(self.process_group); + let status = self.wait_for_exit(REAP_DEADLINE).ok(); + let group_gone = + wait_for_process_group_gone(self.process_group, REAP_DEADLINE).unwrap_or(false); + let capture = if group_gone { + self.finish_capture() + } else { + CaptureOutcome::default() + }; + let termination = match kill_result { + Ok(()) => "sigkill".to_string(), + Err(error) => format!("sigkill-failed: {error}"), + }; + let mut error = RunnerError::new(code, message) + .with_repetition(self.repetition) + .with_child_process(process_evidence( + stage.to_string(), + self.declared_deadline, + self.measurement_watchdog, + self.started.elapsed(), + termination, + status.as_ref(), + group_gone, + capture, + )); + error.context.gqt_settled_elapsed_us = self.settled_elapsed_us; + Err(error) + } + + fn finish_capture(&mut self) -> CaptureOutcome { + self.stdin_commands.take(); + let stdin_stopped = finish_pipe_thread( + "stdin writer", + self.stdin_done.take(), + self.stdin_stop.take(), + self.stdin_thread.take(), + ) + .is_ok(); + let stdout_result = finish_pipe_thread( + "stdout reader", + self.stdout_done.take(), + self.stdout_stop.take(), + self.stdout_thread.take(), + ); + let stderr_result = finish_pipe_thread( + "stderr reader", + self.stderr_result.take(), + self.stderr_stop.take(), + self.stderr_thread.take(), + ); + let stdout_clean_eof = matches!(&stdout_result, Ok(Ok(()))); + let stderr_stopped = stderr_result.is_ok(); + CaptureOutcome { + stderr: stderr_result.unwrap_or_else(|error| StderrCapture { + tail: format!("[stderr capture did not stop cleanly: {error}]").into_bytes(), + truncated: false, + clean_eof: false, + }), + stdout_clean_eof, + threads_stopped: stdin_stopped && stdout_result.is_ok() && stderr_stopped, + } + } +} + +#[cfg(unix)] +impl Drop for WorkerProcess { + fn drop(&mut self) { + let child_reaped = self.reaped.is_some(); + let group_gone = process_group_is_gone(self.process_group).unwrap_or(false); + if !child_reaped || !group_gone { + let _ = kill_process_group(self.process_group); + let _ = self.wait_for_exit(REAP_DEADLINE); + let _ = wait_for_process_group_gone(self.process_group, REAP_DEADLINE); + } + let _ = self.finish_capture(); + } +} + +#[cfg(unix)] +struct StdinWrite { + encoded: Vec, + completed: SyncSender>, +} + +#[cfg(unix)] +struct StdinWriter { + commands: SyncSender, + stop: Arc, + done: Receiver<()>, + thread: JoinHandle<()>, +} + +#[cfg(unix)] +fn spawn_stdin_writer(mut stdin: std::process::ChildStdin) -> std::io::Result { + set_nonblocking(&stdin)?; + let (send, receive) = mpsc::sync_channel::(1); + let stop = Arc::new(AtomicBool::new(false)); + let thread_stop = stop.clone(); + let (done_send, done) = mpsc::sync_channel(1); + let thread = std::thread::Builder::new() + .name("omnigraph-bench-worker-stdin".to_string()) + .spawn(move || { + loop { + match receive.recv_timeout(PIPE_POLL) { + Ok(write) => { + let result = + write_nonblocking(&mut stdin, &write.encoded, thread_stop.as_ref()); + let failed = result.is_err(); + let _ = write.completed.send(result); + if failed { + break; + } + } + Err(RecvTimeoutError::Timeout) if !thread_stop.load(Ordering::Acquire) => {} + Err(RecvTimeoutError::Timeout | RecvTimeoutError::Disconnected) => break, + } + } + let _ = done_send.send(()); + })?; + Ok(StdinWriter { + commands: send, + stop, + done, + thread, + }) +} + +#[cfg(unix)] +enum ReceiveFailure { + Timeout, + Protocol(String), +} + +#[cfg(unix)] +#[derive(Debug, Default)] +struct StderrCapture { + tail: Vec, + truncated: bool, + clean_eof: bool, +} + +#[cfg(unix)] +#[derive(Debug, Default)] +struct CaptureOutcome { + stderr: StderrCapture, + stdout_clean_eof: bool, + threads_stopped: bool, +} + +#[cfg(unix)] +struct FrameReader { + frames: Receiver>, + stop: Arc, + done: Receiver>, + thread: JoinHandle<()>, +} + +#[cfg(unix)] +fn spawn_frame_reader(mut stdout: std::process::ChildStdout) -> std::io::Result { + set_nonblocking(&stdout)?; + let (send, receive) = mpsc::channel(); + let stop = Arc::new(AtomicBool::new(false)); + let thread_stop = stop.clone(); + let (done_send, done) = mpsc::sync_channel(1); + let thread = std::thread::Builder::new() + .name("omnigraph-bench-worker-stdout".to_string()) + .spawn(move || { + let result = read_frame_pipe(&mut stdout, thread_stop.as_ref(), &send); + if let Err(error) = &result { + let _ = send.send(Err(error.clone())); + } + let _ = done_send.send(result); + })?; + Ok(FrameReader { + frames: receive, + stop, + done, + thread, + }) +} + +#[cfg(unix)] +fn spawn_stderr_reader( + mut stderr: std::process::ChildStderr, +) -> std::io::Result<(Arc, Receiver, JoinHandle<()>)> { + set_nonblocking(&stderr)?; + let stop = Arc::new(AtomicBool::new(false)); + let thread_stop = stop.clone(); + let (result_send, result) = mpsc::sync_channel(1); + let thread = std::thread::Builder::new() + .name("omnigraph-bench-worker-stderr".to_string()) + .spawn(move || { + let capture = read_stderr_pipe(&mut stderr, thread_stop.as_ref()); + let _ = result_send.send(capture); + })?; + Ok((stop, result, thread)) +} + +#[cfg(unix)] +fn set_nonblocking(pipe: &T) -> std::io::Result<()> { + use nix::fcntl::{FcntlArg, OFlag, fcntl}; + + let flags = fcntl(pipe, FcntlArg::F_GETFL).map_err(std::io::Error::from)?; + let flags = OFlag::from_bits_truncate(flags) | OFlag::O_NONBLOCK; + fcntl(pipe, FcntlArg::F_SETFL(flags)) + .map(|_| ()) + .map_err(std::io::Error::from) +} + +#[cfg(unix)] +fn write_nonblocking( + writer: &mut impl Write, + encoded: &[u8], + stop: &AtomicBool, +) -> Result<(), String> { + let mut offset = 0; + while offset < encoded.len() { + if stop.load(Ordering::Acquire) { + return Err("worker stdin writer was stopped".to_string()); + } + match writer.write(&encoded[offset..]) { + Ok(0) => return Err("worker stdin closed during a protocol frame".to_string()), + Ok(written) => offset += written, + Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { + std::thread::sleep(PIPE_POLL); + } + Err(error) if error.kind() == std::io::ErrorKind::Interrupted => {} + Err(error) => return Err(error.to_string()), + } + } + writer.flush().map_err(|error| error.to_string()) +} + +#[cfg(unix)] +fn read_frame_pipe( + reader: &mut impl Read, + stop: &AtomicBool, + send: &mpsc::Sender>, +) -> Result<(), String> { + let mut pending = Vec::new(); + let mut frames = 0usize; + let mut buffer = [0_u8; 8192]; + loop { + match reader.read(&mut buffer) { + Ok(0) if pending.is_empty() => return Ok(()), + Ok(0) => { + return Err(format!( + "worker stdout ended with {} unterminated frame bytes", + pending.len() + )); + } + Ok(read) => { + pending.extend_from_slice(&buffer[..read]); + while let Some(newline) = pending.iter().position(|byte| *byte == b'\n') { + let mut framed = pending.drain(..=newline).collect::>(); + framed.pop(); + if framed.is_empty() { + return Err("worker stdout contained an empty frame".to_string()); + } + if framed.len() > MAX_WORKER_FRAME_BYTES { + return Err(format!( + "worker stdout frame has {} bytes; the limit is {MAX_WORKER_FRAME_BYTES}", + framed.len() + )); + } + frames += 1; + if frames > MAX_CHILD_FRAMES { + return Err(format!( + "worker emitted more than {MAX_CHILD_FRAMES} protocol frames" + )); + } + let frame = serde_json::from_slice::(&framed) + .map_err(|error| format!("could not decode worker frame: {error}"))?; + if send.send(Ok(frame)).is_err() { + return Ok(()); + } + } + if pending.len() > MAX_WORKER_FRAME_BYTES { + return Err(format!( + "worker stdout unterminated frame exceeds {MAX_WORKER_FRAME_BYTES} bytes" + )); + } + } + Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { + if stop.load(Ordering::Acquire) { + return Err( + "worker stdout did not reach clean EOF before capture shutdown".to_string(), + ); + } + std::thread::sleep(PIPE_POLL); + } + Err(error) if error.kind() == std::io::ErrorKind::Interrupted => {} + Err(error) => return Err(format!("worker stdout read failed: {error}")), + } + } +} + +#[cfg(unix)] +fn read_stderr_pipe(reader: &mut impl Read, stop: &AtomicBool) -> StderrCapture { + let mut retained = VecDeque::with_capacity(STDERR_TAIL_BYTES); + let mut truncated = false; + let clean_eof = loop { + let mut buffer = [0_u8; 8192]; + match reader.read(&mut buffer) { + Ok(0) => break true, + Ok(read) => retain_stderr(&mut retained, &buffer[..read], &mut truncated), + Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { + if stop.load(Ordering::Acquire) { + break false; + } + std::thread::sleep(PIPE_POLL); + } + Err(error) if error.kind() == std::io::ErrorKind::Interrupted => {} + Err(error) => { + retain_stderr( + &mut retained, + format!("\n[stderr read failed: {error}]").as_bytes(), + &mut truncated, + ); + break false; + } + } + }; + StderrCapture { + tail: retained.into_iter().collect(), + truncated, + clean_eof, + } +} + +#[cfg(unix)] +fn retain_stderr(retained: &mut VecDeque, bytes: &[u8], truncated: &mut bool) { + for byte in bytes { + if retained.len() == STDERR_TAIL_BYTES { + retained.pop_front(); + *truncated = true; + } + retained.push_back(*byte); + } +} + +#[cfg(unix)] +fn finish_pipe_thread( + name: &str, + result: Option>, + stop: Option>, + thread: Option>, +) -> Result { + let result = result.ok_or_else(|| format!("{name} result channel was not installed"))?; + let stop = stop.ok_or_else(|| format!("{name} stop flag was not installed"))?; + let thread = thread.ok_or_else(|| format!("{name} thread was not installed"))?; + let value = match result.recv_timeout(PIPE_DRAIN_DEADLINE) { + Ok(value) => value, + Err(RecvTimeoutError::Timeout) => { + stop.store(true, Ordering::Release); + result.recv_timeout(PIPE_STOP_DEADLINE).map_err(|error| { + format!("{name} did not stop after bounded drain and cancellation: {error}") + })? + } + Err(RecvTimeoutError::Disconnected) => { + return Err(format!("{name} stopped without a completion result")); + } + }; + thread + .join() + .map_err(|_| format!("{name} panicked after reporting completion"))?; + Ok(value) +} + +#[cfg(unix)] +fn process_evidence( + stage: String, + declared_deadline: Option, + measurement_watchdog: Duration, + elapsed: Duration, + termination: String, + child_exit: Option<&ReapedChild>, + process_group_gone: bool, + capture: CaptureOutcome, +) -> ChildProcessEvidence { + use std::os::unix::process::ExitStatusExt; + + ChildProcessEvidence { + stage, + declared_deadline_us: declared_deadline.map(duration_us), + measurement_watchdog_us: duration_us(measurement_watchdog), + supervisor_elapsed_us: duration_us(elapsed), + termination, + exit_code: child_exit.and_then(|exit| exit.status.code()), + signal: child_exit.and_then(|exit| exit.status.signal()), + peak_rss_bytes: child_exit.map(|exit| exit.peak_rss_bytes), + direct_child_reaped: child_exit.is_some(), + process_group_gone, + stdio_closed_cleanly: capture.threads_stopped + && capture.stdout_clean_eof + && capture.stderr.clean_eof, + stderr_tail: String::from_utf8_lossy(&capture.stderr.tail).into_owned(), + stderr_truncated: capture.stderr.truncated, + quarantined_workspace: None, + } +} + +#[cfg(unix)] +fn wait4_nonblocking(pid: i32) -> Result, String> { + use std::os::unix::process::ExitStatusExt; + + let mut status = 0; + let mut usage = std::mem::MaybeUninit::::zeroed(); + loop { + let reaped = + unsafe { nix::libc::wait4(pid, &mut status, nix::libc::WNOHANG, usage.as_mut_ptr()) }; + if reaped == 0 { + return Ok(None); + } + if reaped == pid { + let usage = unsafe { usage.assume_init() }; + return Ok(Some(ReapedChild { + status: ExitStatus::from_raw(status), + peak_rss_bytes: normalized_peak_rss_bytes(&usage), + })); + } + if reaped == -1 { + let error = std::io::Error::last_os_error(); + if error.raw_os_error() == Some(nix::libc::EINTR) { + continue; + } + return Err(error.to_string()); + } + return Err(format!( + "wait4 reaped unexpected process {reaped}; expected {pid}" + )); + } +} + +#[cfg(unix)] +fn normalized_peak_rss_bytes(usage: &nix::libc::rusage) -> u64 { + let peak = u64::try_from(usage.ru_maxrss).unwrap_or(0); + #[cfg(target_os = "macos")] + return peak; + #[cfg(not(target_os = "macos"))] + return peak.saturating_mul(1024); +} + +#[cfg(unix)] +fn configure_child_process_group(command: &mut Command) { + use std::os::unix::process::CommandExt; + + command.process_group(0); +} + +#[cfg(unix)] +fn kill_process_group(process_group: i32) -> Result<(), String> { + use nix::errno::Errno; + use nix::sys::signal::{Signal, kill}; + use nix::unistd::Pid; + + match kill(Pid::from_raw(-process_group), Signal::SIGKILL) { + Ok(()) | Err(Errno::ESRCH) => Ok(()), + Err(error) => Err(error.to_string()), + } +} + +#[cfg(unix)] +fn process_group_is_gone(process_group: i32) -> Result { + use nix::errno::Errno; + use nix::sys::signal::kill; + use nix::unistd::Pid; + + match kill(Pid::from_raw(-process_group), None) { + Ok(()) => Ok(false), + Err(Errno::ESRCH) => Ok(true), + Err(error) => Err(error.to_string()), + } +} + +#[cfg(unix)] +fn wait_for_process_group_gone(process_group: i32, timeout: Duration) -> Result { + let started = Instant::now(); + loop { + if process_group_is_gone(process_group)? { + return Ok(true); + } + if started.elapsed() >= timeout { + return Ok(false); + } + std::thread::sleep(PROCESS_GROUP_POLL); + } +} + +#[cfg(unix)] +fn validate_sample_admission( + sample: &RepObservation, + input: &SupervisionInput, + settled_elapsed_us: u64, +) -> Result<(), String> { + crate::gqt_runner::validate_sample( + sample, + &input.case, + input.repetition, + &input.physical_digest, + settled_elapsed_us, + false, + ) + .map_err(|error| error.to_string()) +} + +fn duration_us(duration: Duration) -> u64 { + u64::try_from(duration.as_micros()).unwrap_or(u64::MAX) +} + +fn auxiliary_deadline(input: &SupervisionInput) -> Duration { + #[cfg(test)] + if let Some(override_deadline) = input.auxiliary_deadline_override { + return override_deadline; + } + measurement_watchdog(input).max(AUXILIARY_DEADLINE_FLOOR) +} + +fn measurement_watchdog(input: &SupervisionInput) -> Duration { + input.deadline.unwrap_or(UNDECLARED_MEASUREMENT_WATCHDOG) +} + +fn measurement_timeout_failure(input: &SupervisionInput, action: &str) -> (&'static str, String) { + match input.deadline { + Some(deadline) => ( + "operation_deadline_exceeded", + format!( + "repetition {} {action} within the declared {} second deadline; the worker process group was killed and reaped", + input.repetition, + deadline.as_secs() + ), + ), + None => ( + "worker_measurement_watchdog_exceeded", + format!( + "repetition {} {action} within the independent {} second safety watchdog for an operation with no declared deadline; the worker process group was killed and reaped", + input.repetition, + UNDECLARED_MEASUREMENT_WATCHDOG.as_secs() + ), + ), + } +} + +fn remaining(total: Duration, elapsed: Duration) -> Duration { + total.saturating_sub(elapsed) +} + +/// Bound the complete request before admitting a dataset build, using fixed-width +/// digest placeholders and maximum-width counters for the not-yet-built tree. +pub(crate) fn preflight_plan(plan: &crate::gqt_case::PlannedGqt, cache: &Path) -> RunnerResult<()> { + let case = plan + .bind( + &"0".repeat(64), + crate::dataset_identity::REGISTERED_LOGICAL_ALGORITHM, + ) + .map_err(|e| RunnerError::new("worker_protocol_error", e))?; + let entry = cache.join("0".repeat(64)); + let request = ParentFrameV1::Request { + protocol_version: WORKER_PROTOCOL_VERSION, + request: Box::new(WorkerRequestV1 { + repetition: 10_000, + expected_point_id: case.point_id.clone(), + expected_case_digest: case.plan.case_digest.clone(), + case, + repetition_root: entry.join("active"), + worker_scratch_root: entry.join("worker-scratch-00010000"), + expected_physical_digest: PhysicalDigest { + files: u64::MAX, + bytes: u64::MAX, + digest_sha256: "0".repeat(64), + }, + expected_metadata_digest: MetadataDigest { + entries: u64::MAX, + files: u64::MAX, + directories: u64::MAX, + bytes: u64::MAX, + shape_sha256: "0".repeat(64), + state_sha256: "0".repeat(64), + }, + }), + }; + crate::gqt_protocol::write_frame(&mut std::io::sink(), &request) + .map_err(|e| RunnerError::new("worker_protocol_error", e.to_string())) +} diff --git a/crates/omnigraph-bench/src/gqt_tests.rs b/crates/omnigraph-bench/src/gqt_tests.rs new file mode 100644 index 000000000..7a5d906a8 --- /dev/null +++ b/crates/omnigraph-bench/src/gqt_tests.rs @@ -0,0 +1,1022 @@ +//! The public catalog and the measured adapter share these owning-layer tests. +use crate::gqt_case::*; +use crate::gqt_runner::{execute_gqt_rep_signaled, validate_sample}; +use crate::runner::{MeasurementSignals, RunnerResult}; +use omnigraph_gqt_core::StepKind; +use std::path::{Path, PathBuf}; + +const END_TO_END: [(&str, StepKind); 14] = [ + ("e2e-merge-all-changed", StepKind::BranchMerge), + ("e2e-merge-all-new", StepKind::BranchMerge), + ("e2e-merge-diverged-updates", StepKind::BranchMerge), + ("e2e-mixed-load", StepKind::Load), + ("e2e-branch-create", StepKind::BranchCreate), + ("e2e-branch-create-from", StepKind::BranchCreate), + ("e2e-branch-list", StepKind::BranchList), + ("e2e-branch-delete", StepKind::BranchDelete), + ("e2e-branch-adopt-untouched", StepKind::BranchMerge), + ("e2e-branch-adopt-written", StepKind::BranchMerge), + ("e2e-branch-first-write", StepKind::Mutate), + ("e2e-nearest-prefilter", StepKind::Query), + ("e2e-nearest-nprobes-one", StepKind::Query), + ("e2e-rrf-traversal", StepKind::Query), +]; +const QUERY_SHAPES: [&str; 14] = [ + "e2e-query-scan", + "e2e-query-wide-scan", + "e2e-query-filter", + "e2e-query-lookup", + "e2e-query-count", + "e2e-query-grouped", + "e2e-query-top-people", + "e2e-query-friends", + "e2e-query-filtered-friends", + "e2e-query-no-friends", + "e2e-query-count-bare", + "e2e-query-destination-projection", + "e2e-query-grouped-fanout", + "e2e-query-destination-search", +]; +const TRAVERSAL_SHAPES: [(&str, bool); 5] = [ + ("e2e-traversal-hop1", true), + ("e2e-traversal-hop2", true), + ("e2e-traversal-hop3", true), + ("e2e-traversal-selective-csr", false), + ("e2e-traversal-selective-indexed", false), +]; + +fn query_shape_cases() -> impl Iterator { + QUERY_SHAPES + .into_iter() + .map(|id| (id, true)) + .chain(TRAVERSAL_SHAPES) +} + +fn catalog() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../benchmarks") +} +fn plan(name: &str) -> PlannedGqt { + crate::catalog::Catalog::load(&catalog().join("benchmarks.yaml")) + .unwrap() + .plan(name) + .unwrap() +} +#[derive(Debug, Default)] +struct Signals { + events: Vec<&'static str>, + elapsed: Option, +} +impl MeasurementSignals for Signals { + fn ready(&mut self) -> RunnerResult<()> { + self.events.push("ready"); + Ok(()) + } + fn settled(&mut self, elapsed: u64) -> RunnerResult<()> { + self.events.push("settled"); + self.elapsed = Some(elapsed); + Ok(()) + } +} +async fn run_sample( + plan: &PlannedGqt, +) -> Result<(crate::gqt_runner::GqtRepObservation, Signals), crate::runner::RunnerError> { + run_sample_with_logical(plan) + .await + .map(|(sample, signals, _)| (sample, signals)) +} +async fn run_sample_with_logical( + plan: &PlannedGqt, +) -> Result< + ( + crate::gqt_runner::GqtRepObservation, + Signals, + crate::dataset_identity::DatasetLogicalV1, + ), + crate::runner::RunnerError, +> { + let directory = tempfile::tempdir().unwrap(); + let root = directory.path().join("active"); + let scratch = directory.path().join("scratch"); + std::fs::create_dir(&scratch).unwrap(); + let (logical, _) = crate::dataset_worker::build_dataset( + &plan.dataset_build_plan(), + root.to_str().unwrap(), + &scratch, + None, + ) + .await + .unwrap(); + let physical = + crate::reset::digest_physical_tree(&root, crate::reset::TraversalLimits::default()) + .unwrap(); + let metadata = + crate::reset::digest_metadata_tree(&root, crate::reset::TraversalLimits::default()) + .unwrap(); + let bound = plan + .bind(&logical.logical_content_sha256, &logical.algorithm) + .unwrap(); + let mut signals = Signals::default(); + let sample = + execute_gqt_rep_signaled(1, &root, &physical, &metadata, &bound, &mut signals).await?; + validate_sample(&sample, &bound, 1, &physical, sample.elapsed_us, false).unwrap(); + assert_eq!(signals.events, vec!["ready", "settled"]); + assert_eq!(signals.elapsed, Some(sample.elapsed_us)); + Ok((sample, signals, logical)) +} +#[test] +fn original_pairs_and_groups_preserve_pre_migration_identity() { + let catalog = crate::catalog::Catalog::load(&catalog().join("benchmarks.yaml")).unwrap(); + let baseline: serde_json::Value = + serde_json::from_str(include_str!("../tests/fixtures/gqt-catalog-identity.json")).unwrap(); + let baseline = baseline.as_object().unwrap(); + assert_eq!(baseline.len(), 40); + for (id, old) in baseline { + let scenario = catalog + .definition + .scenarios + .iter() + .find(|scenario| scenario.id == *id) + .unwrap_or_else(|| panic!("original scenario {id} is missing")); + let plan = catalog.plan(&scenario.id).unwrap(); + plan.revalidate().unwrap(); + assert_eq!( + old["planned_sha256"], plan.planned_sha256, + "{}", + scenario.id + ); + assert_eq!(old["recipe_sha256"], plan.recipe_sha256); + assert_eq!(old["workload_sha256"], plan.queries.sha256); + assert_eq!(old["needs_indices"], plan.needs_indices); + let bound = plan + .bind( + &"a".repeat(64), + crate::dataset_identity::DATASET_LOGICAL_ALGORITHM, + ) + .unwrap(); + assert_eq!(old["bound_point_id"], bound.point_id); + assert_eq!( + old["measured_step"], + serde_json::to_value(&plan.definition.workload.measured_step).unwrap() + ); + assert_eq!( + old["environment"], + serde_json::to_value(&plan.definition.environment).unwrap() + ); + assert_eq!( + old["protocol"], + serde_json::to_value(&plan.definition.protocol).unwrap() + ); + assert_eq!( + old["cache_condition"], + serde_json::to_value(&plan.cache_condition).unwrap() + ); + assert_eq!( + old["repetitions"], + scenario.expand(&catalog.definition.defaults).1 + ); + } + let groups: std::collections::BTreeMap> = + serde_json::from_str(include_str!("../tests/fixtures/gqt-catalog-groups.json")).unwrap(); + assert_eq!(groups.len(), 8); + let selection = |name: Option<&str>| { + catalog + .resolve(name, None) + .unwrap() + .runs + .into_iter() + .map(|run| (run.case.id().to_owned(), run.repetitions)) + .collect::>() + }; + for (group, expected) in &groups { + assert_eq!(selection(Some(group)), *expected, "group {group}"); + } + assert_eq!(selection(None), groups["local-fast"]); + assert_eq!( + selection(Some("search")), + vec![ + ("nearest-ranks-updated-embedding".into(), 1), + ("nearest-skips-deleted-rows-and-fills-limit".into(), 1), + ] + ); +} + +#[test] +fn end_to_end_catalog_selects_complete_public_operations() { + use crate::case::{EnginePreparation, PageCacheCondition, ProcessLifecycle}; + + let catalog = crate::catalog::Catalog::load(&catalog().join("benchmarks.yaml")).unwrap(); + let selected = catalog.resolve(Some("end-to-end"), None).unwrap(); + assert_eq!( + selected + .runs + .iter() + .map(|run| (run.case.id(), run.repetitions)) + .collect::>(), + END_TO_END + .iter() + .map(|(id, _)| (*id, 1)) + .collect::>() + ); + for (name, kind) in END_TO_END { + let p = catalog.plan(name).unwrap(); + p.revalidate().unwrap(); + p.dataset_build_plan().revalidate().unwrap(); + crate::gqt_runner::preflight_acquisition_budget(&p, 1).unwrap(); + let parsed = p.queries.parse().unwrap(); + let steps = workload_steps(&parsed).unwrap(); + let measured = &p.definition.workload.measured_step; + assert_eq!(measured.ordinal, 1, "{name}"); + assert_eq!(steps[0].kind, kind, "{name}"); + assert_eq!(steps[0].source.trim(), measured.text.trim(), "{name}"); + let restart = steps + .iter() + .position(|step| step.kind == StepKind::Restart) + .unwrap_or_else(|| panic!("{name}: fresh-handle verification is missing")); + assert!( + steps[restart + 1..] + .iter() + .any(|step| step.kind == StepKind::Query), + "{name}: reopen must be followed by an explicit row check" + ); + assert_eq!( + p.cache_condition.process, + ProcessLifecycle::FreshPerRepetition + ); + assert_eq!(p.cache_condition.engine, EnginePreparation::PreparationOnly); + assert_eq!( + p.cache_condition.page_cache, + PageCacheCondition::Uncontrolled + ); + assert_eq!(p.cache_condition.iterations, 0); + } +} + +#[tokio::test] +async fn end_to_end_catalog_executes_exact_rows_and_fresh_handle_isolation() { + for (name, kind) in END_TO_END { + let p = plan(name); + let (sample, _) = run_sample(&p) + .await + .unwrap_or_else(|error| panic!("{name}: {error}")); + assert_eq!(sample.outcome, "expectations-passed", "{name}"); + assert!(sample.verification.selected_assertion_passed, "{name}"); + assert!(sample.verification.following_assertions > 0, "{name}"); + assert_eq!( + sample.steps.iter().filter(|step| step.ordinal == 1).count(), + 1, + "{name}: one complete public operation is measured" + ); + assert_eq!( + sample.merge.is_some(), + kind == StepKind::BranchMerge, + "{name}" + ); + } +} + +#[test] +fn query_shape_catalog_selects_complete_queries_with_bounded_plans() { + use crate::case::{EnginePreparation, PageCacheCondition, ProcessLifecycle}; + + let catalog = crate::catalog::Catalog::load(&catalog().join("benchmarks.yaml")).unwrap(); + for (group, expected) in [ + ("query-shapes", QUERY_SHAPES.to_vec()), + ( + "traversal", + TRAVERSAL_SHAPES.iter().map(|(id, _)| *id).collect(), + ), + ] { + let selected = catalog.resolve(Some(group), None).unwrap(); + assert_eq!( + selected + .runs + .iter() + .map(|run| (run.case.id(), run.repetitions)) + .collect::>(), + expected.into_iter().map(|id| (id, 1)).collect::>(), + "{group}" + ); + } + for (name, warm) in query_shape_cases() { + let p = catalog.plan(name).unwrap(); + p.revalidate().unwrap(); + p.dataset_build_plan().revalidate().unwrap(); + crate::gqt_runner::preflight_acquisition_budget(&p, 1).unwrap(); + let parsed = p.queries.parse().unwrap(); + let steps = workload_steps(&parsed).unwrap(); + let measured = &p.definition.workload.measured_step; + let selected_index = usize::from(warm); + assert_eq!(measured.ordinal, selected_index + 1, "{name}"); + assert_eq!(steps.len(), selected_index + 3, "{name}"); + assert_eq!(steps[selected_index].kind, StepKind::Query, "{name}"); + assert_eq!( + steps[selected_index].source.trim(), + measured.text.trim(), + "{name}" + ); + if warm { + assert_eq!(steps[0].kind, StepKind::Query, "{name}"); + assert_eq!(steps[0].source.trim(), measured.text.trim(), "{name}"); + } + assert_eq!( + steps[selected_index + 1].kind, + StepKind::Restart, + "{name}: verification must reopen the fixture" + ); + assert_eq!(steps[selected_index + 2].kind, StepKind::Query, "{name}"); + assert_eq!( + steps[selected_index + 2].source.trim(), + measured.text.trim(), + "{name}: the reopened handle must return the same complete result" + ); + assert_eq!( + p.cache_condition.process, + ProcessLifecycle::FreshPerRepetition + ); + assert_eq!( + p.cache_condition.engine, + if warm { + EnginePreparation::WarmedByProgram + } else { + EnginePreparation::PreparationOnly + }, + "{name}" + ); + assert_eq!( + p.cache_condition.page_cache, + if warm { + PageCacheCondition::ProgramConditioned + } else { + PageCacheCondition::Uncontrolled + }, + "{name}" + ); + assert_eq!(p.cache_condition.iterations, u32::from(warm), "{name}"); + if !warm { + assert!( + p.needs_indices, + "{name}: pinned traversal needs prepared indexes" + ); + } + } +} + +#[tokio::test] +async fn query_shape_catalog_executes_exact_rows_and_fresh_handle_isolation() { + for (name, _) in query_shape_cases() { + let p = plan(name); + let (sample, _) = run_sample(&p) + .await + .unwrap_or_else(|error| panic!("{name}: {error}")); + assert_eq!(sample.outcome, "expectations-passed", "{name}"); + assert!(sample.verification.selected_assertion_passed, "{name}"); + assert!(sample.verification.following_assertions > 0, "{name}"); + assert_eq!( + sample + .steps + .iter() + .filter(|step| step.ordinal == p.definition.workload.measured_step.ordinal) + .count(), + 1, + "{name}: one complete query is measured" + ); + assert!(sample.merge.is_none(), "{name}"); + } +} + +#[test] +fn content_identity_excludes_authored_locations_and_selectors() { + let p = plan("tiny-read"); + let mut moved = p.clone(); + moved.definition.id = "renamed-case".into(); + moved.definition.workload.queries = "elsewhere/query.gqt".into(); + moved.definition.fixture = GqtFixture::Dataset { + path: "elsewhere/dataset.gqt".into(), + }; + if let DatasetRecipe::Gqt { source } = &mut moved.dataset { + source.stem = "renamed_dataset".into() + } + moved.queries.stem = "renamed_queries".into(); + moved.case_digest = crate::model::typed_sha256(&moved.definition).unwrap(); + moved.revalidate().unwrap(); + assert_eq!( + p.bind( + &"a".repeat(64), + crate::dataset_identity::DATASET_LOGICAL_ALGORITHM + ) + .unwrap() + .point_id, + moved + .bind( + &"a".repeat(64), + crate::dataset_identity::DATASET_LOGICAL_ALGORITHM + ) + .unwrap() + .point_id + ); + assert_ne!( + p.bind( + &"a".repeat(64), + crate::dataset_identity::DATASET_LOGICAL_ALGORITHM + ) + .unwrap() + .point_id, + p.bind( + &"b".repeat(64), + crate::dataset_identity::DATASET_LOGICAL_ALGORITHM + ) + .unwrap() + .point_id + ); +} +#[test] +fn selected_echo_loop_write_prefix_and_implicit_suffix_refuse() { + let p = plan("tiny-read"); + let c = p.queries.parse().unwrap(); + let mut changed = p.definition.workload.measured_step.clone(); + changed.text.push_str(" changed"); + assert!(admit_queries(&c, &changed).is_err()); + let header = p.queries.text.split("--- query").next().unwrap(); + let implicit = format!( + "{header}{}\n--- expect unordered\n{{\"key\":\"a\",\"val\":1}}\n{{\"key\":\"b\",\"val\":2}}\n--- expect shape\nkey: String\nval: I64\n\n--- restart\n", + p.definition.workload.measured_step.text + ); + let c = omnigraph_gqt_core::parse_case("implicit_suffix", &implicit).unwrap(); + assert!(admit_queries(&c, &p.definition.workload.measured_step).is_err()); + let first = p.queries.text.find("--- query").unwrap(); + let second = p.queries.text[first + 3..].find("--- query").unwrap() + first + 3; + let looped = format!( + "{}--- loop $i 0 2\n{}--- endloop\n{}", + &p.queries.text[..first], + &p.queries.text[first..second], + &p.queries.text[second..] + ); + let c = omnigraph_gqt_core::parse_case("selected_loop", &looped).unwrap(); + assert!(admit_queries(&c, &p.definition.workload.measured_step).is_err()); + let mut written = p.queries.text.clone(); + written.insert_str( + first, + "--- mutate\nbranch create \"child\" from main\n--- expect ok\n", + ); + let c = omnigraph_gqt_core::parse_case("write_prefix", &written).unwrap(); + let mut selection = p.definition.workload.measured_step.clone(); + selection.ordinal = 2; + assert!(admit_queries(&c, &selection).is_err()); + let dst = p.queries.text.replace( + "target: omnigraph-engine", + "target: omnigraph-engine-dst\n seeds: [1]", + ); + let c = omnigraph_gqt_core::parse_case("dst_only", &dst).unwrap(); + assert!(admit_queries(&c, &p.definition.workload.measured_step).is_err()); +} +#[tokio::test] +async fn selected_read_restart_mutation_branch_and_single_load_use_engine_receipts() { + for name in [ + "tiny-read", + "tiny-restart", + "tiny-post-reopen", + "tiny-mutate", + "tiny-branch", + "tiny-load", + ] { + let p = plan(name); + let (sample, _) = run_sample(&p) + .await + .unwrap_or_else(|e| panic!("{name}: {e}")); + assert_eq!( + sample + .steps + .iter() + .filter(|s| s.ordinal == p.definition.workload.measured_step.ordinal) + .count(), + 1 + ); + assert!(sample.verification.following_assertions > 0); + assert!(sample.merge.is_none()); + } +} +#[tokio::test] +async fn bounded_scenario_catalog_executes_exact_postconditions_and_retained_history() { + let mut equal_current = Vec::new(); + for name in [ + "very-long-history-32-read", + "very-long-history-32-write", + "very-long-history-32-reopen", + "hot-table-idle-base", + "hot-table-idle-tables-4", + "hot-table-idle-branches-4", + "hot-table-idle-branches-4-aged", + "parallel-tables-1", + "parallel-tables-2", + "parallel-tables-4", + "identity-lifecycle", + "repeated-deletion-recreation-rows", + "repeated-deletion-recreation-branches", + "threshold-crossings-before", + "threshold-crossings-at", + "threshold-crossings-after", + "threshold-crossings-production-control", + "equal-current-narrow-one-batch", + "equal-current-wide-one-batch", + "equal-current-wide-four-batches", + ] { + let p = plan(name); + let (sample, _, logical) = run_sample_with_logical(&p) + .await + .unwrap_or_else(|e| panic!("{name}: {e}")); + assert!(sample.verification.following_assertions > 0, "{name}"); + let main = logical.branches.iter().find(|b| b.name == "main").unwrap(); + if name.starts_with("very-long-history-32-") { + assert_eq!(main.history_commits, 34, "{name}"); + } + if name.starts_with("equal-current-") { + equal_current.push((name, main.clone())); + } + } + assert_eq!(equal_current.len(), 3); + let narrow = &equal_current[0].1; + let wide = &equal_current[1].1; + let batched = &equal_current[2].1; + assert_eq!(narrow.content_sha256, wide.content_sha256); + assert_eq!(narrow.content_sha256, batched.content_sha256); + assert_eq!(narrow.schema_sha256, batched.schema_sha256); + assert_eq!(narrow.history_commits, 18); + assert_eq!(wide.history_commits, 18); + assert_eq!(batched.history_commits, 66); + assert_ne!(narrow.lineage_sha256, batched.lineage_sha256); +} +#[tokio::test] +async fn dataset_seed_indices_precede_updates_and_deletes() { + for name in [ + "nearest-ranks-updated-embedding", + "nearest-skips-deleted-rows-and-fills-limit", + ] { + let p = plan(name); + assert!(p.needs_indices); + assert!(!match &p.dataset { + DatasetRecipe::Gqt { source } => source.parse().unwrap().needs_indices, + _ => unreachable!(), + }); + run_sample(&p) + .await + .unwrap_or_else(|e| panic!("{name}: {e}")); + } +} +#[tokio::test] +async fn post_settled_assertion_failure_retains_rejected_evidence() { + let mut p = plan("tiny-mutate"); + p.queries.text = p.queries.text.replace("\"val\":3", "\"val\":999"); + p.queries.sha256 = sha256_bytes(p.queries.text.as_bytes()); + p.planned_sha256 = p.planned_hash().unwrap(); + let e = run_sample(&p).await.unwrap_err(); + assert_eq!(e.code, "gqt_verification_failed"); + let sample = e.context.gqt_settled_sample.unwrap(); + assert_eq!(sample.outcome, "verification-failed"); + assert!(sample.verification.selected_assertion_passed); + assert_eq!(sample.steps.iter().filter(|s| s.ordinal == 1).count(), 1); +} +#[tokio::test] +async fn empty_seed_and_unwritten_child_have_reproducible_dataset_identity() { + let directory = tempfile::tempdir().unwrap(); + let source = directory.path().join("empty_dataset.gqt"); + std::fs::write(&source,"# issue: none\n# notes: Empty data with a lazy branch.\n--- runner\ntimeout_ms: 10000\nenvironments:\n - target: omnigraph-engine\n storage: local-filesystem\n--- schema\nnode Item { key: String @key val: I64 }\n--- seed\n--- mutate\nbranch create \"child\" from main\n--- expect ok\n").unwrap(); + let p = override_sources(plan("tiny-read"), Some(&source), None).unwrap(); + let mut identities = Vec::new(); + for index in 0..2 { + let active = directory.path().join(format!("active{index}")); + let scratch = directory.path().join(format!("scratch{index}")); + std::fs::create_dir(&scratch).unwrap(); + let (logical, _) = crate::dataset_worker::build_dataset( + &p.dataset_build_plan(), + active.to_str().unwrap(), + &scratch, + None, + ) + .await + .unwrap(); + crate::dataset_identity::validate(&logical, None).unwrap(); + assert_eq!(logical.branches.len(), 2); + assert!(logical.branches.iter().all(|b| b.node_tables[0].rows == 0)); + identities.push(logical.logical_content_sha256) + } + assert_eq!(identities[0], identities[1]); +} +#[test] +fn request_budget_and_projection_budget_are_admitted_before_io() { + let mut p = plan("tiny-read"); + p.definition.workload.measured_step.text = "x".repeat(16 * 1024 + 1); + assert!(validate_definition(&p.definition).is_err()); + let p = plan("tiny-read"); + let b = p + .bind( + &"a".repeat(64), + crate::dataset_identity::DATASET_LOGICAL_ALGORITHM, + ) + .unwrap(); + assert!(serde_json::to_vec(&b).unwrap().len() < 512 * 1024); +} + +async fn authority_fixture() -> crate::gqt_record::GqtRunRecordV1 { + use crate::gqt_record::{GqtMeasurementsV1, GqtRunIdentityV1, GqtRunRecordV1}; + use crate::record::{ + AcquisitionStatusV1, AcquisitionV1, EvidenceStrengthV1, WallClockSummaryV1, + }; + let plan = plan("tiny-read"); + let directory = tempfile::tempdir().unwrap(); + let active = directory.path().join("active"); + let scratch = directory.path().join("scratch"); + std::fs::create_dir(&scratch).unwrap(); + let (summary, registered_source_identity) = crate::dataset_worker::build_dataset( + &plan.dataset_build_plan(), + active.to_str().unwrap(), + &scratch, + None, + ) + .await + .unwrap(); + let physical = + crate::reset::digest_physical_tree(&active, crate::reset::TraversalLimits::default()) + .unwrap(); + let template_metadata = + crate::reset::digest_metadata_tree(&active, crate::reset::TraversalLimits::default()) + .unwrap(); + let bound = plan + .bind(&summary.logical_content_sha256, &summary.algorithm) + .unwrap(); + let mut sample = execute_gqt_rep_signaled( + 1, + &active, + &physical, + &template_metadata, + &bound, + &mut Signals::default(), + ) + .await + .unwrap(); + sample.peak_rss_bytes = Some(1024); + let legacy = crate::record::tests::valid_record_fixture(); + let mut invocation = legacy.invocation; + invocation.invocation_id.replace_range(25..26, "C"); + let elapsed = sample.elapsed_us; + let record = GqtRunRecordV1 { + format_version: 1, + invocation, + run: GqtRunIdentityV1 { + point_identity_version: 1, + point_id: bound.point_id, + point_name: bound.point_name, + case_id: plan.definition.id.clone(), + case_digest: plan.case_digest.clone(), + run_spec: bound.identity, + }, + sut: legacy.sut, + machine: legacy.machine, + backend: legacy.backend, + fixture: crate::dataset_cache::DatasetManifestV1 { + format_version: 1, + key: "a".repeat(64), + recipe_sha256: plan.recipe_sha256, + engine_digest: crate::dataset_cache::GQT_ENGINE_DIGEST.into(), + needs_indices: plan.needs_indices, + reset: plan.definition.protocol.reset, + handoff: crate::dataset_worker::FixtureBuildHandoff { + summary, + registered_source_identity, + physical, + template_metadata, + }, + }, + dataset_cache_hit: true, + acquisition: AcquisitionV1 { + status: AcquisitionStatusV1::Complete, + requested_repetitions: 1, + observed_repetitions: 1, + terminal: None, + }, + measurements: GqtMeasurementsV1 { + wall_clock: WallClockSummaryV1 { + min_us: elapsed, + p50_us: elapsed, + max_us: elapsed, + p95_us: None, + p95_supported: false, + evidence: EvidenceStrengthV1::Directional, + }, + raw_samples: vec![sample], + layer_presence: legacy.measurements.layer_presence, + claim_policy: legacy.measurements.claim_policy, + }, + }; + crate::gqt_record::validate(&record).unwrap(); + record +} +fn rehash_record(record: &mut crate::gqt_record::GqtRunRecordV1) { + record.run.point_id = crate::model::typed_sha256(&record.run.run_spec).unwrap(); + record.run.point_name = format!( + "gqt-{}-{}", + record.run.run_spec.cache_condition.display_label(), + &record.run.point_id[..12] + ); +} +#[tokio::test] +async fn gqt_authority_refuses_invalid_machine_counters_dataset_and_treatment() { + let record = authority_fixture().await; + let mutations: &[fn(&mut crate::gqt_record::GqtRunRecordV1)] = &[ + |r| r.machine.logical_cores = 0, + |r| { + r.measurements.raw_samples[0] + .logical_store_calls + .manifest + .get = u64::MAX; + r.measurements.raw_samples[0].logical_store_calls.table.get = 1; + }, + |r| { + r.measurements.raw_samples[0].control_store_calls.write_text = 1; + r.measurements.raw_samples[0] + .control_store_calls + .mutation_calls = 0; + }, + |r| r.fixture.handoff.summary.branches.clear(), + |r| r.fixture.handoff.summary.algorithm = "unknown".into(), + |r| r.fixture.handoff.template_metadata.files += 1, + |r| r.run.run_spec.protocol.deadline_seconds = Some(0), + |r| { + r.run.run_spec.measured_step.text = + r.run + .run_spec + .measured_step + .text + .replacen("--- query", "--- queryjunk", 1) + }, + |r| r.run.run_spec.measured_step.text = "--- load invalid\ninvalid: recipe".into(), + |r| r.run.run_spec.cache_condition.iterations = 1, + |r| { + r.measurements.raw_samples[0].steps[0].kind = + crate::gqt_runner::GqtOperationKind::Mutate + }, + |r| r.measurements.raw_samples[0].outcome = "verification-failed".into(), + ]; + for mutate in mutations { + let mut changed = record.clone(); + mutate(&mut changed); + rehash_record(&mut changed); + assert!(crate::gqt_record::validate(&changed).is_err()); + } + let mut censored = record.clone(); + censored.acquisition.requested_repetitions = 2; + censored.acquisition.status = crate::record::AcquisitionStatusV1::Censored; + censored.acquisition.terminal = Some(crate::record::AcquisitionTerminalV1 { + failed_repetition: 1, + stage: crate::record::AcquisitionTerminalStageV1::Runner, + code: "gqt_verification_failed".into(), + }); + crate::gqt_record::validate(&censored).unwrap(); + assert!(!censored.claim_eligible()); + censored + .acquisition + .terminal + .as_mut() + .unwrap() + .failed_repetition = 2; + assert!(crate::gqt_record::validate(&censored).is_err()); +} +#[tokio::test] +async fn mixed_legacy_and_gqt_archive_rebuilds_and_queries_both_points() { + let directory = tempfile::tempdir().unwrap(); + let archive = directory.path().join("archive"); + let projection = directory.path().join("projection"); + crate::archive::preflight_archive_publication(&archive).unwrap(); + let legacy = crate::record::tests::valid_record_fixture(); + let gqt = authority_fixture().await; + let canonical = crate::gqt_record::canonical_bytes(&gqt).unwrap(); + assert_eq!( + crate::gqt_record::parse(&canonical).unwrap(), + crate::gqt_record::AnyRunRecordV1::Gqt(gqt.clone()) + ); + crate::archive::publish_record(&archive, &legacy).unwrap(); + let receipt = crate::archive::publish_record(&archive, &gqt).unwrap(); + let built = crate::projection::rebuild_projection(&archive, &projection) + .await + .unwrap(); + assert_eq!(built.record_count, 2); + assert_eq!(built.point_count, 2); + let points = crate::projection::list_points_page(&projection, 10, None) + .await + .unwrap(); + assert_eq!(points.rows.len(), 2); + let runs = + crate::projection::list_runs_for_point_page(&projection, &gqt.run.point_id, 10, None) + .await + .unwrap(); + assert_eq!(runs.rows.len(), 1); + assert_eq!(runs.rows[0]["record_sha256"], receipt.record_sha256); + assert_eq!(runs.rows[0]["invocation_id"], gqt.invocation.invocation_id); +} +#[test] +fn raw_dataset_plan_needs_no_measured_operation_and_unions_query_indexes() { + let measured = plan("nearest-ranks-updated-embedding"); + let dataset = catalog().join("fixtures/nearest_ranks_updated_embedding.gqt"); + let queries = catalog().join("workloads/nearest_ranks_updated_embedding.gqt"); + let raw = dataset_file( + &dataset, + None, + measured.definition.environment.backend.clone(), + measured.definition.protocol.reset, + ) + .unwrap(); + assert!(!raw.needs_indices); + let indexed = dataset_file( + &dataset, + Some(&queries), + measured.definition.environment.backend.clone(), + measured.definition.protocol.reset, + ) + .unwrap(); + assert!(indexed.needs_indices); + assert_eq!(indexed.recipe_sha256, measured.recipe_sha256); + assert_eq!(indexed, measured.dataset_build_plan()); +} +#[test] +fn acquisition_receipts_fit_before_dataset_io() { + use crate::gqt_runner::{ + GQT_RECORD_ENVELOPE_RESERVE, preflight_acquisition_budget, sample_byte_upper_bound, + }; + let mut p = plan("tiny-read"); + preflight_acquisition_budget(&p, 10_000).unwrap(); + let first = p.queries.text.find("--- query").unwrap(); + let second = p.queries.text[first + 3..].find("--- query").unwrap() + first + 3; + p.queries.text = format!( + "{}--- loop $i 0 4095\n{}--- endloop\n", + &p.queries.text[..second], + &p.queries.text[second..] + ); + p.queries.sha256 = sha256_bytes(p.queries.text.as_bytes()); + p.planned_sha256 = p.planned_hash().unwrap(); + p.revalidate().unwrap(); + preflight_acquisition_budget(&p, 1).unwrap(); + let err = preflight_acquisition_budget(&p, 10_000).unwrap_err(); + assert_eq!(err.code, "gqt_record_budget_exceeded"); + let sample = sample_byte_upper_bound(&p).unwrap(); + let last = + ((crate::record::MAX_RECORD_BYTES - GQT_RECORD_ENVELOPE_RESERVE) / (sample + 1)) as u32; + assert!(last > 1 && last < 10_000); + preflight_acquisition_budget(&p, last).unwrap(); + assert!(preflight_acquisition_budget(&p, last + 1).is_err()); + let mut merge = plan("branch-merge-d50-warm"); + let with_phases = sample_byte_upper_bound(&merge).unwrap(); + merge.definition.protocol.attribution = crate::case::Attribution::Off; + assert!(sample_byte_upper_bound(&merge).unwrap() < with_phases); +} + +#[tokio::test] +async fn completed_gqt_prefix_has_one_owner_and_failed_repetition_is_retained() { + let record = authority_fixture().await; + let p = plan("tiny-read"); + let logical = &record.fixture.handoff.summary; + let bound = p + .bind(&logical.logical_content_sha256, &logical.algorithm) + .unwrap(); + let sample = record.measurements.raw_samples[0].clone(); + let partial = crate::gqt_runner::RunExecution { + runner_output_version: 1, + case_id: record.run.case_id, + case_path: catalog().join("cases/tiny-read.case-v1.yaml"), + point_id: bound.point_id.clone(), + point_name: bound.point_name.clone(), + requested_repetitions: 2, + bound, + build: crate::runner::build_evidence(None).unwrap(), + machine: record.machine, + environment: crate::environment::LocalEnvironmentEvidence { + filesystem: "apfs".into(), + storage_class: "nvme-ssd".into(), + mount_point: "/test".into(), + storage_protocol: "local".into(), + available_bytes: 1024, + probe: "test", + }, + fixture: record.fixture, + dataset_cache_hit: true, + samples: vec![sample.clone()], + wall_clock: crate::runner::WallClockSummary { + observed_repetitions: 1, + min_us: sample.elapsed_us, + p50_us: sample.elapsed_us, + max_us: sample.elapsed_us, + p95_us: None, + p95_supported: false, + }, + durable_record: false, + }; + let mut error = crate::runner::RunnerError::new("worker_failed", "test failure"); + error.context.gqt_partial_run = Some(Box::new(partial)); + error.context.gqt_settled_sample = Some(Box::new(sample)); + error.context.gqt_settled_elapsed_us = Some(7); + error.context.child_process = Some(crate::runner::ChildProcessEvidence::default()); + error.context.quarantined_workspace = Some(PathBuf::from("/test/quarantined")); + let before = serde_json::to_value(&error).unwrap(); + assert!(before.get("gqt_partial_run").is_some()); + error.context.clear_completed_prefix(); + let after = serde_json::to_value(&error).unwrap(); + for key in [ + "completed_runs", + "completed_samples", + "partial_run", + "gqt_partial_run", + ] { + assert!(after.get(key).is_none(), "{key}"); + } + for key in [ + "gqt_settled_sample", + "gqt_settled_elapsed_us", + "child_process", + "quarantined_workspace", + ] { + assert_eq!(after[key], before[key], "{key}"); + } +} + +#[test] +fn complete_frame_bound_accounts_for_paths_and_json_escaping_before_build() { + let p = plan("tiny-read"); + crate::gqt_supervisor::preflight_plan(&p, Path::new("/cache")).unwrap(); + let huge = PathBuf::from(format!("/{}", "\"".repeat(600_000))); + assert!(crate::gqt_supervisor::preflight_plan(&p, &huge).is_err()); +} + +#[test] +fn nested_and_relocated_catalogs_keep_content_identity_and_refuse_aliases() { + let directory = tempfile::tempdir().unwrap(); + let first = directory.path().join("first"); + for child in ["cases/nested", "fixtures", "workloads", "suites/group"] { + std::fs::create_dir_all(first.join(child)).unwrap(); + } + std::fs::copy( + catalog().join("fixtures/tiny_graph.gqt"), + first.join("fixtures/tiny_graph.gqt"), + ) + .unwrap(); + std::fs::copy( + catalog().join("workloads/tiny_read.gqt"), + first.join("workloads/tiny_read.gqt"), + ) + .unwrap(); + let mut definition = plan("tiny-read").definition; + definition.fixture = GqtFixture::Dataset { + path: "../fixtures/tiny_graph.gqt".into(), + }; + definition.workload.queries = "../workloads/tiny_read.gqt".into(); + let original = serde_yaml::to_string(&definition).unwrap(); + let nested = original + .replace("../fixtures/", "../../fixtures/") + .replace("../workloads/", "../../workloads/"); + std::fs::write(first.join("cases/nested/read.case-v1.yaml"), &nested).unwrap(); + let suite = "version: 1\nname: nested\nruns:\n - case: ../../cases/nested/read.case-v1.yaml\n repetitions: 1\n"; + std::fs::write(first.join("suites/group/suite-v1.yaml"), suite).unwrap(); + let initial = crate::load_suite(&first.join("suites/group")) + .into_result() + .unwrap(); + let moved = directory.path().join("moved"); + std::fs::rename(first, &moved).unwrap(); + let relocated = crate::load_suite(&moved.join("suites/group")) + .into_result() + .unwrap(); + assert_eq!( + initial.runs[0].case.planned_identity(), + relocated.runs[0].case.planned_identity() + ); + std::fs::write( + moved.join("cases/nested/alias.case-v1.yaml"), + nested.replace("id: tiny-read", "id: alias-read"), + ) + .unwrap(); + std::fs::write( + moved.join("suites/group/suite-v1.yaml"), + format!("{suite} - case: ../../cases/nested/alias.case-v1.yaml\n repetitions: 1\n"), + ) + .unwrap(); + assert!( + crate::load_suite(&moved.join("suites/group")) + .into_result() + .is_err() + ); +} +#[tokio::test] +async fn expected_parameter_error_does_not_claim_a_warming_engine_read() { + let mut p = plan("tiny-read"); + let prefix = "--- query\nquery invalid($key: String) { match { $i: Item { key: $key } } return { $i.val } }\n--- params\n{\"key\":42}\n--- expect error: params rejected\n\n"; + let at = p.queries.text.find("--- query").unwrap(); + p.queries.text.insert_str(at, prefix); + p.queries.sha256 = sha256_bytes(p.queries.text.as_bytes()); + p.definition.workload.measured_step.ordinal = 2; + p.cache_condition = admit_queries( + &p.queries.parse().unwrap(), + &p.definition.workload.measured_step, + ) + .unwrap(); + p.case_digest = crate::model::typed_sha256(&p.definition).unwrap(); + p.planned_sha256 = p.planned_hash().unwrap(); + let error = run_sample(&p).await.unwrap_err(); + assert_eq!(error.code, "gqt_prepare_failed"); + assert!(error.context.gqt_settled_sample.is_none()); +} diff --git a/crates/omnigraph-bench/src/gqt_worker.rs b/crates/omnigraph-bench/src/gqt_worker.rs new file mode 100644 index 000000000..fa805517b --- /dev/null +++ b/crates/omnigraph-bench/src/gqt_worker.rs @@ -0,0 +1,416 @@ +//! One-process execution endpoint for the private repetition protocol. + +use std::io::{BufReader, BufWriter}; +use std::process::ExitCode; +use std::sync::mpsc::{self, Receiver}; + +use crate::gqt_case::BoundGqt as ValidatedCase; +use crate::gqt_protocol::{ + ChildFrameV1, ParentFrameV1, WORKER_PROTOCOL_VERSION, WorkerRequestV1, WorkerStageV1, + digest_worker_executable, read_frame, validate_protocol_version, write_frame, +}; +use crate::gqt_runner::execute_gqt_rep_signaled; +use crate::runner::{MeasurementSignals, RunnerError, RunnerResult}; + +/// Run exactly one repetition over the private stdin/stdout worker protocol. +/// +/// This is public only so the package binary can host the hidden worker +/// command. It is not a stable embedding API. +#[doc(hidden)] +pub async fn run_worker_stdio_v1() -> ExitCode { + let input = std::io::stdin(); + let output = std::io::stdout(); + let mut input = BufReader::new(input); + let mut output = BufWriter::new(output); + + let request = match read_request(&mut input) { + Ok(request) => request, + Err(error) => { + let _ = send_failure(&mut output, WorkerStageV1::Bootstrap, &error, None); + return ExitCode::FAILURE; + } + }; + let parent_frames = match spawn_parent_watch(input) { + Ok(parent_frames) => parent_frames, + Err(error) => { + let error = RunnerError::new( + "worker_watchdog_failed", + format!("could not start parent-liveness watcher: {error}"), + ); + let _ = send_failure(&mut output, WorkerStageV1::Bootstrap, &error, None); + return ExitCode::FAILURE; + } + }; + let executable_digest = match std::env::current_exe() + .map_err(|error| error.to_string()) + .and_then(|path| digest_worker_executable(&path).map_err(|error| error.to_string())) + { + Ok(digest) => digest, + Err(message) => { + let error = RunnerError::new( + "worker_attestation_failed", + format!("could not attest the running worker executable: {message}"), + ); + let _ = send_failure(&mut output, WorkerStageV1::Bootstrap, &error, None); + return ExitCode::FAILURE; + } + }; + let worker_build = match crate::runner::worker_build_attestation(executable_digest) { + Ok(build) => build, + Err(error) => { + let _ = send_failure(&mut output, WorkerStageV1::Bootstrap, &error, None); + return ExitCode::FAILURE; + } + }; + let mut signals = ProtocolSignals { + parent_frames, + output, + request: request.clone(), + worker_build, + }; + + let result = execute_request(&request, &mut signals).await; + match result { + Ok(sample) => { + let frame = ChildFrameV1::Complete { + protocol_version: WORKER_PROTOCOL_VERSION, + point_id: request.expected_point_id.clone(), + case_digest: request.expected_case_digest.clone(), + sample: Box::new(sample), + }; + match write_frame(&mut signals.output, &frame) { + Ok(()) => ExitCode::SUCCESS, + Err(error) => { + eprintln!("could not send repetition completion: {error}"); + ExitCode::FAILURE + } + } + } + Err(error) => { + let settled = error.context.gqt_settled_sample.clone(); + let (stage, emitted_error) = match stage_for_error(&error) { + Some(stage) => (stage, error), + None => ( + WorkerStageV1::Protocol, + RunnerError::new( + "worker_stage_unclassified", + format!( + "worker error code `{}` has no declared execution-stage mapping", + error.code + ), + ), + ), + }; + if let Err(protocol_error) = + send_failure(&mut signals.output, stage, &emitted_error, settled) + { + eprintln!("could not send structured worker failure: {protocol_error}"); + } + ExitCode::FAILURE + } + } +} + +fn read_request(input: &mut BufReader) -> RunnerResult { + let frame = read_frame::<_, ParentFrameV1>(input).map_err(|error| { + RunnerError::new( + "worker_protocol_error", + format!("could not read worker request: {error}"), + ) + })?; + let Some(ParentFrameV1::Request { + protocol_version, + request, + }) = frame + else { + return Err(RunnerError::new( + "worker_protocol_error", + "worker expected exactly one request frame before preparation", + )); + }; + validate_protocol_version(protocol_version) + .map_err(|error| RunnerError::new("worker_protocol_error", error.to_string()))?; + Ok(*request) +} + +async fn execute_request( + request: &WorkerRequestV1, + signals: &mut ProtocolSignals, +) -> RunnerResult { + crate::runner::enforce_release_build()?; + crate::runner::validate_benchmark_child_runtime_overrides(&request.worker_scratch_root)?; + let validated = validate_worker_case(request)?; + execute_gqt_rep_signaled( + request.repetition, + &request.repetition_root, + &request.expected_physical_digest, + &request.expected_metadata_digest, + &validated, + signals, + ) + .await +} + +fn validate_worker_case(request: &WorkerRequestV1) -> RunnerResult { + if !request.repetition_root.is_absolute() { + return Err(RunnerError::new( + "worker_identity_mismatch", + format!( + "repetition root must be absolute: {}", + request.repetition_root.display() + ), + )); + } + if !request.worker_scratch_root.is_absolute() { + return Err(RunnerError::new( + "worker_protocol_error", + "worker scratch root must be absolute", + )); + } + let expected_name = format!("worker-scratch-{:08}", request.repetition); + if request + .worker_scratch_root + .file_name() + .and_then(|name| name.to_str()) + != Some(expected_name.as_str()) + { + return Err(RunnerError::new( + "worker_protocol_error", + "worker scratch root does not match the repetition identity", + )); + } + let scratch_metadata = + std::fs::symlink_metadata(&request.worker_scratch_root).map_err(|error| { + RunnerError::new( + "worker_protocol_error", + format!("could not inspect worker scratch root: {error}"), + ) + })?; + if scratch_metadata.file_type().is_symlink() || !scratch_metadata.is_dir() { + return Err(RunnerError::new( + "worker_protocol_error", + "worker scratch root must be a real directory", + )); + } + let repetition_root = std::fs::canonicalize(&request.repetition_root).map_err(|error| { + RunnerError::new( + "worker_protocol_error", + format!("could not resolve worker repetition root: {error}"), + ) + })?; + let worker_scratch_root = + std::fs::canonicalize(&request.worker_scratch_root).map_err(|error| { + RunnerError::new( + "worker_protocol_error", + format!("could not resolve worker scratch root: {error}"), + ) + })?; + if repetition_root.parent() != worker_scratch_root.parent() { + return Err(RunnerError::new( + "worker_protocol_error", + "worker scratch root must be a sibling of the repetition store on the same verified scratch backend", + )); + } + let mut entries = std::fs::read_dir(&worker_scratch_root).map_err(|error| { + RunnerError::new( + "worker_protocol_error", + format!("could not inspect worker scratch contents: {error}"), + ) + })?; + if entries + .next() + .transpose() + .map_err(|error| { + RunnerError::new( + "worker_protocol_error", + format!("could not inspect worker scratch entry: {error}"), + ) + })? + .is_some() + { + return Err(RunnerError::new( + "worker_protocol_error", + "worker scratch root must be empty before measurement preparation", + )); + } + request + .case + .revalidate() + .map_err(|e| RunnerError::new("worker_case_invalid", e))?; + let validated = request.case.clone(); + if validated.point_id != request.expected_point_id + || validated.plan.case_digest != request.expected_case_digest + { + return Err(RunnerError::new( + "worker_identity_mismatch", + format!( + "worker derived point_id={} case_digest={}, expected point_id={} case_digest={}", + validated.point_id, + validated.plan.case_digest, + request.expected_point_id, + request.expected_case_digest + ), + )); + } + Ok(validated) +} + +struct ProtocolSignals { + parent_frames: Receiver>, + output: BufWriter, + request: WorkerRequestV1, + worker_build: crate::gqt_protocol::WorkerBuildV1, +} + +impl MeasurementSignals for ProtocolSignals { + fn ready(&mut self) -> RunnerResult<()> { + let machine = crate::machine::capture_machine_identity().map_err(|error| { + RunnerError::new( + "machine_identity_capture_failed", + format!("could not capture repetition-worker machine identity: {error}"), + ) + })?; + write_frame( + &mut self.output, + &ChildFrameV1::Ready { + protocol_version: WORKER_PROTOCOL_VERSION, + repetition: self.request.repetition, + point_id: self.request.expected_point_id.clone(), + case_digest: self.request.expected_case_digest.clone(), + worker_build: Box::new(self.worker_build.clone()), + machine: Box::new(machine), + physical_digest: self.request.expected_physical_digest.clone(), + metadata_digest: self.request.expected_metadata_digest.clone(), + }, + ) + .map_err(|error| RunnerError::new("worker_protocol_error", error.to_string()))?; + + let begin = self + .parent_frames + .recv() + .map_err(|_| { + RunnerError::new( + "worker_parent_disconnected", + "parent-liveness watcher stopped before measurement began", + ) + })? + .map_err(|error| RunnerError::new("worker_protocol_error", error))?; + match begin { + ParentFrameV1::Begin { + protocol_version, + repetition, + } if protocol_version == WORKER_PROTOCOL_VERSION + && repetition == self.request.repetition => {} + frame => { + return Err(RunnerError::new( + "worker_protocol_error", + format!( + "worker expected begin-v{} for repetition {}, got {frame:?}", + WORKER_PROTOCOL_VERSION, self.request.repetition + ), + )); + } + } + Ok(()) + } + + fn settled(&mut self, elapsed_us: u64) -> RunnerResult<()> { + write_frame( + &mut self.output, + &ChildFrameV1::Settled { + protocol_version: WORKER_PROTOCOL_VERSION, + repetition: self.request.repetition, + elapsed_us, + }, + ) + .map_err(|error| RunnerError::new("worker_protocol_error", error.to_string())) + } +} + +/// Parent EOF terminates the worker during preparation, measurement, or verification. +fn spawn_parent_watch( + mut input: BufReader, +) -> std::io::Result>> { + let (send, receive) = mpsc::sync_channel(1); + std::thread::Builder::new() + .name("omnigraph-bench-parent-watch".to_string()) + .spawn(move || { + match read_frame::<_, ParentFrameV1>(&mut input) { + Ok(Some(frame)) => { + if send.send(Ok(frame)).is_err() { + return; + } + } + Ok(None) => std::process::exit(125), + Err(error) => { + let _ = send.send(Err(error.to_string())); + return; + } + } + + match read_frame::<_, ParentFrameV1>(&mut input) { + Ok(None) => std::process::exit(125), + Ok(Some(_)) | Err(_) => std::process::exit(126), + } + })?; + Ok(receive) +} + +fn stage_for_error(error: &RunnerError) -> Option { + if error.code.starts_with("gqt_") { + return Some(if error.code == "gqt_verification_failed" { + WorkerStageV1::Verify + } else if error.code == "gqt_measure_failed" { + WorkerStageV1::Measure + } else { + WorkerStageV1::Prepare + }); + } + Some(match error.code.as_str() { + "release_build_required" + | "worker_attestation_failed" + | "worker_build_attestation_invalid" + | "worker_case_invalid" + | "worker_identity_mismatch" + | "invalid_lance_mem_pool_size" + | "unsupported_runtime_override" + | "build_attestation_environment_mismatch" + | "unsupported_runner_axis" => WorkerStageV1::Bootstrap, + "pre_measurement_write_detected" + | "pre_measurement_shape_mismatch" + | "cache_preparation_failed" + | "protected_head_capture_failed" + | "unsupported_cache_condition" + | "machine_identity_capture_failed" + | "engine_open_failed" + | "storage_open_failed" + | "non_utf8_path" => WorkerStageV1::Prepare, + "merge_failed" | "merge_deadline_exceeded" | "duration_overflow" | "counter_regression" => { + WorkerStageV1::Measure + } + "verification_failed" + | "vacuous_merge" + | "missing_table_walk_phase" + | "interval_overflow" => WorkerStageV1::Verify, + "worker_protocol_error" | "worker_parent_disconnected" => WorkerStageV1::Protocol, + _ => return None, + }) +} + +fn send_failure( + output: &mut BufWriter, + stage: WorkerStageV1, + error: &RunnerError, + settled_sample: Option>, +) -> Result<(), crate::gqt_protocol::WorkerProtocolError> { + write_frame( + output, + &ChildFrameV1::Failed { + protocol_version: WORKER_PROTOCOL_VERSION, + stage, + code: error.code.clone(), + message: error.message.clone(), + settled_sample, + }, + ) +} diff --git a/crates/omnigraph-bench/src/legacy/branch_merge_oracle.rs b/crates/omnigraph-bench/src/legacy/branch_merge_oracle.rs new file mode 100644 index 000000000..b5151f265 --- /dev/null +++ b/crates/omnigraph-bench/src/legacy/branch_merge_oracle.rs @@ -0,0 +1,146 @@ +//! Historical Rust fixture oracle retained only for GQT parity tests. +use super::*; +pub async fn initialize_local_fixture( + root_uri: &str, + plan: &BranchMergePlan, +) -> BranchMergeResult { + let preflight = plan.preflight()?; + if root_uri.contains("://") && !root_uri.starts_with("file://") { + return Err(unsupported( + "invocation.root_uri", + format!("local fixture initialization cannot use {root_uri:?}"), + )); + } + let schema = schema_source(plan.tables); + let db = Session::from_defaults( + Arc::new(Omnigraph::init(root_uri, &schema).await.map_err(|error| { + fixture_error(format!("initialize fixture at {root_uri}: {error}")) + })?), + SessionSettings::default(), + ); + let base_load_commits = load_base(&db, plan).await?; + if u64::try_from(base_load_commits).ok() != Some(preflight.base_load_commits) { + return Err(fixture_error(format!( + "builder-v3 base-load recipe drifted: preflight declared {} publications, execution produced {base_load_commits}", + preflight.base_load_commits + ))); + } + let optimized_user_tables = match plan.compaction_recency { + CompactionRecency::Optimized => { + let outcomes = db + .optimize() + .await + .map_err(|error| fixture_error(format!("optimize fixture main branch: {error}")))?; + let intended_keys = (0..plan.node_tables()) + .map(node_table_key) + .chain((0..plan.edge_tables()).map(edge_table_key)); + for key in intended_keys { + let outcome = outcomes + .iter() + .find(|outcome| outcome.type_key == key) + .ok_or_else(|| { + fixture_error(format!( + "optimized fixture returned no outcome for intended user table {key}" + )) + })?; + if outcome.skipped.is_some() + || !outcome.committed + || outcome.fragments_removed == 0 + || outcome.fragments_added == 0 + { + return Err(fixture_error(format!( + "optimized fixture did not productively compact {key}: committed={}, fragments_removed={}, fragments_added={}, skipped={:?}", + outcome.committed, + outcome.fragments_removed, + outcome.fragments_added, + outcome.skipped + ))); + } + } + plan.tables + } + CompactionRecency::NotOptimized => 0, + }; + + prepare_reversible_updates(&db, plan).await?; + + db.branch_create_from(ReadTarget::branch(MAIN_BRANCH), SOURCE_BRANCH) + .await + .map_err(|error| fixture_error(format!("create {SOURCE_BRANCH}: {error}")))?; + db.branch_create_from(ReadTarget::branch(MAIN_BRANCH), TARGET_BRANCH) + .await + .map_err(|error| fixture_error(format!("create {TARGET_BRANCH}: {error}")))?; + + let queries = mutation_queries(plan.diverged_tables); + diverge(&db, SOURCE_BRANCH, Side::Source, plan, &queries).await?; + diverge(&db, TARGET_BRANCH, Side::Target, plan, &queries).await?; + + let schema_shape = verified_schema_shape_json(&db, plan)?; + let mut logical_digest = Sha256::new(); + logical_digest.update(LOGICAL_FIXTURE_DIGEST_DOMAIN); + hash_logical_field( + &mut logical_digest, + b"schema-shape", + schema_shape.as_bytes(), + ); + hash_logical_field(&mut logical_digest, b"logical-index-inventory", b"[]"); + verify_branch( + &db, + MAIN_BRANCH, + plan, + BranchState::Main, + Some(&mut logical_digest), + ) + .await?; + verify_branch( + &db, + SOURCE_BRANCH, + plan, + BranchState::Source, + Some(&mut logical_digest), + ) + .await?; + verify_branch( + &db, + TARGET_BRANCH, + plan, + BranchState::Target, + Some(&mut logical_digest), + ) + .await?; + let source_history_depth = u64::try_from( + db.list_commits(Some(SOURCE_BRANCH)) + .await + .map_err(|error| fixture_error(format!("list {SOURCE_BRANCH} commits: {error}")))? + .len(), + ) + .map_err(|_| fixture_error("source history depth does not fit u64"))?; + let target_history_depth = u64::try_from( + db.list_commits(Some(TARGET_BRANCH)) + .await + .map_err(|error| fixture_error(format!("list {TARGET_BRANCH} commits: {error}")))? + .len(), + ) + .map_err(|_| fixture_error("target history depth does not fit u64"))?; + if source_history_depth != plan.requested_history_depth + || target_history_depth != plan.requested_history_depth + { + return Err(unsupported( + "fixture.state.history_depth", + format!( + "requested exactly {} reachable commits per branch, but deterministic construction produced {source_history_depth} on {SOURCE_BRANCH} and {target_history_depth} on {TARGET_BRANCH}; builder v3 does not silently pad or squash history; declare the observed depth or revise the versioned deterministic builder contract", + plan.requested_history_depth + ), + )); + } + let logical_content_sha256 = format!("{:x}", logical_digest.finalize()); + + drop(db); + Ok(FixtureBuildSummary { + base_load_commits, + optimized_user_tables, + source_history_depth, + target_history_depth, + logical_content_sha256, + }) +} diff --git a/crates/omnigraph-bench/src/legacy/case.rs b/crates/omnigraph-bench/src/legacy/case.rs new file mode 100644 index 000000000..fb6b0ac16 --- /dev/null +++ b/crates/omnigraph-bench/src/legacy/case.rs @@ -0,0 +1,1700 @@ +use std::path::Path; + +use serde::{Deserialize, Deserializer, Serialize}; + +use crate::model::{ + Diagnostic, ValidationOutcome, declared_version, read_yaml_file, strict_yaml, typed_sha256, + valid_kebab_id, +}; +use crate::{CASE_FORMAT_VERSION, POINT_IDENTITY_VERSION}; + +const MAX_TABLES: u64 = 10_000; +const MAX_ROWS_PER_TABLE: u64 = 1_000_000_000; +const MAX_TOTAL_ROWS: u64 = 10_000_000_000; +const MAX_PAYLOAD_BYTES_PER_ROW: u64 = 64 * 1024 * 1024; +const MAX_LOGICAL_PAYLOAD_BYTES: u64 = 1 << 50; +const MAX_HISTORY_DEPTH: u64 = 1_000_000; +pub(crate) const MAX_WARMUP_ITERATIONS: u32 = 1_000; +const MAX_DEADLINE_SECONDS: u64 = 3_600; +pub(crate) const SYNTHETIC_BRANCH_MERGE_BUILDER_VERSION: u32 = 3; +pub(crate) const MAX_PREPARATION_COMMITS: u64 = 10_000; +pub(crate) const MAX_PREPARATION_ROWS_PER_COMMIT: u64 = 4_096; + +/// A complete V1 branch-merge experiment. `id` is a human selector only. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct CaseV1 { + pub version: u32, + pub id: String, + pub scenario: Scenario, + pub fixture: Fixture, + pub workload: Workload, + pub environment: Environment, + pub protocol: Protocol, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum Scenario { + #[serde(rename = "branch-merge-v1")] + BranchMergeV1, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Fixture { + pub builder: FixtureBuilder, + pub data: Data, + pub state: State, + /// Optional, independently versioned preparation. Omitting this field must + /// preserve the canonical bytes of every existing builder-v3 point. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub preparation: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "kind", deny_unknown_fields)] +pub enum FixturePreparation { + #[serde(rename = "reversible-updates-v1")] + ReversibleUpdatesV1 { + additional_commits: u64, + rows_per_commit: u64, + seed: u64, + maintenance: PreparationMaintenance, + }, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum PreparationMaintenance { + None, +} + +impl FixturePreparation { + pub fn additional_commits(self) -> u64 { + match self { + Self::ReversibleUpdatesV1 { + additional_commits, .. + } => additional_commits, + } + } + + pub fn rows_per_commit(self) -> u64 { + match self { + Self::ReversibleUpdatesV1 { + rows_per_commit, .. + } => rows_per_commit, + } + } + + pub fn seed(self) -> u64 { + match self { + Self::ReversibleUpdatesV1 { seed, .. } => seed, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct FixtureBuilder { + pub kind: FixtureBuilderKind, + pub version: u32, + pub seed: u64, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum FixtureBuilderKind { + #[serde(rename = "synthetic-branch-merge")] + SyntheticBranchMerge, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Data { + pub provenance: DataProvenance, + pub tables: u64, + pub rows_per_table: u64, + pub payload_bytes: u64, + pub column_shape: ColumnShape, + pub topology_skew: TopologySkew, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum DataProvenance { + Synthetic, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum ColumnShape { + Scalars, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum TopologySkew { + Uniform, + PowerLaw, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct State { + pub aging: Aging, + /// Structured index inventory. Empty means no indexes. Each entry names + /// the exact table/column, index mechanism, and current coverage state, so + /// adding indexed cases never requires replacing a lossy global tag. + pub indexes: Vec, + pub deletion_history: DeletionHistory, + pub compaction_recency: CompactionRecency, + pub history_depth: u64, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Aging { + BulkLoaded, + SmallCommits, +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct IndexSpec { + pub table: String, + pub column: String, + pub kind: IndexKind, + pub freshness: IndexFreshness, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum IndexKind { + Btree, + Fts, + Ann, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum IndexFreshness { + Optimized, + RowsStale, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum DeletionHistory { + None, + Heavy, + ReversibleUpdates, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum CompactionRecency { + Optimized, + NotOptimized, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Workload { + pub delta_rows_per_side: u64, + pub diverged_tables: u64, + pub arrival: Arrival, + pub clients: u32, + pub read_write_mix: ReadWriteMix, + pub contention: Contention, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Arrival { + UnscheduledSingleShot, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum ReadWriteMix { + ReadHeavy, + Balanced, + WriteHeavy, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Contention { + NotApplicable, + SameKey, + DistinctKey, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Environment { + pub backend: Backend, + pub network_position: NetworkPosition, + pub execution: Execution, + pub cache_condition: CacheCondition, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[serde(tag = "kind", rename_all = "kebab-case")] +pub enum Backend { + LocalFs { + filesystem: LocalFilesystem, + storage_class: LocalStorageClass, + }, + S3 { + implementation: S3Implementation, + implementation_version: String, + region: String, + storage_class: String, + versioning: S3Versioning, + image_digest: Option, + }, +} + +impl<'de> Deserialize<'de> for Backend { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + match BackendWire::deserialize(deserializer)? { + BackendWire::Local(LocalBackendWire { + kind: LocalBackendKind::LocalFs, + filesystem, + storage_class, + }) => Ok(Self::LocalFs { + filesystem, + storage_class, + }), + BackendWire::S3(S3BackendWire { + kind: S3BackendKind::S3, + implementation, + implementation_version, + region, + storage_class, + versioning, + image_digest, + }) => Ok(Self::S3 { + implementation, + implementation_version, + region, + storage_class, + versioning, + image_digest, + }), + } + } +} + +#[derive(Deserialize)] +#[serde(untagged)] +enum BackendWire { + Local(LocalBackendWire), + S3(S3BackendWire), +} + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct LocalBackendWire { + kind: LocalBackendKind, + filesystem: LocalFilesystem, + storage_class: LocalStorageClass, +} + +#[derive(Deserialize)] +enum LocalBackendKind { + #[serde(rename = "local-fs")] + LocalFs, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum LocalFilesystem { + Apfs, + Ext4, + Xfs, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum LocalStorageClass { + NvmeSsd, + SataSsd, + NetworkBlock, + RamDisk, +} + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct S3BackendWire { + kind: S3BackendKind, + implementation: S3Implementation, + implementation_version: String, + region: String, + storage_class: String, + versioning: S3Versioning, + #[serde(default)] + image_digest: Option, +} + +#[derive(Deserialize)] +enum S3BackendKind { + #[serde(rename = "s3")] + S3, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum S3Implementation { + AwsS3, + Minio, + Rustfs, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum S3Versioning { + Enabled, + Disabled, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum NetworkPosition { + SameHost, + SameRegion, + Remote, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Execution { + Embedded, + Server, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct CacheCondition { + pub process: ProcessLifecycle, + pub engine: EnginePreparation, + pub page_cache: PageCacheCondition, + pub program: WarmupProgram, + pub iterations: u32, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum ProcessLifecycle { + FreshPerRepetition, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum EnginePreparation { + PreparationOnly, + WarmedByProgram, + ReopenedAfterProgram, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum PageCacheCondition { + Uncontrolled, + ProgramConditioned, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum WarmupProgram { + None, + BranchMergeReadSetV1, + GqtReadSetV1, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Protocol { + /// Measured-operation deadline. An explicit YAML `null` means no + /// measurement deadline; the runner's independent supervisor watchdog + /// remains bounded either way. + #[serde(deserialize_with = "deserialize_required_optional_deadline")] + pub deadline_seconds: Option, + pub attribution: Attribution, + pub schedule: Schedule, + pub reset: ResetMode, + pub timer: Timer, +} + +fn deserialize_required_optional_deadline<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + Option::::deserialize(deserializer) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Attribution { + PerPhase, + Off, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Schedule { + Manual, + Earned, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum ResetMode { + PlainCopy, + LocalClonefile, + S3Versioning, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Timer { + Monotonic, +} + +/// Deterministic source/target change mix for `branch-merge-v1`. +/// +/// Fixture admission and fixture construction must use this one definition so +/// the capacity proof cannot drift from the rows the builder actually writes. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct BranchMergeChangeMix { + pub updates: u64, + pub deletes: u64, + pub inserts: u64, +} + +pub(crate) fn branch_merge_change_mix(delta: u64) -> BranchMergeChangeMix { + let updates = delta.div_ceil(3); + let remaining = delta - updates; + let deletes = remaining.div_ceil(2); + BranchMergeChangeMix { + updates, + deletes, + inserts: remaining - deletes, + } +} + +/// Versioned, canonical point identity. It deliberately has no case id, +/// source path, suite, or repetition quantity. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PointIdentityV1 { + pub identity_version: u32, + pub scenario: Scenario, + pub fixture: Fixture, + pub workload: Workload, + pub environment: Environment, + pub protocol: Protocol, +} + +impl From<&CaseV1> for PointIdentityV1 { + fn from(case: &CaseV1) -> Self { + Self { + identity_version: POINT_IDENTITY_VERSION, + scenario: case.scenario, + fixture: case.fixture.clone(), + workload: case.workload.clone(), + environment: case.environment.clone(), + protocol: case.protocol.clone(), + } + } +} + +/// A strict, semantically valid case plus its two distinct digests. +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct ValidatedCase { + pub definition: CaseV1, + pub identity: PointIdentityV1, + /// Full SHA-256 of [`PointIdentityV1`], the experiment's natural key. + pub point_id: String, + /// Full SHA-256 of the complete typed case, including format version/id. + pub case_digest: String, + /// Human-readable convenience label. Never use this as identity. + pub point_name: String, +} + +/// Parse and semantically validate one case-v1 YAML document. +pub fn parse_case(source: &str) -> ValidationOutcome { + let version = match declared_version(source, "case") { + Ok(version) => version, + Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), + }; + if version != CASE_FORMAT_VERSION { + return ValidationOutcome::failure(vec![Diagnostic::error( + "unsupported_case_version", + "version", + format!( + "unsupported case version {version}; this build supports version {CASE_FORMAT_VERSION}" + ), + )]); + } + let definition: CaseV1 = match strict_yaml(source, "case") { + Ok(case) => case, + Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), + }; + validate_case(definition) +} + +/// Read, parse, and semantically validate one case-v1 YAML file. +pub fn load_case(path: &Path) -> ValidationOutcome { + let source = match read_yaml_file(path, "case") { + Ok(source) => source, + Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), + }; + parse_case(&source) +} + +/// Check cross-field invariants and derive stable identities. +pub fn validate_case(mut definition: CaseV1) -> ValidationOutcome { + normalize_identity_strings(&mut definition); + let mut diagnostics = Vec::new(); + if definition.version != CASE_FORMAT_VERSION { + diagnostics.push(Diagnostic::error( + "unsupported_case_version", + "version", + format!( + "unsupported case version {}; this build supports version {CASE_FORMAT_VERSION}", + definition.version + ), + )); + } + if !valid_kebab_id(&definition.id) || definition.id.len() > 128 { + diagnostics.push(Diagnostic::error( + "invalid_case_id", + "id", + "case id must be 1..=128 characters of kebab-case ASCII ([a-z0-9]+(?:-[a-z0-9]+)*)", + )); + } + if definition.fixture.builder.version != SYNTHETIC_BRANCH_MERGE_BUILDER_VERSION { + diagnostics.push(Diagnostic::error( + "unsupported_builder_version", + "fixture.builder.version", + format!( + "synthetic-branch-merge builder version {} is unsupported; this build supports version {SYNTHETIC_BRANCH_MERGE_BUILDER_VERSION}", + definition.fixture.builder.version, + ), + )); + } + validate_fixture_scale(&definition.fixture, &mut diagnostics); + if definition.fixture.data.topology_skew != TopologySkew::Uniform { + diagnostics.push(Diagnostic::error( + "unsupported_branch_merge_topology", + "fixture.data.topology_skew", + "synthetic branch-merge-v1 currently supports topology_skew: uniform", + )); + } + validate_indexes( + definition.fixture.data.column_shape, + &definition.fixture.state.indexes, + &mut diagnostics, + ); + validate_fixture_state(&definition.fixture, &mut diagnostics); + validate_workload(&definition, &mut diagnostics); + validate_cache_condition(&definition.environment.cache_condition, &mut diagnostics); + validate_backend_protocol(&definition, &mut diagnostics); + + if !diagnostics.is_empty() { + return ValidationOutcome::failure(diagnostics); + } + + definition.fixture.state.indexes.sort(); + let identity = PointIdentityV1::from(&definition); + let point_id = match typed_sha256(&identity) { + Ok(digest) => digest, + Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), + }; + let case_digest = match typed_sha256(&definition) { + Ok(digest) => digest, + Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), + }; + let short = &point_id[..12]; + let point_name = format!( + "branch-merge-t{}-n{}-d{}-{}-{short}", + definition.fixture.data.tables, + definition.fixture.data.rows_per_table, + definition.workload.delta_rows_per_side, + definition.environment.cache_condition.display_label(), + ); + ValidationOutcome::success(ValidatedCase { + definition, + identity, + point_id, + case_digest, + point_name, + }) +} + +fn normalize_identity_strings(case: &mut CaseV1) { + for index in &mut case.fixture.state.indexes { + index.table = index.table.trim().to_owned(); + index.column = index.column.trim().to_owned(); + } + if let Backend::S3 { + implementation_version, + region, + storage_class, + .. + } = &mut case.environment.backend + { + *implementation_version = implementation_version.trim().to_owned(); + *region = region.trim().to_owned(); + *storage_class = storage_class.trim().to_owned(); + } +} + +impl CacheCondition { + pub(crate) fn display_label(&self) -> &'static str { + match self.engine { + EnginePreparation::PreparationOnly => "process-cold", + EnginePreparation::WarmedByProgram => "warm", + EnginePreparation::ReopenedAfterProgram => "post-reopen", + } + } +} + +fn validate_workload(case: &CaseV1, diagnostics: &mut Vec) { + let data = &case.fixture.data; + let workload = &case.workload; + let edge_tables = data.tables / 2; + if workload.delta_rows_per_side == 0 { + diagnostics.push(Diagnostic::error( + "invalid_delta", + "workload.delta_rows_per_side", + "delta_rows_per_side must be >= 1", + )); + } + if workload.diverged_tables == 0 || workload.diverged_tables > edge_tables { + diagnostics.push(Diagnostic::error( + "invalid_diverged_tables", + "workload.diverged_tables", + format!( + "builder v3 diverges edge tables and requires diverged_tables between 1 and the fixture's {edge_tables} edge tables" + ), + )); + } + if workload.clients != 1 { + diagnostics.push(Diagnostic::error( + "unsupported_branch_merge_clients", + "workload.clients", + "branch-merge-v1 is an unscheduled single-shot workload and requires clients: 1", + )); + } + if workload.read_write_mix != ReadWriteMix::WriteHeavy { + diagnostics.push(Diagnostic::error( + "unsupported_branch_merge_read_write_mix", + "workload.read_write_mix", + "branch-merge-v1 measures one client-visible write and requires read_write_mix: write-heavy", + )); + } + if workload.contention != Contention::DistinctKey { + diagnostics.push(Diagnostic::error( + "unsupported_branch_merge_contention", + "workload.contention", + "branch-merge-v1 uses disjoint source/target cohorts and requires contention: distinct-key", + )); + } + + if workload.delta_rows_per_side > 0 + && workload.diverged_tables > 0 + && workload.diverged_tables <= edge_tables + { + let change_mix = branch_merge_change_mix(workload.delta_rows_per_side); + let per_table = change_mix + .updates + .div_ceil(workload.diverged_tables) + .checked_add(change_mix.deletes.div_ceil(workload.diverged_tables)) + .and_then(|rows| rows.checked_mul(2)); + match per_table { + Some(required) if required <= data.rows_per_table => {} + Some(required) => diagnostics.push(Diagnostic::error( + "fixture_cohort_capacity_exceeded", + "workload.delta_rows_per_side", + format!( + "the branch-merge cohorts need {required} base rows in the busiest table, but rows_per_table is {}", + data.rows_per_table + ), + )), + None => diagnostics.push(Diagnostic::error( + "fixture_cohort_capacity_overflow", + "workload.delta_rows_per_side", + "branch-merge cohort sizing overflowed u64", + )), + } + } +} + +fn validate_fixture_scale(fixture: &Fixture, diagnostics: &mut Vec) { + let data = &fixture.data; + if !(1..=MAX_TABLES).contains(&data.tables) { + diagnostics.push(Diagnostic::error( + "invalid_table_count", + "fixture.data.tables", + format!("table count must be in 1..={MAX_TABLES}"), + )); + } + if data.tables < 2 || !data.tables.is_multiple_of(2) { + diagnostics.push(Diagnostic::error( + "invalid_graph_table_mix", + "fixture.data.tables", + "synthetic-branch-merge builder v3 requires an even total table count >= 2, split equally between node and edge tables", + )); + } + if !(1..=MAX_ROWS_PER_TABLE).contains(&data.rows_per_table) { + diagnostics.push(Diagnostic::error( + "invalid_row_count", + "fixture.data.rows_per_table", + format!("rows_per_table must be in 1..={MAX_ROWS_PER_TABLE}"), + )); + } + if data.payload_bytes > MAX_PAYLOAD_BYTES_PER_ROW { + diagnostics.push(Diagnostic::error( + "invalid_payload_size", + "fixture.data.payload_bytes", + format!("payload_bytes must be <= {MAX_PAYLOAD_BYTES_PER_ROW}"), + )); + } + if !(1..=MAX_HISTORY_DEPTH).contains(&fixture.state.history_depth) { + diagnostics.push(Diagnostic::error( + "invalid_history_depth", + "fixture.state.history_depth", + format!("history_depth must be in 1..={MAX_HISTORY_DEPTH}"), + )); + } + + match data.tables.checked_mul(data.rows_per_table) { + Some(total_rows) if total_rows > MAX_TOTAL_ROWS => diagnostics.push(Diagnostic::error( + "fixture_row_budget_exceeded", + "fixture.data", + format!("tables * rows_per_table must be <= {MAX_TOTAL_ROWS}, got {total_rows}"), + )), + Some(total_rows) => match total_rows.checked_mul(data.payload_bytes) { + Some(total_bytes) if total_bytes > MAX_LOGICAL_PAYLOAD_BYTES => { + diagnostics.push(Diagnostic::error( + "fixture_payload_budget_exceeded", + "fixture.data", + format!( + "logical payload must be <= {MAX_LOGICAL_PAYLOAD_BYTES} bytes, got {total_bytes}" + ), + )); + } + Some(_) => {} + None => diagnostics.push(Diagnostic::error( + "fixture_payload_size_overflow", + "fixture.data", + "tables * rows_per_table * payload_bytes overflowed u64", + )), + }, + None => diagnostics.push(Diagnostic::error( + "fixture_row_count_overflow", + "fixture.data", + "tables * rows_per_table overflowed u64", + )), + } +} + +fn validate_fixture_state(fixture: &Fixture, diagnostics: &mut Vec) { + if let Some(preparation) = fixture.preparation { + if !(2..=MAX_PREPARATION_COMMITS).contains(&preparation.additional_commits()) + || !preparation.additional_commits().is_multiple_of(2) + { + diagnostics.push(Diagnostic::error( + "invalid_preparation_commits", "fixture.preparation.additional_commits", + format!("reversible updates require an even number of real commits in 2..={MAX_PREPARATION_COMMITS}"), + )); + } + if !(1..=MAX_PREPARATION_ROWS_PER_COMMIT).contains(&preparation.rows_per_commit()) + || preparation.rows_per_commit() > fixture.data.rows_per_table + { + diagnostics.push(Diagnostic::error( + "invalid_preparation_rows", "fixture.preparation.rows_per_commit", + format!("rows_per_commit must be in 1..={MAX_PREPARATION_ROWS_PER_COMMIT} and no greater than rows_per_table"), + )); + } + if fixture.state.aging != Aging::SmallCommits + || fixture.state.deletion_history != DeletionHistory::ReversibleUpdates + || fixture.state.compaction_recency != CompactionRecency::NotOptimized + || !fixture.state.indexes.is_empty() + { + diagnostics.push(Diagnostic::error( + "preparation_state_mismatch", "fixture.state", + "reversible-updates-v1 requires small-commits aging, reversible-updates deletion history, not-optimized compaction, and indexes: []", + )); + } + } else if fixture.state.deletion_history == DeletionHistory::ReversibleUpdates { + diagnostics.push(Diagnostic::error( + "missing_preparation", + "fixture.preparation", + "reversible-updates deletion history requires its preparation recipe", + )); + } + if fixture.builder.kind == FixtureBuilderKind::SyntheticBranchMerge + && fixture.builder.version == SYNTHETIC_BRANCH_MERGE_BUILDER_VERSION + && fixture.state.compaction_recency == CompactionRecency::Optimized + { + diagnostics.push(Diagnostic::error( + "impossible_optimized_index_state", + "fixture.state.compaction_recency", + "synthetic-branch-merge builder v3 cannot truthfully declare optimized state because OmniGraph optimization materializes indexes outside this builder's exact inventory contract; use not-optimized", + )); + } +} + +fn validate_indexes( + column_shape: ColumnShape, + indexes: &[IndexSpec], + diagnostics: &mut Vec, +) { + let mut seen = std::collections::BTreeSet::new(); + for (index, spec) in indexes.iter().enumerate() { + if spec.table.trim().is_empty() { + diagnostics.push(Diagnostic::error( + "empty_index_table", + format!("fixture.state.indexes[{index}].table"), + "index table must not be empty", + )); + } + if spec.column.trim().is_empty() { + diagnostics.push(Diagnostic::error( + "empty_index_column", + format!("fixture.state.indexes[{index}].column"), + "index column must not be empty", + )); + } + if !seen.insert((&spec.table, &spec.column, spec.kind)) { + diagnostics.push(Diagnostic::error( + "duplicate_index", + format!("fixture.state.indexes[{index}]"), + format!( + "duplicate {:?} index on {}.{}; freshness is one state of one index", + spec.kind, spec.table, spec.column + ), + )); + } + if column_shape == ColumnShape::Scalars && spec.kind == IndexKind::Ann { + diagnostics.push(Diagnostic::error( + "impossible_index_inventory", + format!("fixture.state.indexes[{index}].kind"), + "ANN indexes require a vector column shape; this case declares column_shape: scalars", + )); + } + } +} + +fn validate_cache_condition(condition: &CacheCondition, diagnostics: &mut Vec) { + let ProcessLifecycle::FreshPerRepetition = condition.process; + if condition.iterations > MAX_WARMUP_ITERATIONS { + diagnostics.push(Diagnostic::error( + "warmup_iteration_budget_exceeded", + "environment.cache_condition.iterations", + format!("warm-up iterations must be <= {MAX_WARMUP_ITERATIONS}"), + )); + } + match condition.engine { + EnginePreparation::PreparationOnly => { + if condition.page_cache != PageCacheCondition::Uncontrolled + || condition.program != WarmupProgram::None + || condition.iterations != 0 + { + diagnostics.push(Diagnostic::error( + "invalid_preparation_only_cache_condition", + "environment.cache_condition", + "preparation-only requires page_cache: uncontrolled, program: none, and iterations: 0", + )); + } + } + EnginePreparation::WarmedByProgram | EnginePreparation::ReopenedAfterProgram => { + if condition.page_cache != PageCacheCondition::ProgramConditioned + || condition.program != WarmupProgram::BranchMergeReadSetV1 + || condition.iterations == 0 + { + diagnostics.push(Diagnostic::error( + "invalid_programmed_cache_condition", + "environment.cache_condition", + "warmed-by-program and reopened-after-program require page_cache: program-conditioned, a named program, and iterations >= 1", + )); + } + } + } +} + +fn valid_sha256_image_digest(value: &str) -> bool { + let Some(hex) = value.strip_prefix("sha256:") else { + return false; + }; + hex.len() == 64 + && hex + .bytes() + .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) +} + +fn validate_backend_protocol(case: &CaseV1, diagnostics: &mut Vec) { + let environment = &case.environment; + let protocol = &case.protocol; + if let Some(deadline_seconds) = protocol.deadline_seconds { + if !(1..=MAX_DEADLINE_SECONDS).contains(&deadline_seconds) { + diagnostics.push(Diagnostic::error( + "invalid_deadline", + "protocol.deadline_seconds", + format!("deadline_seconds must be null or in 1..={MAX_DEADLINE_SECONDS}"), + )); + } + } + if protocol.schedule != Schedule::Manual { + diagnostics.push(Diagnostic::error( + "unsupported_automatic_schedule", + "protocol.schedule", + "branch-merge-v1 is unscheduled and must use the manual schedule", + )); + } + if protocol.attribution == Attribution::PerPhase && environment.execution != Execution::Embedded + { + diagnostics.push(Diagnostic::error( + "unavailable_phase_attribution", + "protocol.attribution", + "per-phase attribution is currently available only for embedded execution", + )); + } + match &environment.backend { + Backend::LocalFs { filesystem, .. } => { + if environment.network_position != NetworkPosition::SameHost { + diagnostics.push(Diagnostic::error( + "invalid_local_network_position", + "environment.network_position", + "local-fs requires network_position: same-host", + )); + } + if !matches!( + protocol.reset, + ResetMode::PlainCopy | ResetMode::LocalClonefile + ) { + diagnostics.push(Diagnostic::error( + "invalid_local_reset", + "protocol.reset", + "local-fs requires reset: plain-copy or local-clonefile", + )); + } + if protocol.reset == ResetMode::LocalClonefile && *filesystem != LocalFilesystem::Apfs { + diagnostics.push(Diagnostic::error( + "invalid_clonefile_filesystem", + "protocol.reset", + "local-clonefile is the APFS clonefile reset; other filesystems must use plain-copy", + )); + } + } + Backend::S3 { + implementation, + implementation_version, + region, + storage_class, + versioning, + image_digest, + } => { + for (path, value) in [ + ( + "environment.backend.implementation_version", + implementation_version, + ), + ("environment.backend.region", region), + ("environment.backend.storage_class", storage_class), + ] { + if value.trim().is_empty() { + diagnostics.push(Diagnostic::error( + "incomplete_s3_identity", + path, + "S3 backend identity fields must not be empty", + )); + } + } + if *implementation == S3Implementation::AwsS3 + && environment.network_position == NetworkPosition::SameHost + { + diagnostics.push(Diagnostic::error( + "invalid_aws_s3_network_position", + "environment.network_position", + "AWS S3 requires network_position: same-region or remote; same-host is reserved for local compatible stores", + )); + } + if protocol.reset != ResetMode::S3Versioning { + diagnostics.push(Diagnostic::error( + "invalid_s3_reset", + "protocol.reset", + "S3 requires reset: s3-versioning", + )); + } + if *versioning != S3Versioning::Enabled { + diagnostics.push(Diagnostic::error( + "s3_versioning_required", + "environment.backend.versioning", + "s3-versioning reset requires bucket versioning to be enabled", + )); + } + match implementation { + S3Implementation::AwsS3 => { + if image_digest.is_some() { + diagnostics.push(Diagnostic::error( + "forbidden_aws_s3_image_digest", + "environment.backend.image_digest", + "AWS S3 is a managed service identity and must not declare image_digest", + )); + } + } + S3Implementation::Minio | S3Implementation::Rustfs => match image_digest { + None => diagnostics.push(Diagnostic::error( + "missing_s3_image_digest", + "environment.backend.image_digest", + "MinIO and RustFS backend identities require an image_digest", + )), + Some(digest) if !valid_sha256_image_digest(digest) => { + diagnostics.push(Diagnostic::error( + "invalid_s3_image_digest", + "environment.backend.image_digest", + "image_digest must be exactly lowercase sha256:<64hex>", + )); + } + Some(_) => {} + }, + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const VALID: &str = r#" +version: 1 +id: m3-n100k-d50-warm +scenario: branch-merge-v1 +fixture: + builder: + kind: synthetic-branch-merge + version: 3 + seed: 0 + data: + provenance: synthetic + tables: 8 + rows_per_table: 100000 + payload_bytes: 64 + column_shape: scalars + topology_skew: uniform + state: + aging: bulk-loaded + indexes: [] + deletion_history: none + compaction_recency: not-optimized + history_depth: 1 +workload: + delta_rows_per_side: 50 + diverged_tables: 4 + arrival: unscheduled-single-shot + clients: 1 + read_write_mix: write-heavy + contention: distinct-key +environment: + backend: + kind: local-fs + filesystem: apfs + storage_class: nvme-ssd + network_position: same-host + execution: embedded + cache_condition: + process: fresh-per-repetition + engine: warmed-by-program + page_cache: program-conditioned + program: branch-merge-read-set-v1 + iterations: 1 +protocol: + deadline_seconds: 60 + attribution: per-phase + schedule: manual + reset: plain-copy + timer: monotonic +"#; + + fn valid() -> ValidatedCase { + parse_case(VALID).into_result().unwrap() + } + + fn s3_case( + implementation: &str, + implementation_version: &str, + versioning: &str, + image_digest: Option<&str>, + ) -> String { + let image = image_digest + .map(|digest| format!("\n image_digest: {digest}")) + .unwrap_or_default(); + VALID + .replace( + " backend:\n kind: local-fs\n filesystem: apfs\n storage_class: nvme-ssd", + &format!( + " backend:\n kind: s3\n implementation: {implementation}\n implementation_version: {implementation_version}\n region: us-east-1\n storage_class: standard\n versioning: {versioning}{image}" + ), + ) + .replace("network_position: same-host", "network_position: same-region") + .replace("reset: plain-copy", "reset: s3-versioning") + } + + #[test] + fn parses_strict_v1_and_derives_full_distinct_digests() { + let case = valid(); + assert_eq!(case.point_id.len(), 64); + assert_eq!(case.case_digest.len(), 64); + assert_ne!(case.point_id, case.case_digest); + assert!(case.point_name.ends_with(&case.point_id[..12])); + } + + #[test] + fn absent_preparation_preserves_existing_canonical_point_and_case_bytes() { + let case = parse_case(include_str!( + "../../tests/fixtures/legacy/branch-merge-d50-process-cold-xfs.case-v1.yaml" + )) + .into_result() + .unwrap(); + assert_eq!( + case.point_id, + "3a79a396ccb95f383370f55665136396ed8c83636b3cd08648eb3290c859bc33" + ); + assert_eq!( + case.case_digest, + "0f16aa99402d2359b934cdc3ac478a56bac46ec8ed245662c4e7ea9ce3ff3e7a" + ); + let bytes = serde_json::to_string(&case.definition).unwrap(); + assert!(!bytes.contains("\"preparation\":")); + assert_eq!( + serde_json::from_str::(&bytes).unwrap(), + case.definition + ); + } + + #[test] + fn reversible_preparation_is_strict_bounded_and_identity_bearing() { + let source = VALID.replace("fixture:\n", "fixture:\n preparation: { kind: reversible-updates-v1, additional_commits: 64, rows_per_commit: 7, seed: 42, maintenance: none }\n") + .replace("aging: bulk-loaded", "aging: small-commits") + .replace("deletion_history: none", "deletion_history: reversible-updates") + .replace("history_depth: 1", "history_depth: 277"); + let aged = parse_case(&source).into_result().unwrap(); + assert_eq!( + crate::branch_merge::BranchMergePlan::try_from(&aged) + .unwrap() + .preflight() + .unwrap() + .expected_history_depth, + 277 + ); + for (from, to) in [ + ("additional_commits: 64", "additional_commits: 2"), + ("rows_per_commit: 7", "rows_per_commit: 1"), + ("seed: 42", "seed: 43"), + ] { + let other = parse_case(&source.replace(from, to)).into_result().unwrap(); + assert_ne!(aged.point_id, other.point_id); + } + for (from, to) in [ + ("additional_commits: 64", "additional_commits: 0"), + ("additional_commits: 64", "additional_commits: 3"), + ("additional_commits: 64", "additional_commits: 10002"), + ("rows_per_commit: 7", "rows_per_commit: 0"), + ("rows_per_commit: 7", "rows_per_commit: 4097"), + ("rows_per_table: 100000", "rows_per_table: 6"), + ("reversible-updates-v1", "reversible-updates-v2"), + ("maintenance: none", "maintenance: optimize"), + (", maintenance: none", ""), + (", seed: 42", ""), + ("maintenance: none", "maintenance: none, typo: true"), + ("aging: small-commits", "aging: bulk-loaded"), + ( + "deletion_history: reversible-updates", + "deletion_history: none", + ), + ] { + assert!( + parse_case(&source.replace(from, to)).into_result().is_err(), + "accepted {to}" + ); + } + let without_recipe = VALID.replace( + "deletion_history: none", + "deletion_history: reversible-updates", + ); + assert!(parse_case(&without_recipe).into_result().is_err()); + } + + #[test] + fn case_id_and_yaml_format_do_not_change_point_identity() { + let first = valid(); + let reordered = VALID + .replace("id: m3-n100k-d50-warm", "id: another-id") + .replace( + "rows_per_table: 100000\n payload_bytes: 64", + "payload_bytes: 64\n rows_per_table: 100000", + ) + .replace( + "version: 1\nid:", + "# formatting is not identity\nversion: 1\nid:", + ); + let second = parse_case(&reordered).into_result().unwrap(); + assert_eq!(first.point_id, second.point_id); + assert_ne!(first.case_digest, second.case_digest); + } + + #[test] + fn every_typed_identity_change_moves_the_point_id() { + let first = valid(); + let changed = VALID.replace("payload_bytes: 64", "payload_bytes: 65"); + let second = parse_case(&changed).into_result().unwrap(); + assert_ne!(first.point_id, second.point_id); + } + + #[test] + fn complete_data_and_workload_factors_are_point_identity() { + let base = valid().definition; + let base_id = typed_sha256(&PointIdentityV1::from(&base)).unwrap(); + + let mut topology = base.clone(); + topology.fixture.data.topology_skew = TopologySkew::PowerLaw; + assert_ne!( + base_id, + typed_sha256(&PointIdentityV1::from(&topology)).unwrap() + ); + + let mut mix = base.clone(); + mix.workload.read_write_mix = ReadWriteMix::Balanced; + assert_ne!(base_id, typed_sha256(&PointIdentityV1::from(&mix)).unwrap()); + + let mut contention = base; + contention.workload.contention = Contention::SameKey; + assert_ne!( + base_id, + typed_sha256(&PointIdentityV1::from(&contention)).unwrap() + ); + } + + #[test] + fn branch_merge_requires_supported_complete_factor_levels() { + for (from, to, code) in [ + ( + "topology_skew: uniform", + "topology_skew: power-law", + "unsupported_branch_merge_topology", + ), + ( + "read_write_mix: write-heavy", + "read_write_mix: balanced", + "unsupported_branch_merge_read_write_mix", + ), + ( + "contention: distinct-key", + "contention: same-key", + "unsupported_branch_merge_contention", + ), + ] { + assert!( + parse_case(&VALID.replace(from, to)) + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == code), + "missing {code}" + ); + } + } + + #[test] + fn unknown_fields_and_versions_fail_closed() { + let unknown = VALID.replace("version: 1", "version: 1\nunknown: true"); + assert_eq!( + parse_case(&unknown).diagnostics[0].code, + "invalid_case_yaml" + ); + let future = VALID.replace("version: 1", "version: 2"); + assert_eq!( + parse_case(&future).diagnostics[0].code, + "unsupported_case_version" + ); + let old_builder = + VALID.replace(" version: 3\n seed: 0", " version: 2\n seed: 0"); + assert_eq!( + parse_case(&old_builder).diagnostics[0].code, + "unsupported_builder_version" + ); + let future_builder = + VALID.replace(" version: 3\n seed: 0", " version: 4\n seed: 0"); + assert_eq!( + parse_case(&future_builder).diagnostics[0].code, + "unsupported_builder_version" + ); + let duplicate = VALID.replace("version: 1", "version: 1\nversion: 1"); + assert_eq!( + parse_case(&duplicate).diagnostics[0].code, + "invalid_case_yaml" + ); + let backend_unknown = + VALID.replace("kind: local-fs", "kind: local-fs\n endpoint: surprise"); + assert_eq!( + parse_case(&backend_unknown).diagnostics[0].code, + "invalid_case_yaml" + ); + } + + #[test] + fn index_inventory_is_normalized_before_identity_and_duplicate_checks() { + let first_yaml = VALID.replace( + "indexes: []", + "indexes:\n - { table: n0, column: id, kind: btree, freshness: optimized }\n - { table: n1, column: name, kind: fts, freshness: rows-stale }", + ); + let second_yaml = first_yaml.replace( + " - { table: n0, column: id, kind: btree, freshness: optimized }\n - { table: n1, column: name, kind: fts, freshness: rows-stale }", + " - { table: n1, column: name, kind: fts, freshness: rows-stale }\n - { table: n0, column: id, kind: btree, freshness: optimized }", + ); + let first = parse_case(&first_yaml).into_result().unwrap(); + let second = parse_case(&second_yaml).into_result().unwrap(); + assert_eq!(first.point_id, second.point_id); + assert_eq!(first.case_digest, second.case_digest); + + let padded_yaml = first_yaml + .replace("table: n0", "table: ' n0 '") + .replace("column: id", "column: ' id '"); + let padded = parse_case(&padded_yaml).into_result().unwrap(); + assert_eq!(first.point_id, padded.point_id); + assert_eq!(first.case_digest, padded.case_digest); + + let duplicate = first_yaml.replace( + " - { table: n1, column: name, kind: fts, freshness: rows-stale }", + " - { table: n0, column: id, kind: btree, freshness: rows-stale }", + ); + assert!( + parse_case(&duplicate) + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "duplicate_index") + ); + + let padded_duplicate = first_yaml.replace( + " - { table: n1, column: name, kind: fts, freshness: rows-stale }", + " - { table: ' n0 ', column: ' id ', kind: btree, freshness: rows-stale }", + ); + assert!( + parse_case(&padded_duplicate) + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "duplicate_index") + ); + + let impossible = VALID.replace( + "indexes: []", + "indexes:\n - { table: n0, column: embedding, kind: ann, freshness: optimized }", + ); + assert!( + parse_case(&impossible) + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "impossible_index_inventory") + ); + } + + #[test] + fn builder_v3_rejects_optimized_fixture_state_for_any_index_inventory() { + let optimized = VALID.replace( + "compaction_recency: not-optimized", + "compaction_recency: optimized", + ); + let partial_inventory = optimized.replace( + "indexes: []", + "indexes:\n - { table: n0, column: id, kind: btree, freshness: optimized }", + ); + for yaml in [optimized, partial_inventory] { + let outcome = parse_case(&yaml); + assert!(!outcome.ok); + assert!(outcome.value.is_none()); + assert!(outcome.diagnostics.iter().any(|diagnostic| { + diagnostic.code == "impossible_optimized_index_state" + && diagnostic.path == "fixture.state.compaction_recency" + })); + } + } + + #[test] + fn bounds_and_structured_index_semantics_are_checked_together() { + let invalid = VALID + .replace("rows_per_table: 100000", "rows_per_table: 1") + .replace("diverged_tables: 4", "diverged_tables: 9") + .replace( + "indexes: []", + "indexes:\n - { table: '', column: id, kind: btree, freshness: optimized }", + ); + let codes: Vec<_> = parse_case(&invalid) + .diagnostics + .into_iter() + .map(|diagnostic| diagnostic.code) + .collect(); + assert!(codes.contains(&"invalid_diverged_tables".to_string())); + assert!(codes.contains(&"empty_index_table".to_string())); + } + + #[test] + fn builder_v3_requires_balanced_node_edge_tables_and_edge_divergence() { + for (yaml, code) in [ + ( + VALID.replace("tables: 8", "tables: 1"), + "invalid_graph_table_mix", + ), + ( + VALID.replace("tables: 8", "tables: 7"), + "invalid_graph_table_mix", + ), + ( + VALID.replace("diverged_tables: 4", "diverged_tables: 5"), + "invalid_diverged_tables", + ), + ] { + assert!( + parse_case(&yaml) + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == code), + "missing {code} for {yaml}" + ); + } + } + + #[test] + fn fixture_scale_is_bounded_before_a_runner_sees_the_plan() { + let oversized = VALID + .replace("tables: 8", "tables: 10001") + .replace("rows_per_table: 100000", "rows_per_table: 1000000000") + .replace("payload_bytes: 64", "payload_bytes: 67108864") + .replace("history_depth: 1", "history_depth: 1000001"); + let codes: Vec<_> = parse_case(&oversized) + .diagnostics + .into_iter() + .map(|diagnostic| diagnostic.code) + .collect(); + assert!(codes.contains(&"invalid_table_count".to_string())); + assert!(codes.contains(&"fixture_row_budget_exceeded".to_string())); + assert!(codes.contains(&"invalid_history_depth".to_string())); + + let oversized_payload = VALID + .replace("rows_per_table: 100000", "rows_per_table: 1000000000") + .replace("payload_bytes: 64", "payload_bytes: 67108864"); + assert!( + parse_case(&oversized_payload) + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "fixture_payload_budget_exceeded") + ); + } + + #[test] + fn cache_condition_is_typed_cross_validated_and_identity_bearing() { + let process_cold = VALID + .replace("engine: warmed-by-program", "engine: preparation-only") + .replace( + "page_cache: program-conditioned", + "page_cache: uncontrolled", + ) + .replace("program: branch-merge-read-set-v1", "program: none") + .replace("iterations: 1", "iterations: 0"); + let process_cold = parse_case(&process_cold).into_result().unwrap(); + assert!(process_cold.point_name.contains("process-cold")); + assert_ne!(valid().point_id, process_cold.point_id); + + let post_reopen = VALID.replace( + "engine: warmed-by-program", + "engine: reopened-after-program", + ); + let post_reopen = parse_case(&post_reopen).into_result().unwrap(); + assert!(post_reopen.point_name.contains("post-reopen")); + assert_ne!(valid().point_id, post_reopen.point_id); + + let two_iterations = parse_case(&VALID.replace("iterations: 1", "iterations: 2")) + .into_result() + .unwrap(); + assert_ne!(valid().point_id, two_iterations.point_id); + + let invalid = VALID.replace("engine: warmed-by-program", "engine: preparation-only"); + assert_eq!( + parse_case(&invalid).diagnostics[0].code, + "invalid_preparation_only_cache_condition" + ); + let invalid_warm_page_cache = VALID.replace( + "page_cache: program-conditioned", + "page_cache: uncontrolled", + ); + assert_eq!( + parse_case(&invalid_warm_page_cache).diagnostics[0].code, + "invalid_programmed_cache_condition" + ); + let false_page_cache_claim = VALID.replace( + "page_cache: program-conditioned", + "page_cache: witnessed-evicted", + ); + assert_eq!( + parse_case(&false_page_cache_claim).diagnostics[0].code, + "invalid_case_yaml" + ); + let unsupported = VALID.replace( + "program: branch-merge-read-set-v1", + "program: invented-warmup", + ); + assert_eq!( + parse_case(&unsupported).diagnostics[0].code, + "invalid_case_yaml" + ); + + let unbounded = VALID.replace("iterations: 1", "iterations: 1001"); + assert!( + parse_case(&unbounded) + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "warmup_iteration_budget_exceeded") + ); + } + + #[test] + fn backend_reset_and_identity_semantics_are_checked() { + let invalid = s3_case("aws-s3", "''", "disabled", None) + .replace("reset: s3-versioning", "reset: plain-copy"); + let codes: Vec<_> = parse_case(&invalid) + .diagnostics + .into_iter() + .map(|diagnostic| diagnostic.code) + .collect(); + assert!(codes.contains(&"incomplete_s3_identity".to_string())); + assert!(codes.contains(&"invalid_s3_reset".to_string())); + assert!(codes.contains(&"s3_versioning_required".to_string())); + + let invalid_clonefile = VALID + .replace("filesystem: apfs", "filesystem: ext4") + .replace("reset: plain-copy", "reset: local-clonefile"); + assert!( + parse_case(&invalid_clonefile) + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "invalid_clonefile_filesystem") + ); + } + + #[test] + fn deadline_is_explicit_bounded_or_none_and_remains_identity() { + let bounded = valid(); + let none = parse_case(&VALID.replace("deadline_seconds: 60", "deadline_seconds: null")) + .into_result() + .unwrap(); + assert_eq!(none.definition.protocol.deadline_seconds, None); + assert_eq!( + serde_json::to_value(&none.identity).unwrap()["protocol"]["deadline_seconds"], + serde_json::Value::Null + ); + assert_ne!(bounded.point_id, none.point_id); + + let thirty = parse_case(&VALID.replace("deadline_seconds: 60", "deadline_seconds: 30")) + .into_result() + .unwrap(); + assert_ne!(bounded.point_id, thirty.point_id); + + for seconds in [0, MAX_DEADLINE_SECONDS + 1] { + assert!( + parse_case(&VALID.replace( + "deadline_seconds: 60", + &format!("deadline_seconds: {seconds}") + )) + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "invalid_deadline") + ); + } + + let missing = VALID.replace(" deadline_seconds: 60\n", ""); + assert_eq!( + parse_case(&missing).diagnostics[0].code, + "invalid_case_yaml" + ); + } + + #[test] + fn aws_and_image_pinned_compatible_s3_identities_are_typed() { + let aws = parse_case(&s3_case("aws-s3", "managed", "enabled", None)) + .into_result() + .unwrap(); + let digest = format!("sha256:{}", "a".repeat(64)); + let minio = parse_case(&s3_case("minio", "release-1", "enabled", Some(&digest))) + .into_result() + .unwrap(); + assert_ne!(aws.point_id, minio.point_id); + + let same_host_minio = s3_case("minio", "release-1", "enabled", Some(&digest)).replace( + "network_position: same-region", + "network_position: same-host", + ); + assert!(parse_case(&same_host_minio).ok); + } + + #[test] + fn s3_identity_strings_are_normalized_before_validation_and_hashing() { + let digest = format!("sha256:{}", "a".repeat(64)); + let canonical = parse_case(&s3_case("minio", "release-1", "enabled", Some(&digest))) + .into_result() + .unwrap(); + let padded_yaml = s3_case("minio", "' release-1 '", "enabled", Some(&digest)) + .replace("region: us-east-1", "region: ' us-east-1 '") + .replace("storage_class: standard", "storage_class: ' standard '"); + let padded = parse_case(&padded_yaml).into_result().unwrap(); + + assert_eq!(canonical.point_id, padded.point_id); + assert_eq!(canonical.case_digest, padded.case_digest); + let Backend::S3 { + implementation_version, + region, + storage_class, + .. + } = padded.definition.environment.backend + else { + panic!("expected S3 backend"); + }; + assert_eq!(implementation_version, "release-1"); + assert_eq!(region, "us-east-1"); + assert_eq!(storage_class, "standard"); + } + + #[test] + fn compatible_s3_image_digest_rules_fail_closed() { + let missing = parse_case(&s3_case("minio", "release-1", "enabled", None)); + assert!( + missing + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "missing_s3_image_digest") + ); + + let malformed = format!("sha256:{}", "A".repeat(64)); + let malformed = parse_case(&s3_case("rustfs", "release-1", "enabled", Some(&malformed))); + assert!( + malformed + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "invalid_s3_image_digest") + ); + + let forbidden = format!("sha256:{}", "b".repeat(64)); + let forbidden = parse_case(&s3_case("aws-s3", "managed", "enabled", Some(&forbidden))); + assert!( + forbidden + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "forbidden_aws_s3_image_digest") + ); + } +} diff --git a/crates/omnigraph-bench/src/legacy/mod.rs b/crates/omnigraph-bench/src/legacy/mod.rs new file mode 100644 index 000000000..5c605dd45 --- /dev/null +++ b/crates/omnigraph-bench/src/legacy/mod.rs @@ -0,0 +1,3 @@ +//! Historical branch-merge-v1 definitions and byte-compatible archive validation. +pub mod case; +pub mod suite; diff --git a/crates/omnigraph-bench/src/legacy/suite.rs b/crates/omnigraph-bench/src/legacy/suite.rs new file mode 100644 index 000000000..0b2ea32db --- /dev/null +++ b/crates/omnigraph-bench/src/legacy/suite.rs @@ -0,0 +1,577 @@ +use std::collections::{BTreeMap, BTreeSet}; +use std::fs; +use std::path::{Path, PathBuf}; + +use serde::{Deserialize, Serialize}; + +use crate::SUITE_FORMAT_VERSION; +use crate::legacy::case::{ValidatedCase, load_case}; +use crate::model::{ + Diagnostic, ValidationOutcome, declared_version, read_yaml_file, strict_yaml, valid_kebab_id, +}; + +pub(crate) const MAX_SUITE_RUNS: usize = 10_000; +pub(crate) const MAX_REPETITIONS_PER_CASE: u32 = 10_000; +pub(crate) const MAX_TOTAL_REPETITIONS: u64 = 100_000; + +/// A V1 suite groups immutable case definitions and owns sample quantity. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct SuiteV1 { + pub version: u32, + pub name: String, + pub runs: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct SuiteRunV1 { + pub case: PathBuf, + pub repetitions: u32, +} + +/// One resolved suite entry. Repetitions remain visibly outside the case. +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct ResolvedRun { + pub case_path: PathBuf, + pub repetitions: u32, + pub case: ValidatedCase, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct ResolvedSuite { + pub definition: SuiteV1, + pub suite_path: PathBuf, + pub runs: Vec, +} + +/// Parse and structurally validate suite-v1 YAML without reading its cases. +pub fn parse_suite(source: &str) -> ValidationOutcome { + let version = match declared_version(source, "suite") { + Ok(version) => version, + Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), + }; + if version != SUITE_FORMAT_VERSION { + return ValidationOutcome::failure(vec![Diagnostic::error( + "unsupported_suite_version", + "version", + format!( + "unsupported suite version {version}; this build supports version {SUITE_FORMAT_VERSION}" + ), + )]); + } + let suite: SuiteV1 = match strict_yaml(source, "suite") { + Ok(suite) => suite, + Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), + }; + validate_suite(suite) +} + +/// Validate suite-owned facts. Cross-case uniqueness is checked by +/// [`load_suite`] after relative references resolve. +pub fn validate_suite(suite: SuiteV1) -> ValidationOutcome { + let mut diagnostics = Vec::new(); + if suite.version != SUITE_FORMAT_VERSION { + diagnostics.push(Diagnostic::error( + "unsupported_suite_version", + "version", + format!( + "unsupported suite version {}; this build supports version {SUITE_FORMAT_VERSION}", + suite.version + ), + )); + } + if !valid_kebab_id(&suite.name) || suite.name.len() > 128 { + diagnostics.push(Diagnostic::error( + "invalid_suite_name", + "name", + "suite name must be 1..=128 characters of kebab-case ASCII ([a-z0-9]+(?:-[a-z0-9]+)*)", + )); + } + if suite.runs.is_empty() { + diagnostics.push(Diagnostic::error( + "empty_suite", + "runs", + "suite must reference at least one case", + )); + } + if suite.runs.len() > MAX_SUITE_RUNS { + diagnostics.push(Diagnostic::error( + "suite_run_budget_exceeded", + "runs", + format!("suite may contain at most {MAX_SUITE_RUNS} runs"), + )); + } + let mut declared_paths = BTreeSet::new(); + let mut total_repetitions = 0_u64; + for (index, run) in suite.runs.iter().enumerate() { + let path = format!("runs[{index}]"); + if run.case.as_os_str().is_empty() { + diagnostics.push(Diagnostic::error( + "empty_case_path", + format!("{path}.case"), + "case path must not be empty", + )); + } else if run.case.is_absolute() { + diagnostics.push(Diagnostic::error( + "absolute_case_path", + format!("{path}.case"), + "case path must be relative to the suite file", + )); + } + if !declared_paths.insert(run.case.clone()) { + diagnostics.push(Diagnostic::error( + "duplicate_case_path", + format!("{path}.case"), + format!( + "case path '{}' is listed more than once", + run.case.display() + ), + )); + } + if !(1..=MAX_REPETITIONS_PER_CASE).contains(&run.repetitions) { + diagnostics.push(Diagnostic::error( + "invalid_repetitions", + format!("{path}.repetitions"), + format!("repetitions must be in 1..={MAX_REPETITIONS_PER_CASE}"), + )); + } + total_repetitions += u64::from(run.repetitions); + } + if total_repetitions > MAX_TOTAL_REPETITIONS { + diagnostics.push(Diagnostic::error( + "suite_repetition_budget_exceeded", + "runs", + format!( + "suite requests {total_repetitions} repetitions; the per-plan limit is {MAX_TOTAL_REPETITIONS}" + ), + )); + } + if diagnostics.is_empty() { + ValidationOutcome::success(suite) + } else { + ValidationOutcome::failure(diagnostics) + } +} + +/// Load a suite and all referenced case files from one benchmark catalog. +/// +/// The suite must be directly inside `/suites`. Case references remain +/// relative to the suite file, but their canonical targets must stay inside +/// `/cases`. Canonical paths, human case ids, and full point ids must +/// each be unique. +pub fn load_suite(path: &Path) -> ValidationOutcome { + let (suite_path, cases_root) = match resolve_catalog_paths(path) { + Ok(paths) => paths, + Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), + }; + let source = match read_yaml_file(&suite_path, "suite") { + Ok(source) => source, + Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), + }; + let definition = match parse_suite(&source).into_result() { + Ok(suite) => suite, + Err(diagnostics) => return ValidationOutcome::failure(diagnostics), + }; + let suite_dir = suite_path + .parent() + .expect("a canonical file path has a parent"); + let mut diagnostics = Vec::new(); + let mut runs = Vec::with_capacity(definition.runs.len()); + let mut source_indices = Vec::with_capacity(definition.runs.len()); + let mut canonical_paths: BTreeMap = BTreeMap::new(); + + for (index, run) in definition.runs.iter().enumerate() { + let joined = suite_dir.join(&run.case); + let case_path = match fs::canonicalize(&joined) { + Ok(path) => path, + Err(error) => { + diagnostics.push(Diagnostic::error( + "case_path_error", + format!("runs[{index}].case"), + format!("could not resolve '{}': {error}", joined.display()), + )); + continue; + } + }; + if !case_path.starts_with(&cases_root) { + diagnostics.push(Diagnostic::error( + "case_outside_catalog", + format!("runs[{index}].case"), + format!( + "case resolves outside the catalog cases directory '{}': {}", + cases_root.display(), + case_path.display() + ), + )); + continue; + } + if let Some(first) = canonical_paths.insert(case_path.clone(), index) { + diagnostics.push(Diagnostic::error( + "duplicate_case_path", + format!("runs[{index}].case"), + format!( + "case resolves to the same file as runs[{first}]: {}", + case_path.display() + ), + )); + continue; + } + match load_case(&case_path).into_result() { + Ok(case) => { + source_indices.push(index); + runs.push(ResolvedRun { + case_path, + repetitions: run.repetitions, + case, + }); + } + Err(case_diagnostics) => { + diagnostics.extend(case_diagnostics.into_iter().map(|mut diagnostic| { + diagnostic.path = format!("runs[{index}].case.{}", diagnostic.path); + diagnostic + })); + } + } + } + + reject_duplicate_identity(&runs, &source_indices, &mut diagnostics); + if !diagnostics.is_empty() { + return ValidationOutcome::failure(diagnostics); + } + ValidationOutcome::success(ResolvedSuite { + definition, + suite_path, + runs, + }) +} + +fn resolve_catalog_paths(path: &Path) -> Result<(PathBuf, PathBuf), Diagnostic> { + let declared_suite_path = if path.is_absolute() { + path.to_path_buf() + } else { + std::env::current_dir() + .map_err(|error| { + Diagnostic::error( + "suite_path_error", + path.display().to_string(), + format!("could not resolve the current directory: {error}"), + ) + })? + .join(path) + }; + let declared_suites_root = declared_suite_path + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + .unwrap_or_else(|| Path::new(".")); + if declared_suites_root + .file_name() + .is_none_or(|name| name != "suites") + { + return Err(Diagnostic::error( + "suite_catalog_layout_error", + path.display().to_string(), + "suite file must be directly inside a benchmark catalog's 'suites' directory", + )); + } + let declared_catalog_root = declared_suites_root + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + .unwrap_or_else(|| Path::new(".")); + let catalog_root = canonicalize_catalog_path(declared_catalog_root, "catalog root")?; + let suites_root = canonicalize_catalog_path( + &declared_catalog_root.join("suites"), + "catalog suites directory", + )?; + let cases_root = canonicalize_catalog_path( + &declared_catalog_root.join("cases"), + "catalog cases directory", + )?; + + if suites_root.parent() != Some(catalog_root.as_path()) + || cases_root.parent() != Some(catalog_root.as_path()) + || suites_root == cases_root + { + return Err(Diagnostic::error( + "catalog_directory_escape", + catalog_root.display().to_string(), + "the catalog's 'suites' and 'cases' directories must resolve to distinct direct children of its root", + )); + } + + let suite_path = fs::canonicalize(&declared_suite_path).map_err(|error| { + Diagnostic::error( + "suite_path_error", + path.display().to_string(), + format!("could not resolve suite path: {error}"), + ) + })?; + if suite_path.parent() != Some(suites_root.as_path()) { + return Err(Diagnostic::error( + "suite_outside_catalog", + path.display().to_string(), + format!( + "suite resolves outside the catalog suites directory '{}': {}", + suites_root.display(), + suite_path.display() + ), + )); + } + + Ok((suite_path, cases_root)) +} + +fn canonicalize_catalog_path(path: &Path, label: &str) -> Result { + fs::canonicalize(path).map_err(|error| { + Diagnostic::error( + "catalog_path_error", + path.display().to_string(), + format!("could not resolve {label}: {error}"), + ) + }) +} + +fn reject_duplicate_identity( + runs: &[ResolvedRun], + source_indices: &[usize], + diagnostics: &mut Vec, +) { + debug_assert_eq!(runs.len(), source_indices.len()); + let mut ids: BTreeMap<&str, usize> = BTreeMap::new(); + let mut points: BTreeMap<&str, usize> = BTreeMap::new(); + for (loaded_index, run) in runs.iter().enumerate() { + let source_index = source_indices[loaded_index]; + if let Some(first) = ids.insert(&run.case.definition.id, source_index) { + diagnostics.push(Diagnostic::error( + "duplicate_case_id", + format!("runs[{source_index}].case"), + format!( + "case id '{}' is already used by runs[{first}]", + run.case.definition.id + ), + )); + } + if let Some(first) = points.insert(&run.case.point_id, source_index) { + diagnostics.push(Diagnostic::error( + "duplicate_point_id", + format!("runs[{source_index}].case"), + format!( + "point id '{}' is already used by runs[{first}]", + run.case.point_id + ), + )); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const CASE: &str = r#" +version: 1 +id: base-case +scenario: branch-merge-v1 +fixture: + builder: { kind: synthetic-branch-merge, version: 3, seed: 0 } + data: { provenance: synthetic, tables: 8, rows_per_table: 1000, payload_bytes: 64, column_shape: scalars, topology_skew: uniform } + state: { aging: bulk-loaded, indexes: [], deletion_history: none, compaction_recency: not-optimized, history_depth: 21 } +workload: { delta_rows_per_side: 50, diverged_tables: 4, arrival: unscheduled-single-shot, clients: 1, read_write_mix: write-heavy, contention: distinct-key } +environment: + backend: { kind: local-fs, filesystem: apfs, storage_class: nvme-ssd } + network_position: same-host + execution: embedded + cache_condition: { process: fresh-per-repetition, engine: warmed-by-program, page_cache: program-conditioned, program: branch-merge-read-set-v1, iterations: 1 } +protocol: { deadline_seconds: 60, attribution: per-phase, schedule: manual, reset: plain-copy, timer: monotonic } +"#; + + fn suite(case: &str, repetitions: u32) -> String { + format!( + "version: 1\nname: local-smoke\nruns:\n - case: {case}\n repetitions: {repetitions}\n" + ) + } + + fn catalog(root: &Path) -> (PathBuf, PathBuf) { + let cases = root.join("cases"); + let suites = root.join("suites"); + fs::create_dir_all(&cases).unwrap(); + fs::create_dir_all(&suites).unwrap(); + (cases, suites) + } + + #[test] + fn resolves_relative_cases_and_keeps_quantity_outside_identity() { + let dir = tempfile::tempdir().unwrap(); + let (cases, suites) = catalog(dir.path()); + fs::write(cases.join("base.yaml"), CASE).unwrap(); + let suite_path = suites.join("smoke.yaml"); + fs::write(&suite_path, suite("../cases/base.yaml", 5)).unwrap(); + let five = load_suite(&suite_path).into_result().unwrap(); + fs::write(&suite_path, suite("../cases/base.yaml", 20)).unwrap(); + let twenty = load_suite(&suite_path).into_result().unwrap(); + assert_eq!(five.runs[0].case.point_id, twenty.runs[0].case.point_id); + assert_eq!(five.runs[0].repetitions, 5); + assert_eq!(twenty.runs[0].repetitions, 20); + } + + #[test] + fn rejects_duplicate_paths_after_resolution() { + let dir = tempfile::tempdir().unwrap(); + let (cases, suites) = catalog(dir.path()); + fs::write(cases.join("case.yaml"), CASE).unwrap(); + let suite_path = suites.join("suite.yaml"); + fs::write( + &suite_path, + "version: 1\nname: duplicates\nruns:\n - { case: ../cases/case.yaml, repetitions: 5 }\n - { case: ../cases/./case.yaml, repetitions: 5 }\n", + ) + .unwrap(); + let outcome = load_suite(&suite_path); + assert!( + outcome + .diagnostics + .iter() + .any(|diagnostic| diagnostic.code == "duplicate_case_path") + ); + } + + #[test] + fn rejects_duplicate_case_and_point_ids_independently() { + let dir = tempfile::tempdir().unwrap(); + let (cases, suites) = catalog(dir.path()); + fs::write(cases.join("a.yaml"), CASE).unwrap(); + fs::write( + cases.join("same-id.yaml"), + CASE.replace("delta_rows_per_side: 50", "delta_rows_per_side: 51"), + ) + .unwrap(); + fs::write( + cases.join("same-point.yaml"), + CASE.replace("id: base-case", "id: another-case"), + ) + .unwrap(); + let suite_path = suites.join("suite.yaml"); + fs::write( + &suite_path, + "version: 1\nname: duplicates\nruns:\n - { case: ../cases/a.yaml, repetitions: 5 }\n - { case: ../cases/same-id.yaml, repetitions: 5 }\n - { case: ../cases/same-point.yaml, repetitions: 5 }\n", + ) + .unwrap(); + let codes: Vec<_> = load_suite(&suite_path) + .diagnostics + .into_iter() + .map(|diagnostic| diagnostic.code) + .collect(); + assert!(codes.contains(&"duplicate_case_id".to_string())); + assert!(codes.contains(&"duplicate_point_id".to_string())); + } + + #[test] + fn rejects_parent_traversal_outside_the_case_catalog() { + let dir = tempfile::tempdir().unwrap(); + let catalog_root = dir.path().join("catalog"); + let (_cases, suites) = catalog(&catalog_root); + fs::write(dir.path().join("outside.yaml"), "not: [valid").unwrap(); + let suite_path = suites.join("escape.yaml"); + fs::write(&suite_path, suite("../../outside.yaml", 5)).unwrap(); + + let outcome = load_suite(&suite_path); + + assert_eq!(outcome.diagnostics[0].code, "case_outside_catalog"); + } + + #[cfg(unix)] + #[test] + fn rejects_case_symlinks_that_escape_the_catalog() { + use std::os::unix::fs::symlink; + + let dir = tempfile::tempdir().unwrap(); + let catalog_root = dir.path().join("catalog"); + let (cases, suites) = catalog(&catalog_root); + let outside = dir.path().join("outside.yaml"); + fs::write(&outside, "not: [valid").unwrap(); + symlink(&outside, cases.join("escape.yaml")).unwrap(); + let suite_path = suites.join("escape.yaml"); + fs::write(&suite_path, suite("../cases/escape.yaml", 5)).unwrap(); + + let outcome = load_suite(&suite_path); + + assert_eq!(outcome.diagnostics[0].code, "case_outside_catalog"); + } + + #[cfg(unix)] + #[test] + fn rejects_cases_directory_symlinks_that_escape_the_catalog() { + use std::os::unix::fs::symlink; + + let dir = tempfile::tempdir().unwrap(); + let catalog_root = dir.path().join("catalog"); + let suites = catalog_root.join("suites"); + let outside_cases = dir.path().join("outside-cases"); + fs::create_dir_all(&suites).unwrap(); + fs::create_dir_all(&outside_cases).unwrap(); + fs::write(outside_cases.join("base.yaml"), CASE).unwrap(); + symlink(&outside_cases, catalog_root.join("cases")).unwrap(); + let suite_path = suites.join("escape.yaml"); + fs::write(&suite_path, suite("../cases/base.yaml", 5)).unwrap(); + + let outcome = load_suite(&suite_path); + + assert_eq!(outcome.diagnostics[0].code, "catalog_directory_escape"); + } + + #[cfg(unix)] + #[test] + fn rejects_suite_symlinks_that_escape_the_catalog() { + use std::os::unix::fs::symlink; + + let dir = tempfile::tempdir().unwrap(); + let catalog_root = dir.path().join("catalog"); + let (_cases, suites) = catalog(&catalog_root); + let outside = dir.path().join("outside-suite.yaml"); + fs::write(&outside, "not: [valid").unwrap(); + let suite_path = suites.join("escape.yaml"); + symlink(&outside, &suite_path).unwrap(); + + let outcome = load_suite(&suite_path); + + assert_eq!(outcome.diagnostics[0].code, "suite_outside_catalog"); + } + + #[test] + fn rejects_suites_without_a_catalog_layout() { + let dir = tempfile::tempdir().unwrap(); + let suite_path = dir.path().join("suite.yaml"); + fs::write(&suite_path, suite("case.yaml", 5)).unwrap(); + + let outcome = load_suite(&suite_path); + + assert_eq!(outcome.diagnostics[0].code, "suite_catalog_layout_error"); + } + + #[test] + fn suite_is_strict_versioned_and_owns_positive_repetitions() { + let unknown = suite("case.yaml", 5).replace("name:", "unknown: true\nname:"); + assert_eq!( + parse_suite(&unknown).diagnostics[0].code, + "invalid_suite_yaml" + ); + let future = suite("case.yaml", 5).replace("version: 1", "version: 2"); + assert_eq!( + parse_suite(&future).diagnostics[0].code, + "unsupported_suite_version" + ); + assert_eq!( + parse_suite(&suite("case.yaml", 0)).diagnostics[0].code, + "invalid_repetitions" + ); + assert_eq!( + parse_suite(&suite("case.yaml", MAX_REPETITIONS_PER_CASE + 1)).diagnostics[0].code, + "invalid_repetitions" + ); + } + + #[test] + fn absolute_case_paths_are_refused_before_io() { + let yaml = suite("/tmp/case.yaml", 5); + assert_eq!(parse_suite(&yaml).diagnostics[0].code, "absolute_case_path"); + } +} diff --git a/crates/omnigraph-bench/src/lib.rs b/crates/omnigraph-bench/src/lib.rs index 6602298d0..dd610b34b 100644 --- a/crates/omnigraph-bench/src/lib.rs +++ b/crates/omnigraph-bench/src/lib.rs @@ -1,24 +1,41 @@ //! Typed, versioned definitions for the OmniGraph benchmark harness. //! -//! A case describes exactly one experiment. A suite only selects checked-in -//! cases and says how many samples to collect; it cannot override experiment -//! identity. The local runner consumes those resolved plans, canonical JSON is +//! A config pairs fixture/workload GQT, expands defaults and selects experiments. +//! Each resolved case describes one experiment; sample counts remain outside +//! experiment identity. Legacy case/suite readers are retained. The local runner consumes those resolved plans, canonical JSON is //! the durable telemetry authority, and OmniGraph provides a disposable query //! projection over that archive. Cloud orchestration is a later harness slice. pub mod archive; pub mod branch_merge; pub mod case; +pub mod catalog; pub mod counting; +pub mod dataset_cache; +pub mod dataset_identity; +#[doc(hidden)] +pub mod dataset_worker; +pub mod discovery; pub mod environment; pub mod fixture_reference; #[doc(hidden)] +#[cfg(test)] pub mod fixture_worker; +pub mod gqt_case; +#[doc(hidden)] +pub mod gqt_protocol; +pub mod gqt_record; +pub mod gqt_runner; +mod gqt_supervisor; +#[doc(hidden)] +pub mod gqt_worker; +pub mod legacy; pub mod machine; pub mod model; mod preparation; pub mod projection; pub mod real_graph; +#[cfg(test)] pub mod real_graph_run; pub mod record; pub mod registered_fixture; @@ -27,10 +44,13 @@ pub mod runner; #[doc(hidden)] pub mod source_provenance; pub mod suite; +#[cfg(test)] mod supervisor; #[doc(hidden)] +#[cfg(test)] pub mod worker; #[doc(hidden)] +#[cfg(test)] pub mod worker_protocol; pub use case::{CaseV1, PointIdentityV1, ValidatedCase, load_case, parse_case, validate_case}; @@ -39,10 +59,7 @@ pub use fixture_reference::{ normalize_fixture_reference, parse_fixture_reference, }; pub use model::{Diagnostic, DiagnosticSeverity, ValidationOutcome}; -pub use runner::{ - BuildEvidence, RUNNER_OUTPUT_VERSION, RunExecution, RunOptions, RunnerError, SuiteExecution, - execute_run, execute_suite, -}; +pub use runner::{BuildEvidence, RUNNER_OUTPUT_VERSION, RunnerError}; pub use suite::{ ResolvedRun, ResolvedSuite, SuiteRunV1, SuiteV1, load_suite, parse_suite, validate_suite, }; @@ -58,3 +75,11 @@ pub const POINT_IDENTITY_VERSION: u32 = 1; /// Version of the CLI's resolved, execution-free suite-plan projection. pub const PLAN_FORMAT_VERSION: u32 = 1; + +pub use gqt_runner::{RunExecution, RunOptions, SuiteExecution, execute_run, execute_suite}; + +#[cfg(test)] +mod gqt_tests; + +#[cfg(test)] +mod catalog_tests; diff --git a/crates/omnigraph-bench/src/model.rs b/crates/omnigraph-bench/src/model.rs index fcfd3c4a1..43e6fffa6 100644 --- a/crates/omnigraph-bench/src/model.rs +++ b/crates/omnigraph-bench/src/model.rs @@ -1,4 +1,4 @@ -use std::fs::File; +use std::fs::OpenOptions; use std::io::Read; use std::path::Path; @@ -24,6 +24,16 @@ pub struct Diagnostic { pub message: String, } +impl std::fmt::Display for Diagnostic { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + formatter, + "{} at {}: {}", + self.code, self.path, self.message + ) + } +} + impl Diagnostic { pub fn error( code: impl Into, @@ -141,28 +151,51 @@ where } pub(crate) fn read_yaml_file(path: &Path, noun: &str) -> Result { - let file = File::open(path).map_err(|error| { + read_text_file(path, MAX_YAML_BYTES, noun) +} + +pub(crate) fn read_text_file( + path: &Path, + max_bytes: usize, + noun: &str, +) -> Result { + let failure = |message: String| { Diagnostic::error( format!("{noun}_read_error"), path.display().to_string(), - format!("could not open {noun} file: {error}"), + message, ) - })?; + }; + let mut options = OpenOptions::new(); + options.read(true); + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + options.custom_flags(nix::libc::O_NONBLOCK); + } + let file = options + .open(path) + .map_err(|e| failure(format!("could not open {noun} file: {e}")))?; + let metadata = file.metadata().map_err(|e| failure(e.to_string()))?; + if !metadata.is_file() { + return Err(failure(format!("{noun} must be a regular file"))); + } + if metadata.len() > max_bytes as u64 { + return Err(Diagnostic::error( + format!("{noun}_yaml_too_large"), + path.display().to_string(), + format!("{noun} must be <= {max_bytes} bytes"), + )); + } let mut source = String::new(); - file.take(MAX_YAML_BYTES as u64 + 1) + file.take(max_bytes as u64 + 1) .read_to_string(&mut source) - .map_err(|error| { - Diagnostic::error( - format!("{noun}_read_error"), - path.display().to_string(), - format!("could not read {noun} file as UTF-8: {error}"), - ) - })?; - if source.len() > MAX_YAML_BYTES { + .map_err(|e| failure(format!("could not read {noun} as UTF-8: {e}")))?; + if source.len() > max_bytes { return Err(Diagnostic::error( format!("{noun}_yaml_too_large"), path.display().to_string(), - format!("{noun} YAML must be <= {MAX_YAML_BYTES} bytes"), + format!("{noun} must be <= {max_bytes} bytes"), )); } Ok(source) diff --git a/crates/omnigraph-bench/src/projection.rs b/crates/omnigraph-bench/src/projection.rs index 0d5e357de..b5c5aed7e 100644 --- a/crates/omnigraph-bench/src/projection.rs +++ b/crates/omnigraph-bench/src/projection.rs @@ -1513,13 +1513,14 @@ fn validate_inventory(records: ArchiveRecordIter) -> Result Result= &record.invocation.invocation_id) + .is_some_and(|previous| previous >= &record.invocation().invocation_id) { return Err(ProjectionError::new( "projection_inventory_order_invalid", None, format!( "archive invocation {} is not strictly after {:?}", - record.invocation.invocation_id, previous_invocation + record.invocation().invocation_id, + previous_invocation ), )); } - previous_invocation = Some(record.invocation.invocation_id.clone()); + previous_invocation = Some(record.invocation().invocation_id.clone()); if let Some(previous) = digests.insert( receipt.record_sha256.clone(), - record.invocation.invocation_id.clone(), + record.invocation().invocation_id.clone(), ) { return Err(ProjectionError::new( "projection_record_digest_collision", None, format!( "record digest {} appears for invocations {previous} and {}", - receipt.record_sha256, record.invocation.invocation_id + receipt.record_sha256, + record.invocation().invocation_id ), )); } retained.add( std::mem::size_of::<(String, String)>() .saturating_add(receipt.record_sha256.len()) - .saturating_add(record.invocation.invocation_id.len()), + .saturating_add(record.invocation().invocation_id.len()), "record digest index", )?; @@ -1584,9 +1587,9 @@ fn validate_inventory(records: ArchiveRecordIter) -> Result MAX_INVENTORY_ENTRY_BYTES { @@ -1633,7 +1636,48 @@ fn validate_inventory(records: ArchiveRecordIter) -> Result Result { +trait ProjectionRecord { + fn point_row(&self) -> Result; + fn run_row( + &self, + receipt: &crate::archive::ArchiveReceiptV1, + ) -> Result; +} +impl ProjectionRecord for RunRecordV1 { + fn point_row(&self) -> Result { + legacy_point_row(self) + } + fn run_row(&self, r: &crate::archive::ArchiveReceiptV1) -> Result { + legacy_run_row(self, r) + } +} +impl ProjectionRecord for crate::gqt_record::AnyRunRecordV1 { + fn point_row(&self) -> Result { + match self { + Self::Legacy(r) => legacy_point_row(r), + Self::Gqt(r) => gqt_point_row(r), + } + } + fn run_row( + &self, + receipt: &crate::archive::ArchiveReceiptV1, + ) -> Result { + match self { + Self::Legacy(r) => legacy_run_row(r, receipt), + Self::Gqt(r) => gqt_run_row(r, receipt), + } + } +} +fn point_row(record: &R) -> Result { + record.point_row() +} +fn run_row( + record: &R, + receipt: &crate::archive::ArchiveReceiptV1, +) -> Result { + record.run_row(receipt) +} +fn legacy_point_row(record: &RunRecordV1) -> Result { require_sha256(&record.run.point_id, "point id")?; let run_spec_json = canonical_json(&record.run.run_spec, "run spec")?; Ok(PointRow { @@ -1645,7 +1689,7 @@ fn point_row(record: &RunRecordV1) -> Result { }) } -fn run_row( +fn legacy_run_row( record: &RunRecordV1, receipt: &crate::archive::ArchiveReceiptV1, ) -> Result { @@ -1653,7 +1697,7 @@ fn run_row( let wall = &record.measurements.wall_clock; let calls = logical_call_summaries(record)?; Ok(RunRow { - invocation_id: record.invocation.invocation_id.clone(), + invocation_id: record.invocation().invocation_id.clone(), record_sha256: receipt.record_sha256.clone(), archive_object: receipt.object_relative_path.clone(), archive_pointer: receipt.pointer_relative_path.clone(), @@ -1754,6 +1798,127 @@ fn run_row( }) } +fn gqt_point_row(record: &crate::gqt_record::GqtRunRecordV1) -> Result { + require_sha256(&record.run.point_id, "point id")?; + let run_spec_json = canonical_json(&record.run.run_spec, "run spec")?; + Ok(PointRow { + point_id: record.run.point_id.clone(), + point_name: record.run.point_name.clone(), + point_identity_version: record.run.point_identity_version, + scenario: json_string(&record.run.run_spec.scenario, "scenario")?, + run_spec_json, + }) +} + +fn gqt_run_row( + record: &crate::gqt_record::GqtRunRecordV1, + receipt: &crate::archive::ArchiveReceiptV1, +) -> Result { + let machine = &record.machine; + let wall = &record.measurements.wall_clock; + let calls = gqt_logical_call_summaries(record)?; + Ok(RunRow { + invocation_id: record.invocation().invocation_id.clone(), + record_sha256: receipt.record_sha256.clone(), + archive_object: receipt.object_relative_path.clone(), + archive_pointer: receipt.pointer_relative_path.clone(), + session_id: record.invocation.session_id.clone(), + invoked_at_unix_ms: record.invocation.invoked_at_unix_ms, + case_id: record.run.case_id.clone(), + case_digest: record.run.case_digest.clone(), + package_version: record.sut.package_version.clone(), + source_commit: record.sut.source_commit.clone(), + source_tree_dirty: record.sut.source_tree_dirty, + build_profile: record.sut.build.profile.clone(), + build_opt_level: record.sut.build.cargo_opt_level.clone(), + debug_assertions: record.sut.build.debug_assertions, + target_triple: record.sut.build.target_triple.clone(), + rustc_version: record.sut.build.rustc_version.clone(), + build_declared_release_lto: record.sut.build.declared_release_lto.clone(), + build_declared_release_codegen_units: record.sut.build.declared_release_codegen_units, + build_declared_release_strip: record.sut.build.declared_release_strip, + build_cargo_encoded_rustflags_present: record.sut.build.cargo_encoded_rustflags_present, + build_release_profile_environment_overrides_supported: record + .sut + .build + .release_profile_environment_overrides_supported, + build_effective_codegen_options_proved: record.sut.build.effective_codegen_options_proved, + worker_executable_sha256: record.sut.build.worker_executable_sha256.clone(), + sut_fingerprint: typed_json_sha256(&record.sut, "system under test")?, + sut_json: canonical_json(&record.sut, "system under test")?, + machine_fingerprint: typed_json_sha256(machine, "machine identity")?, + machine_format_version: machine.format_version, + machine_os_name: machine.os_name.clone(), + machine_os_version: machine.os_version.clone(), + machine_kernel_version: machine.kernel_version.clone(), + machine_architecture: machine.architecture.clone(), + machine_cpu_model: machine.cpu_model.clone(), + machine_logical_cores: machine.logical_cores, + machine_physical_cores: machine.physical_cores, + machine_total_memory_bytes: machine.total_memory_bytes, + machine_resource_control_json: canonical_json( + &machine.resource_control, + "machine resource control", + )?, + machine_scheduling_json: canonical_json(&machine.scheduling, "machine scheduling")?, + machine_resource_limits_json: canonical_json( + &machine.resource_limits, + "machine resource limits", + )?, + machine_label: machine.machine_label.clone(), + backend_fingerprint: typed_json_sha256(&record.backend, "backend evidence")?, + backend_json: canonical_json(&record.backend, "backend evidence")?, + fixture_manifest_sha256: typed_json_sha256(&record.fixture, "dataset manifest")?, + fixture_logical_sha256: record + .fixture + .handoff + .summary + .logical_content_sha256 + .clone(), + fixture_physical_sha256: record.fixture.handoff.physical.digest_sha256.clone(), + acquisition_status: json_string(&record.acquisition.status, "acquisition status")?, + claim_eligible: record.claim_eligible(), + terminal_failed_repetition: record + .acquisition + .terminal + .as_ref() + .map(|terminal| terminal.failed_repetition), + terminal_stage: record + .acquisition + .terminal + .as_ref() + .map(|terminal| terminal.stage.as_str().to_string()), + terminal_code: record + .acquisition + .terminal + .as_ref() + .map(|terminal| terminal.code.clone()), + requested_repetitions: record.acquisition.requested_repetitions, + observed_repetitions: record.acquisition.observed_repetitions, + min_us: wall.min_us, + p50_us: wall.p50_us, + max_us: wall.max_us, + p95_us: wall.p95_us, + p95_supported: wall.p95_supported, + wall_evidence: json_string(&wall.evidence, "wall evidence")?, + floor_multiplier_millis: record.measurements.claim_policy.floor_multiplier_millis, + lance_data_plane_logical_calls_min: calls.lance_data_plane.min, + lance_data_plane_logical_calls_p50: calls.lance_data_plane.p50, + lance_data_plane_logical_calls_max: calls.lance_data_plane.max, + control_plane_logical_calls_min: calls.control_plane.min, + control_plane_logical_calls_p50: calls.control_plane.p50, + control_plane_logical_calls_max: calls.control_plane.max, + logical_counts_presence_json: canonical_json( + &record.measurements.layer_presence.logical.counts, + "logical counts presence", + )?, + physical_counts_presence_json: canonical_json( + &record.measurements.layer_presence.physical.counts, + "physical counts presence", + )?, + }) +} + async fn load_points<'a>( db: &Session, points: impl Iterator, @@ -1786,9 +1951,9 @@ async fn load_runs(db: &Session, records: ArchiveRecordIter) -> Result<(), Proje })?; let edge_line = serialize_graph_row(&EdgeEnvelope { edge: "Measures", - id: format!("measures:{}", record.invocation.invocation_id), - from: &record.invocation.invocation_id, - to: &record.run.point_id, + id: format!("measures:{}", record.invocation().invocation_id), + from: &record.invocation().invocation_id, + to: record.point_id(), data: MeasuresProperties {}, })?; if let Some(body) = batch.push_group(&[run_line, edge_line])? { @@ -2978,6 +3143,40 @@ fn logical_call_summaries(record: &RunRecordV1) -> Result Result { + let mut lance_data_plane = Vec::with_capacity(record.measurements.raw_samples.len()); + let mut control_plane = Vec::with_capacity(record.measurements.raw_samples.len()); + for sample in &record.measurements.raw_samples { + let manifest = sum_call_counts(sample.logical_store_calls.manifest)?; + let table = sum_call_counts(sample.logical_store_calls.table)?; + lance_data_plane.push(manifest.checked_add(table).ok_or_else(|| { + ProjectionError::new( + "projection_logical_call_overflow", + None, + "per-repetition Lance data-plane logical call total does not fit u64", + ) + })?); + let control = &sample.control_store_calls; + control_plane.push(sum_u64_values( + [ + control.read_text, + control.read_text_if_exists, + control.read_text_versioned, + control.exists, + control.list_dir, + control.mutation_calls, + ], + "per-repetition control-plane logical call total", + )?); + } + Ok(LogicalCallSummaries { + lance_data_plane: summarize_nearest_rank(lance_data_plane, "Lance data-plane")?, + control_plane: summarize_nearest_rank(control_plane, "control-plane")?, + }) +} + fn sum_call_counts(counts: LogicalCallCounts) -> Result { sum_u64_values( [ @@ -3978,7 +4177,7 @@ mod tests { let record = crate::record::tests::valid_record_fixture(); let receipt = crate::archive::ArchiveReceiptV1 { archive_format_version: ARCHIVE_FORMAT_VERSION, - invocation_id: record.invocation.invocation_id.clone(), + invocation_id: record.invocation().invocation_id.clone(), record_sha256: "a".repeat(64), object_relative_path: "objects/sha256/aa/record.json".to_string(), pointer_relative_path: "invocations/01/pointer.json".to_string(), @@ -4055,7 +4254,7 @@ mod tests { let receipt = crate::archive::ArchiveReceiptV1 { archive_format_version: ARCHIVE_FORMAT_VERSION, - invocation_id: record.invocation.invocation_id.clone(), + invocation_id: record.invocation().invocation_id.clone(), record_sha256: "a".repeat(64), object_relative_path: "objects/sha256/aa/record.json".to_string(), pointer_relative_path: "invocations/01/pointer.json".to_string(), @@ -4487,7 +4686,7 @@ mod tests { assert_eq!(runs.rows.len(), 1); assert_eq!( runs.rows[0]["invocation_id"], - record.invocation.invocation_id + record.invocation().invocation_id ); assert_eq!(runs.rows[0]["record_sha256"], receipt.record_sha256); assert_eq!( diff --git a/crates/omnigraph-bench/src/real_graph.rs b/crates/omnigraph-bench/src/real_graph.rs index e7fea969a..24eeeb817 100644 --- a/crates/omnigraph-bench/src/real_graph.rs +++ b/crates/omnigraph-bench/src/real_graph.rs @@ -184,6 +184,16 @@ pub async fn observe_real_graph(root: &Path) -> RealGraphResult, +) -> RealGraphResult { + let native = (branch != "main").then_some(branch); let catalog = db.catalog(); let accepted_ir = catalog.bound_schema_ir().ok_or_else(|| { RealGraphError::new("copied graph catalog is not bound to accepted schema identity") @@ -209,11 +219,11 @@ pub async fn observe_real_graph(root: &Path) -> RealGraphResult RealGraphResult RealGraphResult RealGraphResult> { +pub(crate) fn canonical_json_bytes(value: &Value) -> RealGraphResult> { let mut bytes = Vec::new(); write_canonical_json(value, &mut bytes)?; Ok(bytes) diff --git a/crates/omnigraph-bench/src/record.rs b/crates/omnigraph-bench/src/record.rs index 6d61505ef..67bb914f8 100644 --- a/crates/omnigraph-bench/src/record.rs +++ b/crates/omnigraph-bench/src/record.rs @@ -17,11 +17,14 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use crate::branch_merge::{BranchMergePlan, TARGET_BRANCH}; -use crate::case::{ +use crate::counting::LogicalCallCounts; +use crate::legacy::case::validate_case; +use crate::legacy::case::{ Backend, CaseV1, LocalFilesystem, LocalStorageClass, PointIdentityV1, S3Implementation, S3Versioning, }; -use crate::counting::LogicalCallCounts; +use crate::legacy::suite::MAX_REPETITIONS_PER_CASE; +use crate::legacy::suite::ResolvedRun; use crate::machine::MachineIdentityV1; use crate::model::typed_sha256; use crate::reset::PHYSICAL_TREE_DIGEST_ALGORITHM; @@ -30,8 +33,7 @@ use crate::runner::{ MergeRouteObservation, PhaseObservation, RepObservation, RunExecution, VerificationObservation, validate_successful_merge_phase_topology, }; -use crate::suite::MAX_REPETITIONS_PER_CASE; -use crate::{CASE_FORMAT_VERSION, POINT_IDENTITY_VERSION, ResolvedRun, validate_case}; +use crate::{CASE_FORMAT_VERSION, POINT_IDENTITY_VERSION}; pub use crate::runner::{ FIXTURE_MANIFEST_FORMAT_VERSION, FIXTURE_VALIDATOR_VERSION, FixtureManifestV1, @@ -75,6 +77,12 @@ pub struct RunRecordV1 { } impl RunRecordV1 { + pub fn invocation(&self) -> &InvocationIdentityV1 { + &self.invocation + } + pub fn point_id(&self) -> &str { + &self.run.point_id + } /// A performance claim requires both a complete acquisition and proof of /// the effective build settings that produced the measured executable. /// Current local records deliberately lack the latter proof and therefore @@ -409,7 +417,11 @@ pub struct RecordError { } impl RecordError { - fn new(code: &'static str, path: impl Into, message: impl Into) -> Self { + pub(crate) fn new( + code: &'static str, + path: impl Into, + message: impl Into, + ) -> Self { Self { code, path: path.into(), @@ -434,41 +446,41 @@ pub type RecordResult = Result; /// Bind durable SUT identity to the exact worker build attested by the runner. pub fn sut_identity_for_execution(execution: &RunExecution) -> RecordResult { - let worker_executable_sha256 = execution - .build - .worker_executable_sha256 - .clone() - .ok_or_else(|| { - RecordError::new( - "missing_worker_attestation", - "execution.build.worker_executable_sha256", - "a durable timing record requires an attested worker executable", - ) - })?; + sut_identity_for_build(&execution.build) +} +pub(crate) fn sut_identity_for_build( + build: &crate::runner::BuildEvidence, +) -> RecordResult { + let worker_executable_sha256 = build.worker_executable_sha256.clone().ok_or_else(|| { + RecordError::new( + "missing_worker_attestation", + "build.worker_executable_sha256", + "a durable timing record requires an attested worker executable", + ) + })?; let sut = SutIdentityV1 { package_version: env!("CARGO_PKG_VERSION").to_string(), - source_commit: execution.build.source_commit.clone(), - source_tree_dirty: execution.build.source_tree_dirty, + source_commit: build.source_commit.clone(), + source_tree_dirty: build.source_tree_dirty, build: BuildIdentityV1 { - profile: execution.build.cargo_profile.clone(), - cargo_opt_level: execution.build.cargo_opt_level.clone(), - debug_assertions: execution.build.debug_assertions, - target_triple: execution.build.target_triple.clone(), - rustc_version: execution.build.rustc_version.clone(), - declared_release_lto: execution.build.declared_release_lto.clone(), - declared_release_codegen_units: execution.build.declared_release_codegen_units, - declared_release_strip: execution.build.declared_release_strip, - cargo_encoded_rustflags_present: execution.build.cargo_encoded_rustflags_present, - release_profile_environment_overrides_supported: execution - .build + profile: build.cargo_profile.clone(), + cargo_opt_level: build.cargo_opt_level.clone(), + debug_assertions: build.debug_assertions, + target_triple: build.target_triple.clone(), + rustc_version: build.rustc_version.clone(), + declared_release_lto: build.declared_release_lto.clone(), + declared_release_codegen_units: build.declared_release_codegen_units, + declared_release_strip: build.declared_release_strip, + cargo_encoded_rustflags_present: build.cargo_encoded_rustflags_present, + release_profile_environment_overrides_supported: build .release_profile_environment_overrides_supported, - effective_codegen_options_proved: execution.build.effective_codegen_options_proved, + effective_codegen_options_proved: build.effective_codegen_options_proved, worker_executable_sha256, }, engine: EngineConfigurationV1 { - feature_flags: execution.build.engine_feature_flags.clone(), - enabled_techniques: execution.build.enabled_techniques.clone(), - lance_mem_pool_size: execution.build.effective_lance_mem_pool_size.clone(), + feature_flags: build.engine_feature_flags.clone(), + enabled_techniques: build.enabled_techniques.clone(), + lance_mem_pool_size: build.effective_lance_mem_pool_size.clone(), }, }; validate_sut(&sut)?; @@ -857,7 +869,7 @@ fn local_storage_name(storage: LocalStorageClass) -> &'static str { fn validate_recorded_run_identity( recorded: &ResolvedRunIdentityV1, -) -> RecordResult { +) -> RecordResult { if recorded.point_identity_version != POINT_IDENTITY_VERSION || recorded.run_spec.identity_version != POINT_IDENTITY_VERSION || recorded.point_identity_version != recorded.run_spec.identity_version @@ -926,7 +938,7 @@ fn validate_recorded_run_identity( Ok(sealed) } -fn validate_invocation(invocation: &InvocationIdentityV1) -> RecordResult<()> { +pub(crate) fn validate_invocation(invocation: &InvocationIdentityV1) -> RecordResult<()> { let invocation_time = ulid_timestamp_ms(&invocation.invocation_id).ok_or_else(|| { RecordError::new( "invalid_invocation_id", @@ -968,7 +980,7 @@ fn validate_invocation(invocation: &InvocationIdentityV1) -> RecordResult<()> { Ok(()) } -fn validate_sut(sut: &SutIdentityV1) -> RecordResult<()> { +pub(crate) fn validate_sut(sut: &SutIdentityV1) -> RecordResult<()> { validate_text(&sut.package_version, "sut.package_version")?; if !valid_lower_hex(&sut.source_commit, &[40, 64]) { return Err(RecordError::new( @@ -1044,7 +1056,10 @@ fn validate_effective_environment_value( } } -fn validate_backend(declared: &Backend, observed: &ObservedBackendV1) -> RecordResult<()> { +pub(crate) fn validate_backend( + declared: &Backend, + observed: &ObservedBackendV1, +) -> RecordResult<()> { match (declared, observed) { ( Backend::LocalFs { @@ -1196,7 +1211,7 @@ fn validate_fixture_manifest(manifest: &FixtureManifestV1) -> RecordResult<()> { fn validate_measurements( record: &RunRecordV1, - sealed: &crate::case::ValidatedCase, + sealed: &crate::legacy::case::ValidatedCase, ) -> RecordResult<()> { let requested = record.acquisition.requested_repetitions; let observed = record.acquisition.observed_repetitions; @@ -1371,15 +1386,26 @@ fn validate_measurements( /// control mutation subcategories must remain a partitioned subset of the /// aggregate mutation counter emitted by the engine wrapper. fn validate_projected_call_totals(index: usize, sample: &RawSampleV1) -> RecordResult<()> { + validate_call_totals( + index, + sample.logical_store_calls.manifest, + sample.logical_store_calls.table, + &sample.control_store_calls, + ) +} +pub(crate) fn validate_call_totals( + index: usize, + manifest: LogicalCallCounts, + table: LogicalCallCounts, + control: &ControlCallObservation, +) -> RecordResult<()> { let sample_path = format!("measurements.raw_samples[{index}]"); let manifest = checked_lance_call_total( - sample.logical_store_calls.manifest, + manifest, &format!("{sample_path}.logical_store_calls.manifest"), )?; - let table = checked_lance_call_total( - sample.logical_store_calls.table, - &format!("{sample_path}.logical_store_calls.table"), - )?; + let table = + checked_lance_call_total(table, &format!("{sample_path}.logical_store_calls.table"))?; manifest.checked_add(table).ok_or_else(|| { RecordError::new( "logical_call_count_overflow", @@ -1388,7 +1414,6 @@ fn validate_projected_call_totals(index: usize, sample: &RawSampleV1) -> RecordR ) })?; - let control = &sample.control_store_calls; let classified_mutations = control .write_text .checked_add(control.delete) @@ -1490,7 +1515,7 @@ fn evidence_strength(repetitions: usize) -> EvidenceStrengthV1 { } } -fn v1_layer_presence() -> MeasurementLayerPresenceV1 { +pub(crate) fn v1_layer_presence() -> MeasurementLayerPresenceV1 { MeasurementLayerPresenceV1 { logical: LayerMeasurementsV1 { counts: MeasurementPresenceV1::Observed, @@ -1562,7 +1587,7 @@ fn validate_text(value: &str, path: &str) -> RecordResult<()> { Ok(()) } -fn validate_acquisition_error_code(value: &str, path: &str) -> RecordResult<()> { +pub(crate) fn validate_acquisition_error_code(value: &str, path: &str) -> RecordResult<()> { if value.is_empty() || value.len() > MAX_ACQUISITION_ERROR_CODE_BYTES || !value.is_ascii() { return Err(RecordError::new( "invalid_acquisition_error_code", @@ -1604,7 +1629,7 @@ fn validate_acquisition_error_code(value: &str, path: &str) -> RecordResult<()> Ok(()) } -fn validate_sha256(value: &str, path: &str) -> RecordResult<()> { +pub(crate) fn validate_sha256(value: &str, path: &str) -> RecordResult<()> { if !valid_lower_hex(value, &[64]) { return Err(RecordError::new( "invalid_sha256", @@ -1690,14 +1715,15 @@ fn crockford_value(byte: u8) -> Option { pub(crate) mod tests { use std::path::PathBuf; + use crate::RUNNER_OUTPUT_VERSION; use crate::branch_merge::FixturePreflight; use crate::environment::LocalEnvironmentEvidence; + use crate::legacy::case::parse_case; use crate::machine::MACHINE_IDENTITY_FORMAT_VERSION; use crate::runner::{ BuildEvidence, FixtureObservation, LogicalStoreCallObservation, WallClockSummary, test_general_merge_route, test_general_merge_stored_phases, }; - use crate::{RUNNER_OUTPUT_VERSION, parse_case}; use super::*; @@ -1940,6 +1966,15 @@ protocol: { deadline_seconds: 60, attribution: per-phase, schedule: manual, rese } /// One fully validated durable record for sibling persistence tests. + #[test] + fn legacy_archive_wrapper_matches_the_independent_legacy_serializer() { + let record = valid_record(); + let old = canonical_record_bytes(&record).unwrap(); + let wrapped = crate::gqt_record::AnyRunRecordV1::Legacy(record); + assert_eq!(crate::gqt_record::canonical_bytes(&wrapped).unwrap(), old); + assert_eq!(crate::gqt_record::parse(&old).unwrap(), wrapped); + } + pub(crate) fn valid_record_fixture() -> RunRecordV1 { valid_record() } @@ -2052,6 +2087,13 @@ protocol: { deadline_seconds: 60, attribution: per-phase, schedule: manual, rese assert_eq!(record.acquisition.observed_repetitions, 1); assert_eq!(record.measurements.raw_samples.len(), 1); validate_run_record(&record).unwrap(); + assert_eq!( + canonical_record_bytes(&record).unwrap(), + crate::gqt_record::canonical_bytes(&crate::gqt_record::AnyRunRecordV1::Legacy( + record.clone() + )) + .unwrap() + ); let mut invalid = record; invalid @@ -2193,20 +2235,31 @@ protocol: { deadline_seconds: 60, attribution: per-phase, schedule: manual, rese let mut run = resolved_run(); let mut definition = run.case.definition.clone(); - definition.fixture.preparation = - Some(crate::case::FixturePreparation::ReversibleUpdatesV1 { + definition.fixture.preparation = Some( + crate::legacy::case::FixturePreparation::ReversibleUpdatesV1 { additional_commits: 64, rows_per_commit: 1, seed: 42, - maintenance: crate::case::PreparationMaintenance::None, - }); - definition.fixture.state.aging = crate::case::Aging::SmallCommits; - definition.fixture.state.deletion_history = crate::case::DeletionHistory::ReversibleUpdates; + maintenance: crate::legacy::case::PreparationMaintenance::None, + }, + ); + definition.fixture.state.aging = crate::legacy::case::Aging::SmallCommits; + definition.fixture.state.deletion_history = + crate::legacy::case::DeletionHistory::ReversibleUpdates; definition.fixture.state.history_depth += 64; - run.case = crate::validate_case(definition).into_result().unwrap(); + run.case = crate::legacy::case::validate_case(definition) + .into_result() + .unwrap(); let execution = execution(&run); let aged = build_run_record(&run, &execution, input(&run, &execution)).unwrap(); let encoded = canonical_record_bytes(&aged).unwrap(); + assert_eq!( + encoded, + crate::gqt_record::canonical_bytes(&crate::gqt_record::AnyRunRecordV1::Legacy( + aged.clone() + )) + .unwrap() + ); assert_eq!(parse_canonical_record(&encoded).unwrap(), aged); assert!(!aged.claim_eligible()); let mut mismatched = aged.clone(); diff --git a/crates/omnigraph-bench/src/registered_fixture.rs b/crates/omnigraph-bench/src/registered_fixture.rs index ccba71fc4..8ddf43569 100644 --- a/crates/omnigraph-bench/src/registered_fixture.rs +++ b/crates/omnigraph-bench/src/registered_fixture.rs @@ -758,7 +758,7 @@ fn stage_failure( ValidationOutcome::failure(diagnostics) } -fn load_source_descriptor( +pub(crate) fn load_source_descriptor( path: &Path, ) -> Result<(RegisteredFixtureSourceV1, String), Vec> { let source = read_source_descriptor(path).map_err(|diagnostic| vec![diagnostic])?; diff --git a/crates/omnigraph-bench/src/runner.rs b/crates/omnigraph-bench/src/runner.rs index abaae97a9..2ea20cf46 100644 --- a/crates/omnigraph-bench/src/runner.rs +++ b/crates/omnigraph-bench/src/runner.rs @@ -19,34 +19,69 @@ use std::io::{Read, Seek, Write}; use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::Arc; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; +#[cfg(test)] +use std::time::Duration; +#[cfg(test)] +use std::time::{Instant, SystemTime, UNIX_EPOCH}; +#[cfg(test)] use futures::FutureExt; +#[cfg(test)] use lance::io::WrappingObjectStore; +#[cfg(test)] use omnigraph::Session; +#[cfg(test)] use omnigraph::db::{MergeOutcome, Omnigraph}; +#[cfg(test)] use omnigraph::instrumentation::{ - CountingStorageAdapter, MergeTimingReading, MergeWriteProbes, QueryIoProbes, StorageReadCounts, - with_merge_write_probes, with_query_io_probes, + CountingStorageAdapter, QueryIoProbes, with_merge_write_probes, with_query_io_probes, }; +use omnigraph::instrumentation::{MergeTimingReading, MergeWriteProbes, StorageReadCounts}; +#[cfg(test)] use omnigraph::settings::SessionSettings; use serde::{Deserialize, Serialize}; +#[cfg(test)] use sha2::{Digest, Sha256}; +use crate::branch_merge::FixturePreflight; +#[cfg(test)] +use crate::branch_merge::initialize_local_fixture; +#[cfg(test)] use crate::branch_merge::{ - BranchMergePlan, FixtureBuildSummary, FixturePreflight, SOURCE_BRANCH, TARGET_BRANCH, - capture_protected_branch_heads, initialize_local_fixture, verify_merged_graph, warm_read_set, + BranchMergePlan, FixtureBuildSummary, SOURCE_BRANCH, TARGET_BRANCH, + capture_protected_branch_heads, verify_merged_graph, warm_read_set, }; -use crate::case::{ - Attribution, Backend, CacheCondition, Data, EnginePreparation, FixtureBuilder, LocalFilesystem, - LocalStorageClass, MAX_WARMUP_ITERATIONS, PageCacheCondition, ProcessLifecycle, ResetMode, - State, WarmupProgram, -}; -use crate::counting::{LogicalCallCounter, LogicalCallCounts}; -use crate::environment::{LocalEnvironmentEvidence, verify_local_environment}; +#[cfg(test)] +use crate::counting::LogicalCallCounter; +use crate::counting::LogicalCallCounts; +use crate::environment::LocalEnvironmentEvidence; +#[cfg(test)] +use crate::environment::verify_local_environment; +#[cfg(test)] use crate::fixture_worker::supervise_fixture_build; -use crate::machine::{MachineIdentityV1, capture_machine_identity}; +use crate::gqt_protocol::{ + WorkerBuildV1, digest_worker_executable, open_and_digest_worker_executable, +}; +#[cfg(test)] +use crate::legacy::case::validate_case; +#[cfg(test)] +use crate::legacy::case::{ + Attribution, Backend, EnginePreparation, LocalFilesystem, LocalStorageClass, + MAX_WARMUP_ITERATIONS, PageCacheCondition, ProcessLifecycle, ResetMode, WarmupProgram, +}; +use crate::legacy::case::{CacheCondition, Data, FixtureBuilder, State}; +#[cfg(test)] +use crate::legacy::suite::ResolvedRun; +#[cfg(test)] +use crate::legacy::suite::ResolvedSuite; +#[cfg(test)] +use crate::legacy::suite::{MAX_REPETITIONS_PER_CASE, MAX_SUITE_RUNS, MAX_TOTAL_REPETITIONS}; +use crate::machine::MachineIdentityV1; +#[cfg(test)] +use crate::machine::capture_machine_identity; +#[cfg(test)] use crate::preparation::{PreparationWriteGate, guard_preparation_writes}; +#[cfg(test)] use crate::reset::{ ClonefileTemplate, MetadataDigest, PHYSICAL_TREE_DIGEST_ALGORITHM, PhysicalDigest, PlainCopyTemplate, TraversalLimits, accept_clonefile_template_handoff, @@ -55,12 +90,8 @@ use crate::reset::{ }; #[cfg(test)] use crate::reset::{digest_metadata_tree, digest_physical_tree, verify_physical_tree}; -use crate::suite::{MAX_REPETITIONS_PER_CASE, MAX_SUITE_RUNS, MAX_TOTAL_REPETITIONS}; +#[cfg(test)] use crate::supervisor::{SupervisionInput, supervise_repetition}; -use crate::worker_protocol::{ - WorkerBuildV1, digest_worker_executable, open_and_digest_worker_executable, -}; -use crate::{ResolvedRun, ResolvedSuite, validate_case}; pub const RUNNER_OUTPUT_VERSION: u32 = 2; pub const FIXTURE_MANIFEST_FORMAT_VERSION: u32 = 1; @@ -81,7 +112,9 @@ const RELEASE_PROFILE_ENVIRONMENT_OVERRIDES: &str = env!("OMNIGRAPH_BENCH_RELEASE_PROFILE_ENVIRONMENT_OVERRIDES"); const EFFECTIVE_CODEGEN_OPTIONS_PROVED: &str = env!("OMNIGRAPH_BENCH_EFFECTIVE_CODEGEN_OPTIONS_PROVED"); +#[cfg(test)] const RUN_OWNER_STACK_BYTES: usize = 64 * 1024 * 1024; +#[cfg(test)] const FIXTURE_BUILD_WATCHDOG: Duration = Duration::from_secs(3_600); /// Invocation-only options. No option may override experiment identity. @@ -107,6 +140,10 @@ pub struct RunnerError { #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)] pub struct RunnerErrorContext { + #[serde(skip_serializing_if = "Option::is_none")] + pub gqt_settled_elapsed_us: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub gqt_partial_run: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub case_id: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -119,6 +156,8 @@ pub struct RunnerErrorContext { pub completed_samples: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub settled_sample: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub gqt_settled_sample: Option>, /// Complete verified prefix plus the identities needed to finalize a /// censored durable record. Kept out of the diagnostic envelope because a /// successful archive receipt is the authority for those raw samples. @@ -135,6 +174,16 @@ pub struct RunnerErrorContext { pub quarantined_workspace: Option, } +impl RunnerErrorContext { + /// Remove completed evidence after a receipt or recovery envelope takes ownership. + pub fn clear_completed_prefix(&mut self) { + self.completed_runs.clear(); + self.completed_samples.clear(); + self.partial_run = None; + self.gqt_partial_run = None; + } +} + impl RunnerError { pub(crate) fn new(code: impl Into, message: impl Into) -> Self { Self { @@ -144,6 +193,7 @@ impl RunnerError { } } + #[cfg(test)] fn with_run_identity(mut self, run: &ResolvedRun) -> Self { self.context.case_id = Some(run.case.definition.id.clone()); self.context.point_id = Some(run.case.point_id.clone()); @@ -155,16 +205,19 @@ impl RunnerError { self } + #[cfg(test)] fn with_completed_samples(mut self, samples: Vec) -> Self { self.context.completed_samples = samples; self } + #[cfg(test)] fn with_completed_runs(mut self, runs: Vec) -> Self { self.context.completed_runs = runs; self } + #[cfg(test)] fn with_partial_worker_identity( mut self, build: Option<&WorkerBuildV1>, @@ -175,11 +228,25 @@ impl RunnerError { self } + #[cfg(test)] fn with_partial_run(mut self, execution: RunExecution) -> Self { self.context.partial_run = Some(Box::new(execution)); self } + pub(crate) fn with_gqt_settled_elapsed(mut self, elapsed_us: u64) -> Self { + self.context.gqt_settled_elapsed_us = Some(elapsed_us); + self + } + pub(crate) fn with_gqt_settled_sample( + mut self, + sample: crate::gqt_runner::GqtRepObservation, + ) -> Self { + self.context.gqt_settled_elapsed_us = Some(sample.elapsed_us); + self.context.gqt_settled_sample = Some(Box::new(sample)); + self + } + #[cfg(test)] pub(crate) fn with_settled_sample(mut self, sample: RepObservation) -> Self { self.context.settled_sample = Some(Box::new(sample)); self @@ -190,6 +257,7 @@ impl RunnerError { self } + #[cfg(test)] fn with_quarantined_workspace(mut self, path: PathBuf) -> Self { self.context.quarantined_workspace = Some(path); self @@ -340,7 +408,7 @@ pub struct LogicalFixtureIdentityV1 { pub state: State, pub logical_content_sha256: String, #[serde(default, skip_serializing_if = "Option::is_none")] - pub preparation: Option, + pub preparation: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -855,6 +923,7 @@ pub struct WallClockSummary { /// pass the output of [`crate::load_suite`]; manually constructed values must /// exactly match the suite and case definitions currently loaded from the same /// canonical paths. +#[cfg(test)] pub async fn execute_suite( suite: &ResolvedSuite, options: &RunOptions, @@ -902,6 +971,7 @@ pub async fn execute_suite( } /// Execute one resolved suite entry. +#[cfg(test)] pub async fn execute_run(run: &ResolvedRun, options: &RunOptions) -> RunnerResult { enforce_release_build().map_err(|error| error.with_run_identity(run))?; refuse_unmodeled_runtime_overrides().map_err(|error| error.with_run_identity(run))?; @@ -911,12 +981,14 @@ pub async fn execute_run(run: &ResolvedRun, options: &RunOptions) -> RunnerResul } #[derive(Debug, Clone, Copy)] +#[cfg(test)] struct ExecutionGuards { verify_environment: bool, isolate_repetitions: bool, allow_plain_copy: bool, } +#[cfg(test)] impl ExecutionGuards { fn public() -> Self { Self { @@ -1159,7 +1231,7 @@ fn expected_build_attestation_environment(name: &OsStr) -> Option<&'static str> } } -fn build_evidence(worker: Option<&WorkerBuildV1>) -> RunnerResult { +pub(crate) fn build_evidence(worker: Option<&WorkerBuildV1>) -> RunnerResult { let build = match worker { Some(worker) => worker.clone(), None => worker_build_attestation(String::new())?, @@ -1427,7 +1499,7 @@ fn valid_lower_hex(value: &str, lengths: &[usize]) -> bool { } #[derive(Debug, Clone)] -struct BoundWorkerSource { +pub(crate) struct BoundWorkerSource { configured_executable: PathBuf, executable_file: Arc, executable_bytes: u64, @@ -1435,12 +1507,13 @@ struct BoundWorkerSource { } #[derive(Debug, Clone)] -struct ResolvedWorker { - executable: PathBuf, - executable_sha256: String, +pub(crate) struct ResolvedWorker { + pub(crate) executable: PathBuf, + pub(crate) executable_sha256: String, } -fn validate_production_reset(case: &crate::case::CaseV1) -> RunnerResult<()> { +#[cfg(test)] +fn validate_production_reset(case: &crate::legacy::case::CaseV1) -> RunnerResult<()> { let linux_xfs_process_cold = cfg!(target_os = "linux") && matches!( &case.environment.backend, @@ -1471,6 +1544,7 @@ fn validate_production_reset(case: &crate::case::CaseV1) -> RunnerResult<()> { } } +#[cfg(test)] async fn execute_run_inner( run: &ResolvedRun, options: &RunOptions, @@ -1541,6 +1615,7 @@ async fn execute_run_inner( })? } +#[cfg(test)] async fn execute_owned_run( run: ResolvedRun, options: RunOptions, @@ -1796,7 +1871,8 @@ async fn execute_owned_run( }) } -fn unix_time_millis() -> RunnerResult { +#[cfg(test)] +pub(crate) fn unix_time_millis() -> RunnerResult { let elapsed = SystemTime::now() .duration_since(UNIX_EPOCH) .map_err(|error| { @@ -1813,6 +1889,7 @@ fn unix_time_millis() -> RunnerResult { }) } +#[cfg(test)] fn stamp_frozen_fixture( run: &ResolvedRun, build: &FixtureBuildSummary, @@ -1861,6 +1938,7 @@ fn stamp_frozen_fixture( }) } +#[cfg(test)] fn validate_execution_run(run: &ResolvedRun) -> RunnerResult<()> { if !(1..=MAX_REPETITIONS_PER_CASE).contains(&run.repetitions) { return Err(RunnerError::new( @@ -1897,8 +1975,9 @@ fn validate_execution_run(run: &ResolvedRun) -> RunnerResult<()> { Ok(()) } +#[cfg(test)] fn validate_execution_suite(suite: &ResolvedSuite) -> RunnerResult<()> { - let sealed = crate::load_suite(&suite.suite_path) + let sealed = crate::legacy::suite::load_suite(&suite.suite_path) .into_result() .map_err(|diagnostics| { RunnerError::new( @@ -1927,6 +2006,7 @@ fn validate_execution_suite(suite: &ResolvedSuite) -> RunnerResult<()> { Ok(()) } +#[cfg(test)] fn resolve_worker( options: &RunOptions, guards: ExecutionGuards, @@ -1943,7 +2023,7 @@ fn resolve_worker( resolve_bound_worker(executable).map(Some) } -fn resolve_bound_worker(executable: &Path) -> RunnerResult { +pub(crate) fn resolve_bound_worker(executable: &Path) -> RunnerResult { let executable = std::fs::canonicalize(executable).map_err(|error| { RunnerError::new( "worker_executable_error", @@ -2000,7 +2080,10 @@ fn resolve_bound_worker(executable: &Path) -> RunnerResult { }) } -fn stage_bound_worker(source: BoundWorkerSource, workspace: &Path) -> RunnerResult { +pub(crate) fn stage_bound_worker( + source: BoundWorkerSource, + workspace: &Path, +) -> RunnerResult { let executable = workspace.join("bound-worker-v1"); let mut input = source.executable_file.try_clone().map_err(|error| { RunnerError::new( @@ -2146,11 +2229,13 @@ fn stage_bound_worker(source: BoundWorkerSource, workspace: &Path) -> RunnerResu }) } +#[cfg(test)] enum FrozenTemplate { Clonefile(ClonefileTemplate), PlainCopy(PlainCopyTemplate), } +#[cfg(test)] impl FrozenTemplate { fn physical_digest(&self) -> &PhysicalDigest { match self { @@ -2192,6 +2277,7 @@ impl FrozenTemplate { } } +#[cfg(test)] fn run_supervised_repetitions( workspace: &tempfile::TempDir, template: FrozenTemplate, @@ -2366,6 +2452,7 @@ fn run_supervised_repetitions( Ok((samples, attested_build, attested_machine)) } +#[cfg(test)] fn supervised_prefix_error( error: RunnerError, samples: Vec, @@ -2377,6 +2464,7 @@ fn supervised_prefix_error( .with_partial_worker_identity(build, machine) } +#[cfg(test)] fn supervise_workspace( workspace: tempfile::TempDir, template: FrozenTemplate, @@ -2422,6 +2510,7 @@ fn supervise_workspace( } } +#[cfg(test)] fn containment_proven(error: &RunnerError) -> bool { error .context @@ -2434,6 +2523,7 @@ fn containment_proven(error: &RunnerError) -> bool { }) } +#[cfg(test)] async fn run_in_process_repetitions( _workspace: &tempfile::TempDir, template: &FrozenTemplate, @@ -2471,6 +2561,7 @@ async fn run_in_process_repetitions( Ok(samples) } +#[cfg(test)] fn remove_active_tree(active_root: &Path) -> RunnerResult<()> { match std::fs::symlink_metadata(active_root) { Ok(metadata) if metadata.file_type().is_dir() => std::fs::remove_dir_all(active_root) @@ -2495,6 +2586,7 @@ fn remove_active_tree(active_root: &Path) -> RunnerResult<()> { } } +#[cfg(test)] fn scratch_workspace(options: &RunOptions) -> RunnerResult { match &options.scratch_root { Some(root) => tempfile::Builder::new() @@ -2512,6 +2604,7 @@ fn scratch_workspace(options: &RunOptions) -> RunnerResult { }) } +#[cfg(test)] fn local_environment( run: &ResolvedRun, scratch_path: &Path, @@ -2556,6 +2649,7 @@ pub(crate) fn phase_observations(readings: Vec) -> Vec) -> Vec { phases .into_iter() @@ -2563,6 +2657,7 @@ fn observed_phase_evidence(phases: Vec) -> Vec RunnerResult { match ( condition.process, @@ -2638,8 +2735,10 @@ pub(crate) trait MeasurementSignals { fn settled(&mut self, elapsed_us: u64) -> RunnerResult<()>; } +#[cfg(test)] struct ImmediateMeasurementSignals; +#[cfg(test)] impl MeasurementSignals for ImmediateMeasurementSignals { fn ready(&mut self) -> RunnerResult<()> { Ok(()) @@ -2651,6 +2750,7 @@ impl MeasurementSignals for ImmediateMeasurementSignals { } #[allow(clippy::too_many_arguments)] +#[cfg(test)] pub(crate) async fn execute_rep_signaled( repetition: u32, root: &Path, @@ -2688,6 +2788,7 @@ pub(crate) async fn execute_rep_signaled( } #[allow(clippy::too_many_arguments)] +#[cfg(test)] async fn execute_rep_body( repetition: u32, root: &Path, @@ -2868,6 +2969,7 @@ async fn execute_rep_body( } } +#[cfg(test)] async fn open_counting( root_uri: &str, ) -> RunnerResult<(Session, Arc, PreparationWriteGate)> { @@ -2896,7 +2998,7 @@ async fn open_counting( } #[derive(Debug, Clone, Copy)] -struct ControlSnapshot { +pub(crate) struct ControlSnapshot { read_text: u64, read_text_if_exists: u64, read_text_versioned: u64, @@ -2908,7 +3010,7 @@ struct ControlSnapshot { } impl ControlSnapshot { - fn read(counts: &StorageReadCounts) -> Self { + pub(crate) fn read(counts: &StorageReadCounts) -> Self { Self { read_text: counts.read_text(), read_text_if_exists: counts.read_text_if_exists(), @@ -2921,7 +3023,7 @@ impl ControlSnapshot { } } - fn delta(self, after: Self) -> RunnerResult { + pub(crate) fn delta(self, after: Self) -> RunnerResult { fn checked(after: u64, before: u64, field: &str) -> RunnerResult { after.checked_sub(before).ok_or_else(|| { RunnerError::new( @@ -2952,6 +3054,7 @@ impl ControlSnapshot { } } +#[cfg(test)] fn summarize_wall_clock(samples: &[RepObservation]) -> RunnerResult { if samples.is_empty() { return Err(RunnerError::new( @@ -2978,6 +3081,7 @@ fn summarize_wall_clock(samples: &[RepObservation]) -> RunnerResult u64 { debug_assert!(!sorted.is_empty()); debug_assert!((1..=100).contains(&percentile)); @@ -2989,6 +3093,7 @@ fn nearest_rank(sorted: &[u64], percentile: usize) -> u64 { sorted[rank] } +#[cfg(test)] fn utf8_path<'a>(path: &'a Path, label: &str) -> RunnerResult<&'a str> { path.to_str().ok_or_else(|| { RunnerError::new( @@ -3003,7 +3108,7 @@ mod tests { use std::collections::BTreeSet; use super::*; - use crate::parse_case; + use crate::legacy::case::parse_case; fn general_route(merge_insert_calls: u64) -> MergeRouteObservation { test_general_merge_route(2, merge_insert_calls) @@ -4131,7 +4236,7 @@ protocol: fn checked_catalog_run(repetitions: u32) -> ResolvedRun { let case = parse_case(include_str!( - "../../../benchmarks/cases/branch-merge-d50-warm.case-v1.yaml" + "../tests/fixtures/legacy/branch-merge-d50-warm.case-v1.yaml" )) .into_result() .unwrap(); @@ -4142,13 +4247,23 @@ protocol: } } - fn checked_catalog_suite() -> ResolvedSuite { - crate::load_suite( - &PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../../benchmarks/suites/local-smoke.suite-v1.yaml"), + fn checked_catalog_suite() -> (tempfile::TempDir, ResolvedSuite) { + let directory = tempfile::tempdir().unwrap(); + let cases = directory.path().join("cases"); + let suites = directory.path().join("suites"); + std::fs::create_dir(&cases).unwrap(); + std::fs::create_dir(&suites).unwrap(); + std::fs::write( + cases.join("legacy.case-v1.yaml"), + include_str!("../tests/fixtures/legacy/branch-merge-d50-warm.case-v1.yaml"), ) - .into_result() - .unwrap() + .unwrap(); + let path = suites.join("legacy.suite-v1.yaml"); + std::fs::write(&path, "version: 1\nname: legacy-smoke\nruns:\n - { case: ../cases/legacy.case-v1.yaml, repetitions: 5 }\n").unwrap(); + let suite = crate::legacy::suite::load_suite(&path) + .into_result() + .unwrap(); + (directory, suite) } #[test] @@ -4168,7 +4283,7 @@ protocol: #[test] fn execution_reseals_the_complete_resolved_suite() { - let suite = checked_catalog_suite(); + let (_directory, suite) = checked_catalog_suite(); validate_execution_suite(&suite).unwrap(); let mut mislabeled = suite.clone(); diff --git a/crates/omnigraph-bench/src/suite.rs b/crates/omnigraph-bench/src/suite.rs index a84ef4686..e7facd59b 100644 --- a/crates/omnigraph-bench/src/suite.rs +++ b/crates/omnigraph-bench/src/suite.rs @@ -161,6 +161,9 @@ pub fn validate_suite(suite: SuiteV1) -> ValidationOutcome { /// `/cases`. Canonical paths, human case ids, and full point ids must /// each be unique. pub fn load_suite(path: &Path) -> ValidationOutcome { + if path.is_dir() { + return load_suite_directory(path); + } let (suite_path, cases_root) = match resolve_catalog_paths(path) { Ok(paths) => paths, Err(diagnostic) => return ValidationOutcome::failure(vec![diagnostic]), @@ -266,18 +269,18 @@ fn resolve_catalog_paths(path: &Path) -> Result<(PathBuf, PathBuf), Diagnostic> }; let declared_suites_root = declared_suite_path .parent() - .filter(|parent| !parent.as_os_str().is_empty()) - .unwrap_or_else(|| Path::new(".")); - if declared_suites_root - .file_name() - .is_none_or(|name| name != "suites") - { - return Err(Diagnostic::error( - "suite_catalog_layout_error", - path.display().to_string(), - "suite file must be directly inside a benchmark catalog's 'suites' directory", - )); - } + .and_then(|parent| { + parent + .ancestors() + .find(|p| p.file_name().is_some_and(|name| name == "suites")) + }) + .ok_or_else(|| { + Diagnostic::error( + "suite_catalog_layout_error", + path.display().to_string(), + "suite file must be below a catalog suites directory", + ) + })?; let declared_catalog_root = declared_suites_root .parent() .filter(|parent| !parent.as_os_str().is_empty()) @@ -310,7 +313,7 @@ fn resolve_catalog_paths(path: &Path) -> Result<(PathBuf, PathBuf), Diagnostic> format!("could not resolve suite path: {error}"), ) })?; - if suite_path.parent() != Some(suites_root.as_path()) { + if !suite_path.starts_with(&suites_root) { return Err(Diagnostic::error( "suite_outside_catalog", path.display().to_string(), @@ -345,29 +348,99 @@ fn reject_duplicate_identity( let mut points: BTreeMap<&str, usize> = BTreeMap::new(); for (loaded_index, run) in runs.iter().enumerate() { let source_index = source_indices[loaded_index]; - if let Some(first) = ids.insert(&run.case.definition.id, source_index) { + if let Some(first) = ids.insert(run.case.id(), source_index) { diagnostics.push(Diagnostic::error( "duplicate_case_id", format!("runs[{source_index}].case"), format!( "case id '{}' is already used by runs[{first}]", - run.case.definition.id + run.case.id() ), )); } - if let Some(first) = points.insert(&run.case.point_id, source_index) { + if let Some(first) = points.insert(run.case.planned_identity(), source_index) { diagnostics.push(Diagnostic::error( "duplicate_point_id", format!("runs[{source_index}].case"), format!( "point id '{}' is already used by runs[{first}]", - run.case.point_id + run.case.planned_identity() ), )); } } } +fn load_suite_directory(path: &Path) -> ValidationOutcome { + let result = (|| -> Result> { + let failure = |e: String| { + vec![Diagnostic::error( + "suite_directory_error", + path.display().to_string(), + e, + )] + }; + let mut files = Vec::new(); + for (index, entry) in fs::read_dir(path) + .map_err(|e| failure(e.to_string()))? + .enumerate() + { + if index >= MAX_SUITE_RUNS { + return Err(failure("directory entry budget exceeded".into())); + } + let entry = entry.map_err(|e| failure(e.to_string()))?; + if entry.path().extension().is_some_and(|e| e == "yaml") { + files.push(entry.path()); + } + } + files.sort(); + let mut runs = Vec::new(); + let mut total = 0u64; + for file in files { + let suite = load_suite(&file).into_result()?; + for run in suite.runs { + total = total + .checked_add(run.repetitions as u64) + .ok_or_else(|| failure("repetition total overflow".into()))?; + if runs.len() >= MAX_SUITE_RUNS || total > MAX_TOTAL_REPETITIONS { + return Err(failure( + "suite directory acquisition budget exceeded".into(), + )); + } + runs.push(run); + } + } + if runs.is_empty() { + return Err(failure("directory contains no suite runs".into())); + } + let mut diagnostics = Vec::new(); + let indices = (0..runs.len()).collect::>(); + reject_duplicate_identity(&runs, &indices, &mut diagnostics); + if !diagnostics.is_empty() { + return Err(diagnostics); + } + Ok(ResolvedSuite { + definition: SuiteV1 { + version: 1, + name: "directory".into(), + runs: runs + .iter() + .map(|r| SuiteRunV1 { + case: r.case_path.clone(), + repetitions: r.repetitions, + }) + .collect(), + }, + suite_path: path.to_path_buf(), + runs, + }) + })(); + match result { + Ok(s) => ValidationOutcome::success(s), + Err(d) => ValidationOutcome::failure(d), + } +} + #[cfg(test)] mod tests { use super::*; @@ -413,7 +486,7 @@ protocol: { deadline_seconds: 60, attribution: per-phase, schedule: manual, rese let five = load_suite(&suite_path).into_result().unwrap(); fs::write(&suite_path, suite("../cases/base.yaml", 20)).unwrap(); let twenty = load_suite(&suite_path).into_result().unwrap(); - assert_eq!(five.runs[0].case.point_id, twenty.runs[0].case.point_id); + assert_eq!(five.runs[0].case.point_id(), twenty.runs[0].case.point_id()); assert_eq!(five.runs[0].repetitions, 5); assert_eq!(twenty.runs[0].repetitions, 20); } diff --git a/crates/omnigraph-bench/src/supervisor.rs b/crates/omnigraph-bench/src/supervisor.rs index 4ed00910e..476ef647b 100644 --- a/crates/omnigraph-bench/src/supervisor.rs +++ b/crates/omnigraph-bench/src/supervisor.rs @@ -14,8 +14,8 @@ use std::sync::mpsc::{self, Receiver, RecvTimeoutError, SyncSender, TrySendError use std::thread::JoinHandle; use std::time::{Duration, Instant}; -use crate::ValidatedCase; use crate::branch_merge::{BranchMergePlan, TARGET_BRANCH}; +use crate::legacy::case::ValidatedCase; use crate::machine::MachineIdentityV1; use crate::reset::{MetadataDigest, PhysicalDigest}; use crate::runner::{ @@ -1367,12 +1367,12 @@ fn remaining(total: Duration, elapsed: Duration) -> Duration { #[cfg(all(test, unix))] mod tests { use crate::counting::LogicalCallCounts; + use crate::legacy::case::{ValidatedCase, parse_case}; use crate::runner::{ ControlCallObservation, LogicalStoreCallObservation, VerificationObservation, test_general_merge_route, test_general_merge_stored_phases, }; use crate::worker_protocol::ChildFrameV1; - use crate::{ValidatedCase, parse_case}; use std::sync::{Mutex, MutexGuard}; use super::*; @@ -1389,7 +1389,7 @@ mod tests { fn test_case() -> ValidatedCase { parse_case(include_str!( - "../../../benchmarks/cases/branch-merge-d50-warm.case-v1.yaml" + "../tests/fixtures/legacy/branch-merge-d50-warm.case-v1.yaml" )) .into_result() .unwrap() diff --git a/crates/omnigraph-bench/src/worker.rs b/crates/omnigraph-bench/src/worker.rs index eb608cc0e..4825c4557 100644 --- a/crates/omnigraph-bench/src/worker.rs +++ b/crates/omnigraph-bench/src/worker.rs @@ -6,12 +6,12 @@ use std::sync::mpsc::{self, Receiver}; use std::time::Duration; use crate::branch_merge::BranchMergePlan; +use crate::legacy::case::{ValidatedCase, validate_case}; use crate::runner::{MeasurementSignals, RunnerError, RunnerResult, execute_rep_signaled}; use crate::worker_protocol::{ ChildFrameV1, ParentFrameV1, WORKER_PROTOCOL_VERSION, WorkerRequestV1, WorkerStageV1, digest_worker_executable, read_frame, validate_protocol_version, write_frame, }; -use crate::{ValidatedCase, validate_case}; /// Run exactly one repetition over the private stdin/stdout worker protocol. /// @@ -474,7 +474,7 @@ mod tests { #[test] fn worker_refuses_identity_mismatch_before_opening_a_store() { - let case: crate::CaseV1 = serde_yaml::from_str( + let case: crate::legacy::case::CaseV1 = serde_yaml::from_str( r#" version: 1 id: worker-identity-test diff --git a/crates/omnigraph-bench/src/worker_protocol.rs b/crates/omnigraph-bench/src/worker_protocol.rs index 2186659d0..17fc86259 100644 --- a/crates/omnigraph-bench/src/worker_protocol.rs +++ b/crates/omnigraph-bench/src/worker_protocol.rs @@ -15,7 +15,7 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -use crate::case::CaseV1; +use crate::legacy::case::CaseV1; use crate::machine::MachineIdentityV1; use crate::reset::{MetadataDigest, PhysicalDigest}; use crate::runner::{EffectiveEnvironmentValue, RepObservation}; @@ -32,43 +32,7 @@ pub const MAX_WORKER_FRAME_BYTES: usize = 1024 * 1024; const MAX_WORKER_EXECUTABLE_BYTES: u64 = 2 * 1024 * 1024 * 1024; const EXECUTABLE_DIGEST_BUFFER_BYTES: usize = 1024 * 1024; -/// Attested build facts reported by an honest worker from its own process. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct WorkerBuildV1 { - pub source_commit: String, - /// `None` is an explicit failed build-time probe and is never admissible - /// for a measured worker. Keeping the absence typed lets the parent fail - /// closed instead of accepting a fabricated clean/dirty value. - pub source_tree_dirty: Option, - pub cargo_profile: String, - /// Cargo's profile-level observation, not proof against direct target - /// rustc arguments. - pub cargo_opt_level: String, - pub debug_assertions: bool, - /// Effective Lance memory-pool setting inherited by the measured worker. - /// This is retained until the complete typed engine-environment registry - /// below replaces the one-setting representation. - pub effective_lance_mem_pool_size: Box, - pub target_triple: String, - pub rustc_version: String, - pub declared_release_lto: String, - pub declared_release_codegen_units: Option, - pub declared_release_strip: Option, - pub cargo_encoded_rustflags_present: Option, - pub release_profile_environment_overrides_supported: Option, - /// False until a controlled build wrapper supplies the final target rustc - /// command line in a digest-bound external receipt. - pub effective_codegen_options_proved: bool, - /// Canonical Cargo feature names reported by the linked - /// `omnigraph-engine` artifact itself, not inferred from this CLI crate. - pub engine_feature_flags: Vec, - /// Canonical non-Cargo engine techniques enabled for this execution. - /// Runner-v1 has no such controls and therefore admits only an empty set. - pub enabled_techniques: Vec, - pub executable_sha256: String, -} - +pub use crate::gqt_protocol::WorkerBuildV1; /// Complete, immutable input for one worker process. /// /// The worker revalidates `case` and compares the derived identities with the @@ -424,11 +388,11 @@ mod tests { use std::io::{BufReader, Cursor, Write}; use crate::counting::LogicalCallCounts; + use crate::legacy::case::validate_case; use crate::runner::{ ControlCallObservation, LogicalStoreCallObservation, VerificationObservation, test_general_merge_route, test_general_merge_stored_phases, }; - use crate::validate_case; use super::*; diff --git a/crates/omnigraph-bench/tests/catalog_cli.rs b/crates/omnigraph-bench/tests/catalog_cli.rs new file mode 100644 index 000000000..3985e7e97 --- /dev/null +++ b/crates/omnigraph-bench/tests/catalog_cli.rs @@ -0,0 +1,453 @@ +use std::fs; +use std::path::{Path, PathBuf}; + +use assert_cmd::Command; +use serde_json::Value; + +fn root() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")).join("../..") +} +fn run(cwd: &Path, args: &[&str], ok: bool) -> Value { + let output = Command::cargo_bin("omnigraph-bench") + .unwrap() + .current_dir(cwd) + .args(args) + .output() + .unwrap(); + assert_eq!( + output.status.success(), + ok, + "{args:?}: {}", + String::from_utf8_lossy(&output.stdout) + ); + serde_json::from_slice(&output.stdout) + .unwrap_or_else(|e| panic!("{args:?}: {e}: {}", String::from_utf8_lossy(&output.stdout))) +} +#[test] +fn public_inventory_is_sorted_complete_and_stable() { + for kind in ["fixtures", "workloads", "scenarios"] { + let first = run(&root(), &["list", kind, "--json"], true); + assert_eq!(first, run(&root(), &["list", kind, "--json"], true)); + assert_eq!(first["cli_output_version"], 1); + assert_eq!(first["ok"], true); + let entries = first["value"]["entries"].as_array().unwrap(); + assert!(!entries.is_empty()); + assert!( + entries.iter().all(|e| e["source"] == "available"), + "{first}" + ); + let field = if kind == "scenarios" { "id" } else { "path" }; + assert!( + entries + .windows(2) + .all(|w| w[0][field].as_str() < w[1][field].as_str()) + ); + if kind == "scenarios" { + let catalog = + omnigraph_bench::catalog::Catalog::load(&root().join("benchmarks/benchmarks.yaml")) + .unwrap(); + let mut expected = catalog + .definition + .scenarios + .iter() + .map(|scenario| scenario.id.as_str()) + .collect::>(); + expected.sort_unstable(); + assert_eq!( + entries + .iter() + .map(|entry| entry["id"].as_str().unwrap()) + .collect::>(), + expected + ); + assert_eq!( + first["value"]["groups"]["search"].as_array().unwrap().len(), + 2 + ); + } + } + for config in [ + "benchmarks/benchmarks.yaml", + "benchmarks/custom.example.yaml", + ] { + let inventory = run( + &root(), + &["list", "fixtures", "--config", config, "--json"], + true, + ); + let preparation = inventory["value"]["entries"] + .as_array() + .unwrap() + .iter() + .find(|e| e["path"] == "fixtures/finbench/finbench_disjoint.gqt") + .unwrap(); + assert_eq!(preparation["kind"], "preparation", "{config}"); + assert_eq!(preparation["source"], "available", "{config}"); + } +} +#[test] +fn human_and_machine_help_need_no_catalog_or_cache() { + let directory = tempfile::tempdir().unwrap(); + for args in [ + vec!["--help"], + vec!["run", "--help"], + vec!["help", "config"], + vec!["help", "cache"], + vec!["help", "suite", "run"], + ] { + Command::cargo_bin("omnigraph-bench") + .unwrap() + .current_dir(directory.path()) + .args(args) + .assert() + .success(); + } + let help = run(directory.path(), &["help", "--json"], true); + assert_eq!(help["value"]["config_version"], 2); + let commands = help["value"]["commands"]["subcommands"].as_array().unwrap(); + for name in ["list", "show", "run", "cache", "init", "help"] { + assert!(commands.iter().any(|c| c["name"] == name)); + } + assert!( + !commands + .iter() + .any(|c| c["name"].as_str().unwrap().starts_with("__")) + ); + assert!( + help["value"]["required_combinations"]["show"] + .as_str() + .unwrap() + .contains("exactly one") + ); + assert_eq!(fs::read_dir(directory.path()).unwrap().count(), 0); +} +#[test] +fn argument_and_domain_errors_have_versioned_json() { + for args in [ + vec!["list", "nonsense", "--json"], + vec!["show", "--json"], + vec!["run", "no-such-scenario", "--json"], + vec!["show", "tiny-read", "--config", "missing.yaml", "--json"], + ] { + let result = run(&root(), &args, false); + assert_eq!(result["cli_output_version"], 1); + assert_eq!(result["ok"], false); + assert!(!result["diagnostics"].as_array().unwrap().is_empty()); + } +} +#[test] +fn custom_yaml_and_workload_inspection_resolve_from_another_directory() { + let directory = tempfile::tempdir().unwrap(); + let config = root().join("benchmarks/custom.example.yaml"); + let show = run( + directory.path(), + &[ + "show", + "custom-tiny-read", + "--config", + config.to_str().unwrap(), + "--json", + ], + true, + ); + assert_eq!(show["value"]["measured_step"]["ordinal"], 1); + assert_eq!(show["value"]["repetitions"], 5); + assert!(Path::new(show["value"]["resolved_workload"].as_str().unwrap()).is_absolute()); + let workload = root().join("benchmarks/workloads/tiny_read.gqt"); + let steps = run( + directory.path(), + &["show", "--workload", workload.to_str().unwrap(), "--json"], + true, + ); + assert_eq!( + steps["value"]["operations"][0]["text"] + .as_str() + .unwrap() + .trim(), + show["value"]["measured_step"]["text"] + .as_str() + .unwrap() + .trim() + ); + assert_eq!(steps["value"]["operations"][0]["in_loop"], false); +} +#[test] +#[cfg(debug_assertions)] +fn named_and_custom_runs_use_existing_release_guard_and_failure_evidence() { + for args in [ + vec!["run", "tiny-read", "--json"], + vec![ + "run", + "--config", + "benchmarks/custom.example.yaml", + "--json", + ], + ] { + let result = run(&root(), &args, false); + assert_eq!( + result["runner_output_version"], + omnigraph_bench::RUNNER_OUTPUT_VERSION + ); + assert_eq!(result["error"]["code"], "release_build_required"); + assert!(result["completed_runs"].as_array().unwrap().is_empty()); + } +} +fn copy_pair(directory: &Path) { + fs::create_dir(directory.join("fixtures")).unwrap(); + fs::create_dir(directory.join("workloads")).unwrap(); + fs::copy( + root().join("benchmarks/fixtures/tiny_graph.gqt"), + directory.join("fixtures/tiny_graph.gqt"), + ) + .unwrap(); + fs::copy( + root().join("benchmarks/workloads/tiny_read.gqt"), + directory.join("workloads/tiny_read.gqt"), + ) + .unwrap(); +} +#[test] +fn init_emits_a_valid_exact_selector_and_never_replaces_existing_output() { + let directory = tempfile::tempdir().unwrap(); + copy_pair(directory.path()); + let args = [ + "init", + "--fixture", + "fixtures/tiny_graph.gqt", + "--workload", + "workloads/tiny_read.gqt", + "--step", + "1", + "--output", + "custom.yaml", + "--json", + ]; + let output = run(directory.path(), &args, true); + assert_eq!(output["value"]["scenario"], "custom"); + let before = fs::read(directory.path().join("custom.yaml")).unwrap(); + let show = run( + directory.path(), + &["show", "custom", "--config", "custom.yaml", "--json"], + true, + ); + let source = + omnigraph_bench::gqt_case::read_source(&directory.path().join("workloads/tiny_read.gqt")) + .unwrap(); + assert_eq!( + show["value"]["measured_step"]["text"], + source.parse().unwrap().steps()[0].source + ); + run(directory.path(), &args, false); + assert_eq!( + fs::read(directory.path().join("custom.yaml")).unwrap(), + before + ); + let invalid = [ + "init", + "--fixture", + "fixtures/tiny_graph.gqt", + "--workload", + "workloads/tiny_read.gqt", + "--step", + "999", + "--output", + "bad.yaml", + "--json", + ]; + run(directory.path(), &invalid, false); + assert!(!directory.path().join("bad.yaml").exists()); +} +#[test] +#[cfg(unix)] +fn init_refuses_a_symlink_and_output_outside_the_common_source_root() { + let directory = tempfile::tempdir().unwrap(); + copy_pair(directory.path()); + fs::write(directory.path().join("sentinel"), "untouched").unwrap(); + std::os::unix::fs::symlink("sentinel", directory.path().join("custom.yaml")).unwrap(); + let args = [ + "init", + "--fixture", + "fixtures/tiny_graph.gqt", + "--workload", + "workloads/tiny_read.gqt", + "--step", + "1", + "--output", + "custom.yaml", + "--json", + ]; + run(directory.path(), &args, false); + assert_eq!( + fs::read_to_string(directory.path().join("sentinel")).unwrap(), + "untouched" + ); + fs::create_dir(directory.path().join("nested")).unwrap(); + let mut nested = args; + nested[8] = "nested/custom.yaml"; + run(directory.path(), &nested, false); + assert!(!directory.path().join("nested/custom.yaml").exists()); +} +#[test] +fn cache_misses_and_missing_sources_are_observations_without_filesystem_writes() { + let directory = tempfile::tempdir().unwrap(); + copy_pair(directory.path()); + fs::copy( + root().join("benchmarks/custom.example.yaml"), + directory.path().join("custom.yaml"), + ) + .unwrap(); + let args = [ + "cache", + "status", + "custom-tiny-read", + "--config", + "custom.yaml", + "--dataset-cache", + "missing-cache", + "--json", + ]; + let result = run(directory.path(), &args, true); + assert_eq!(result["value"]["cache"], "missing"); + assert_eq!(result["value"]["source"], "available"); + assert!(!directory.path().join("missing-cache").exists()); + fs::copy( + directory.path().join("workloads/tiny_read.gqt"), + directory.path().join("fixtures/tiny_graph.gqt"), + ) + .unwrap(); + let invalid = run(directory.path(), &args, false); + assert_eq!(invalid["value"]["source"], "invalid"); + let inventory = run( + directory.path(), + &["list", "fixtures", "--config", "custom.yaml", "--json"], + true, + ); + assert_eq!(inventory["value"]["entries"][0]["kind"], "fixture"); + assert_eq!(inventory["value"]["entries"][0]["source"], "invalid"); + fs::remove_file(directory.path().join("fixtures/tiny_graph.gqt")).unwrap(); + let result = run(directory.path(), &args, true); + assert_eq!(result["value"]["source"], "missing"); + assert_eq!(result["value"]["cache"], "unknown"); + fs::write(directory.path().join("workloads/tiny_read.gqt"), "not GQT").unwrap(); + let invalid = run(directory.path(), &args, false); + assert_eq!(invalid["value"]["source"], "invalid"); + assert!(!invalid["diagnostics"].as_array().unwrap().is_empty()); + let page = run( + directory.path(), + &[ + "cache", + "list", + "--dataset-cache", + "missing-cache", + "--json", + ], + true, + ); + assert!(page["value"]["entries"].as_array().unwrap().is_empty()); + assert!(!directory.path().join("missing-cache").exists()); +} + +#[test] +#[cfg(unix)] +fn cache_list_failures_preserve_entries_cursor_and_diagnostics() { + use nix::fcntl::{Flock, FlockArg}; + let directory = tempfile::tempdir().unwrap(); + let first_key = "a".repeat(64); + let second_key = "b".repeat(64); + let first = directory.path().join(&first_key); + let second = directory.path().join(&second_key); + for entry in [&first, &second] { + fs::create_dir(entry).unwrap(); + fs::write(entry.join("lock"), "").unwrap(); + } + let args = [ + "cache", + "list", + "--dataset-cache", + ".", + "--verify", + "--limit", + "1", + "--json", + ]; + let missing = run(directory.path(), &args, true); + assert_eq!(missing["value"]["entries"][0]["cache"], "missing"); + let owner = Flock::lock( + fs::File::open(first.join("lock")).unwrap(), + FlockArg::LockExclusiveNonblock, + ) + .unwrap(); + let busy = run(directory.path(), &args, true); + assert_eq!(busy["value"]["entries"][0]["cache"], "busy"); + drop(owner); + for state in ["invalid", "incomplete", "unknown"] { + match state { + "invalid" => fs::write(first.join("dataset-build.json"), "{broken").unwrap(), + "incomplete" => { + fs::remove_file(first.join("dataset-build.json")).unwrap(); + fs::create_dir(first.join("active")).unwrap(); + } + "unknown" => fs::remove_file(first.join("lock")).unwrap(), + _ => unreachable!(), + } + let page = run(directory.path(), &args, false); + assert_eq!(page["ok"], false); + assert_eq!(page["value"]["entries"][0]["cache"], state); + assert_eq!(page["value"]["next_cursor"], first_key); + assert_eq!( + page["diagnostics"][0]["path"], + first.canonicalize().unwrap().to_str().unwrap() + ); + assert_eq!( + page["diagnostics"][0]["code"], + page["value"]["entries"][0]["diagnostic"]["code"] + ); + Command::cargo_bin("omnigraph-bench") + .unwrap() + .current_dir(directory.path()) + .args(&args[..args.len() - 1]) + .assert() + .failure(); + } + let next = run( + directory.path(), + &[ + "cache", + "list", + "--dataset-cache", + ".", + "--after", + &first_key, + "--json", + ], + true, + ); + assert_eq!(next["value"]["entries"][0]["key"], second_key); + assert_eq!(next["value"]["entries"][0]["cache"], "missing"); + assert_eq!(next["value"]["next_cursor"], Value::Null); +} + +#[test] +#[cfg(unix)] +fn non_utf8_cache_paths_return_json_diagnostics_instead_of_panicking() { + use std::os::unix::ffi::OsStringExt; + let directory = tempfile::tempdir().unwrap(); + let path = directory + .path() + .join(std::ffi::OsString::from_vec(b"cache-\xff".to_vec())); + let output = Command::cargo_bin("omnigraph-bench") + .unwrap() + .args(["cache", "list", "--dataset-cache"]) + .arg(&path) + .arg("--json") + .output() + .unwrap(); + assert!(!output.status.success()); + let result: Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!(result["cli_output_version"], 1); + assert_eq!( + result["diagnostics"][0]["code"], + "output_serialization_failed" + ); + assert!(!path.exists()); +} diff --git a/crates/omnigraph-bench/tests/cli.rs b/crates/omnigraph-bench/tests/cli.rs index 93b66db8a..89b00263b 100644 --- a/crates/omnigraph-bench/tests/cli.rs +++ b/crates/omnigraph-bench/tests/cli.rs @@ -3,6 +3,7 @@ use std::path::{Path, PathBuf}; use assert_cmd::Command; use omnigraph_bench::RUNNER_OUTPUT_VERSION; +use omnigraph_bench::gqt_case::GqtFixture; use predicates::prelude::*; fn repository_root() -> PathBuf { @@ -10,9 +11,82 @@ fn repository_root() -> PathBuf { } fn benchmark_path(relative: &str) -> PathBuf { + if relative.starts_with("cases/") || relative == "cases" || relative.starts_with("suites/") { + return legacy_catalog().join(relative); + } + let relative = + relative + .replacen("datasets/", "fixtures/", 1) + .replacen("queries/", "workloads/", 1); repository_root().join("benchmarks").join(relative) } +fn legacy_catalog() -> &'static Path { + static LEGACY: std::sync::OnceLock = std::sync::OnceLock::new(); + LEGACY + .get_or_init(|| { + let directory = tempfile::tempdir().unwrap(); + fs::create_dir(directory.path().join("cases")).unwrap(); + let catalog = omnigraph_bench::catalog::Catalog::load( + &repository_root().join("benchmarks/benchmarks.yaml"), + ) + .unwrap(); + for scenario in &catalog.definition.scenarios { + let (mut definition, _) = scenario.expand(&catalog.definition.defaults); + for path in omnigraph_bench::catalog::fixture_paths(&definition.fixture) + .into_iter() + .chain([definition.workload.queries.as_path()]) + { + let target = directory.path().join(path); + fs::create_dir_all(target.parent().unwrap()).unwrap(); + fs::copy(catalog.root.join(path), target).unwrap(); + } + match &mut definition.fixture { + GqtFixture::Dataset { path } => *path = Path::new("..").join(&*path), + GqtFixture::Registered { + reference, + preparation, + } => { + *reference = Path::new("..").join(&*reference); + *preparation = Path::new("..").join(&*preparation); + } + } + definition.workload.queries = Path::new("..").join(&definition.workload.queries); + fs::write( + directory + .path() + .join(format!("cases/{}.case-v1.yaml", scenario.id)), + serde_yaml::to_string(&definition).unwrap(), + ) + .unwrap(); + } + for (name, ids) in &catalog.definition.groups { + let suite = omnigraph_bench::SuiteV1 { + version: 1, + name: name.clone(), + runs: ids + .iter() + .map(|id| omnigraph_bench::SuiteRunV1 { + case: format!("../../cases/{id}.case-v1.yaml").into(), + repetitions: catalog + .scenario(id) + .unwrap() + .expand(&catalog.definition.defaults) + .1, + }) + .collect(), + }; + let target = directory + .path() + .join(format!("suites/{name}/suite-v1.yaml")); + fs::create_dir_all(target.parent().unwrap()).unwrap(); + fs::write(target, serde_yaml::to_string(&suite).unwrap()).unwrap(); + } + directory + }) + .path() +} + fn registered_fixture(directory: &Path) -> (PathBuf, PathBuf) { let root = directory.join("root"); fs::create_dir_all(root.join("tables")).expect("fixture tree"); @@ -160,41 +234,15 @@ fn fixture_reference_validate_refuses_a_missing_expected_content_digest() { } #[test] -fn real_graph_run_refuses_debug_timing_before_fixture_setup() { - let directory = tempfile::tempdir().expect("temporary directory"); - let reference = directory.path().join("example.fixture-reference-v1.yaml"); - fs::write(&reference, fixture_reference_yaml(&"4".repeat(64))).expect("fixture reference"); - let spec = directory.path().join("example.run-v1.yaml"); - fs::write( - &spec, - r#"version: 1 -fixture_id: example-graph-v1 -workload: finbench-disjoint-insert-merge -repetitions: 1 -operation_deadline_seconds: 1 -"#, - ) - .expect("real graph run spec"); - - let output = Command::cargo_bin("omnigraph-bench") +fn retired_real_graph_run_is_not_an_execution_route() { + Command::cargo_bin("omnigraph-bench") .expect("benchmark binary") - .args([ - "fixture", - "run-graph", - spec.to_str().expect("UTF-8 run spec"), - "--reference", - reference.to_str().expect("UTF-8 reference"), - "--fixture", - "example-graph-v1=/not/inspected/in-debug", - "--json", - ]) - .output() - .expect("refuse debug real graph timing"); - - assert!(!output.status.success(), "{output:?}"); - let result: serde_json::Value = serde_json::from_slice(&output.stdout).expect("failure JSON"); - assert_eq!(result["ok"], false); - assert_eq!(result["diagnostics"][0]["code"], "release_build_required"); + .args(["fixture", "run-graph", "/not/inspected"]) + .assert() + .failure() + .stderr(predicate::str::contains( + "unrecognized subcommand 'run-graph'", + )); } #[test] @@ -362,7 +410,7 @@ fn fixture_preflight_copy_rejects_default_scratch_inside_bundle() { } #[test] -fn checked_in_case_and_suite_validate() { +fn legacy_case_and_suite_validate() { Command::cargo_bin("omnigraph-bench") .expect("benchmark binary") .args([ @@ -381,7 +429,7 @@ fn checked_in_case_and_suite_validate() { .args([ "suite", "validate", - benchmark_path("suites/local-smoke.suite-v1.yaml") + benchmark_path("suites/local-smoke/suite-v1.yaml") .to_str() .expect("UTF-8 path"), ]) @@ -394,7 +442,7 @@ fn checked_in_case_and_suite_validate() { .args([ "suite", "validate", - benchmark_path("suites/aws-xfs-process-cold.suite-v1.yaml") + benchmark_path("suites/aws-xfs-process-cold/suite-v1.yaml") .to_str() .expect("UTF-8 path"), ]) @@ -405,12 +453,12 @@ fn checked_in_case_and_suite_validate() { #[test] fn suite_commands_accept_a_bare_filename_from_the_suites_directory() { - let suites = benchmark_path("suites"); + let suites = benchmark_path("suites/local-smoke"); for command in ["validate", "plan"] { Command::cargo_bin("omnigraph-bench") .expect("benchmark binary") .current_dir(&suites) - .args(["suite", command, "local-smoke.suite-v1.yaml"]) + .args(["suite", command, "suite-v1.yaml"]) .assert() .success() .stdout(predicate::str::contains("local-smoke")); @@ -448,7 +496,7 @@ fn case_list_is_machine_readable_and_deterministic() { #[test] fn suite_plan_resolves_relative_cases_and_supports_selection() { - let suite = benchmark_path("suites/local-smoke.suite-v1.yaml"); + let suite = benchmark_path("suites/local-smoke/suite-v1.yaml"); let output = Command::cargo_bin("omnigraph-bench") .expect("benchmark binary") .args([ @@ -467,24 +515,29 @@ fn suite_plan_resolves_relative_cases_and_supports_selection() { assert_eq!(plan["plan_version"], 1); assert_eq!(plan["suite"], "local-smoke"); assert_eq!(plan["runs"].as_array().expect("runs").len(), 1); - assert_eq!(plan["runs"][0]["case_id"], "branch-merge-d50-warm"); + assert_eq!( + plan["runs"][0]["case"]["definition"]["id"], + "branch-merge-d50-warm" + ); assert_eq!(plan["runs"][0]["repetitions"], 5); assert_eq!( - plan["runs"][0]["identity"]["environment"]["cache_condition"], + plan["runs"][0]["case"]["cache_condition"], serde_json::json!({ "process": "fresh-per-repetition", "engine": "warmed-by-program", "page_cache": "program-conditioned", - "program": "branch-merge-read-set-v1", - "iterations": 1 + "program": "gqt-read-set-v1", + "iterations": 24 }) ); - // This is the persisted V1 natural key for the checked-in point. An - // identity-serialization change must bump POINT_IDENTITY_VERSION; a - // deliberate factor change must update this fixture. + assert_eq!(plan["runs"][0]["case"]["state"], "gqt"); + assert!(plan["runs"][0]["case"].get("point_id").is_none()); assert_eq!( - plan["runs"][0]["point_id"], - "96b753e93dfed18c29e9f28f7181661cee413bfb4dbd6e31671b6f7418f71ffc" + plan["runs"][0]["case"]["planned_sha256"] + .as_str() + .unwrap() + .len(), + 64 ); } @@ -516,7 +569,7 @@ fn missing_case_selector_fails_instead_of_running_the_full_suite() { .args([ "suite", "plan", - benchmark_path("suites/local-smoke.suite-v1.yaml") + benchmark_path("suites/local-smoke/suite-v1.yaml") .to_str() .expect("UTF-8 path"), "--case", @@ -527,6 +580,59 @@ fn missing_case_selector_fails_instead_of_running_the_full_suite() { .stderr(predicate::str::contains("does-not-exist")); } +#[test] +#[cfg(debug_assertions)] +fn legacy_run_accepts_case_files_without_restricting_the_filename() { + let cases = legacy_catalog().join("cases"); + let original = cases.join("tiny-read.case-v1.yaml"); + for name in ["tiny-read", "custom.case", "custom.YAML", "custom.YML"] { + let path = cases.join(name); + fs::copy(&original, &path).unwrap(); + for input in [path.clone(), Path::new(".").join(name), PathBuf::from(name)] { + let output = Command::cargo_bin("omnigraph-bench") + .unwrap() + .current_dir(&cases) + .arg("run") + .arg(&input) + .arg("--json") + .output() + .unwrap(); + assert!(!output.status.success()); + let result: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!( + result["runner_output_version"], RUNNER_OUTPUT_VERSION, + "{input:?}: {result}" + ); + assert_eq!(result["error"]["code"], "release_build_required"); + assert_eq!(result["error"]["case_id"], "tiny-read"); + assert!(result["completed_runs"].as_array().unwrap().is_empty()); + } + } + let config = repository_root().join("benchmarks/custom.example.yaml"); + let output = Command::cargo_bin("omnigraph-bench") + .unwrap() + .current_dir(&cases) + .args(["run", "tiny-read", "--config"]) + .arg(config) + .arg("--json") + .output() + .unwrap(); + let result: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert!(!output.status.success()); + assert_eq!(result["diagnostics"][0]["code"], "unknown_selection"); + let output = Command::cargo_bin("omnigraph-bench") + .unwrap() + .current_dir(&cases) + .args(["run", "./missing-case", "--json"]) + .output() + .unwrap(); + let result: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert!(!output.status.success()); + assert!(result.to_string().contains("missing-case")); + assert!(!result.to_string().contains("config_not_found")); + assert!(!result.to_string().contains("unknown_selection")); +} + #[test] #[cfg(debug_assertions)] fn suite_run_refuses_debug_wall_clock_measurement_before_fixture_setup() { @@ -535,7 +641,7 @@ fn suite_run_refuses_debug_wall_clock_measurement_before_fixture_setup() { .args([ "suite", "run", - benchmark_path("suites/local-smoke.suite-v1.yaml") + benchmark_path("suites/local-smoke/suite-v1.yaml") .to_str() .expect("UTF-8 path"), "--case", @@ -552,10 +658,7 @@ fn suite_run_refuses_debug_wall_clock_measurement_before_fixture_setup() { assert_eq!(failure["completed_runs"].as_array().unwrap().len(), 0); assert_eq!(failure["error"]["code"], "release_build_required"); assert_eq!(failure["error"]["case_id"], "branch-merge-d50-warm"); - assert_eq!( - failure["error"]["point_id"], - "96b753e93dfed18c29e9f28f7181661cee413bfb4dbd6e31671b6f7418f71ffc" - ); + assert!(failure["error"].get("point_id").is_none()); } #[test] @@ -565,7 +668,7 @@ fn suite_run_checks_selection_before_execution_guards() { .args([ "suite", "run", - benchmark_path("suites/local-smoke.suite-v1.yaml") + benchmark_path("suites/local-smoke/suite-v1.yaml") .to_str() .expect("UTF-8 path"), "--case", @@ -579,31 +682,41 @@ fn suite_run_checks_selection_before_execution_guards() { #[test] fn case_list_rejects_duplicate_catalog_identity() { let directory = tempfile::tempdir().expect("temporary directory"); - let source = fs::read_to_string(benchmark_path("cases/branch-merge-d50-warm.case-v1.yaml")) - .expect("checked-in case"); - fs::write(directory.path().join("a.case-v1.yaml"), &source).expect("first case"); + for child in ["cases", "fixtures", "workloads"] { + fs::create_dir(directory.path().join(child)).unwrap(); + } + for relative in ["fixtures/tiny_graph.gqt", "workloads/tiny_read.gqt"] { + fs::copy(benchmark_path(relative), directory.path().join(relative)).unwrap(); + } + let cases = directory.path().join("cases"); + let source = fs::read_to_string(benchmark_path("cases/tiny-read.case-v1.yaml")).unwrap(); + fs::write(cases.join("a.case-v1.yaml"), &source).unwrap(); fs::write( - directory.path().join("b.case-v1.yaml"), - source.replace( - "id: branch-merge-d50-warm", - "id: branch-merge-d50-warm-alias", - ), + cases.join("b.case-v1.yaml"), + source.replace("id: tiny-read", "id: tiny-read-alias"), ) - .expect("second case"); - + .unwrap(); Command::cargo_bin("omnigraph-bench") .expect("benchmark binary") - .args([ - "case", - "list", - directory.path().to_str().expect("UTF-8 path"), - "--json", - ]) + .args(["case", "list", cases.to_str().unwrap(), "--json"]) .assert() .failure() .stdout(predicate::str::contains("duplicate_point_id")); } +#[test] +fn archived_legacy_point_keeps_its_original_identity() { + let case = omnigraph_bench::legacy::case::parse_case(include_str!( + "fixtures/legacy/branch-merge-d50-warm.case-v1.yaml" + )) + .into_result() + .unwrap(); + assert_eq!( + case.point_id, + "96b753e93dfed18c29e9f28f7181661cee413bfb4dbd6e31671b6f7418f71ffc" + ); +} + #[test] fn archive_verify_accepts_an_empty_authority_without_inventing_records() { let archive = tempfile::tempdir().expect("temporary archive"); diff --git a/crates/omnigraph-bench/tests/fixtures/gqt-catalog-groups.json b/crates/omnigraph-bench/tests/fixtures/gqt-catalog-groups.json new file mode 100644 index 000000000..93eb3a012 --- /dev/null +++ b/crates/omnigraph-bench/tests/fixtures/gqt-catalog-groups.json @@ -0,0 +1,170 @@ +{ + "aws-xfs-process-cold": [ + [ + "branch-merge-d50-process-cold-xfs", + 5 + ] + ], + "finbench": [ + [ + "finbench-disjoint-merge", + 5 + ] + ], + "history-1000": [ + [ + "very-long-history-1000-read", + 1 + ], + [ + "very-long-history-1000-write", + 1 + ], + [ + "very-long-history-1000-reopen", + 1 + ] + ], + "history-10000": [ + [ + "very-long-history-10000-read", + 1 + ], + [ + "very-long-history-10000-write", + 1 + ], + [ + "very-long-history-10000-reopen", + 1 + ] + ], + "history-100000": [ + [ + "very-long-history-100000-read", + 1 + ], + [ + "very-long-history-100000-write", + 1 + ], + [ + "very-long-history-100000-reopen", + 1 + ] + ], + "local-fast": [ + [ + "tiny-read", + 1 + ], + [ + "tiny-restart", + 1 + ], + [ + "tiny-post-reopen", + 1 + ], + [ + "tiny-mutate", + 1 + ], + [ + "tiny-branch", + 1 + ], + [ + "tiny-load", + 1 + ] + ], + "local-regression": [ + [ + "very-long-history-32-read", + 1 + ], + [ + "very-long-history-32-write", + 1 + ], + [ + "very-long-history-32-reopen", + 1 + ], + [ + "hot-table-idle-base", + 1 + ], + [ + "hot-table-idle-tables-4", + 1 + ], + [ + "hot-table-idle-branches-4", + 1 + ], + [ + "hot-table-idle-branches-4-aged", + 1 + ], + [ + "parallel-tables-1", + 1 + ], + [ + "parallel-tables-2", + 1 + ], + [ + "parallel-tables-4", + 1 + ], + [ + "identity-lifecycle", + 1 + ], + [ + "repeated-deletion-recreation-rows", + 1 + ], + [ + "repeated-deletion-recreation-branches", + 1 + ], + [ + "threshold-crossings-before", + 1 + ], + [ + "threshold-crossings-at", + 1 + ], + [ + "threshold-crossings-after", + 1 + ], + [ + "threshold-crossings-production-control", + 1 + ], + [ + "equal-current-narrow-one-batch", + 1 + ], + [ + "equal-current-wide-one-batch", + 1 + ], + [ + "equal-current-wide-four-batches", + 1 + ] + ], + "local-smoke": [ + [ + "branch-merge-d50-warm", + 5 + ] + ] +} diff --git a/crates/omnigraph-bench/tests/fixtures/gqt-catalog-identity.json b/crates/omnigraph-bench/tests/fixtures/gqt-catalog-identity.json new file mode 100644 index 000000000..255e323ba --- /dev/null +++ b/crates/omnigraph-bench/tests/fixtures/gqt-catalog-identity.json @@ -0,0 +1,1322 @@ +{ + "branch-merge-d50-process-cold-xfs": { + "planned_sha256": "ccdd6fe31f024747a44d0911bc915e5c8285d9590d870bf4fe7eedff3c3652b4", + "recipe_sha256": "15da6902a942b5e48e9549b9a5c73d6eea42f4a49f146ff478b364a75b7c8fb9", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "092ba8772837527e545a3aad9ef880ada7837f476fb2543d51cd1fce3d00e877", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nbranch merge \"bench-source\" into \"bench-target\"\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "xfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "plain-copy", + "timer": "monotonic" + }, + "repetitions": 5, + "bound_point_id": "58f5ae4950087b6f9578398df9ec741c0426ae4c7a938c93f0ed85b6e95b922c" + }, + "branch-merge-d50-warm": { + "planned_sha256": "e8a4f0e4761ff264ee41e72613d3d431f8d65b02bc68c957096098fac752077e", + "recipe_sha256": "15da6902a942b5e48e9549b9a5c73d6eea42f4a49f146ff478b364a75b7c8fb9", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "warmed-by-program", + "page_cache": "program-conditioned", + "program": "gqt-read-set-v1", + "iterations": 24 + }, + "workload_sha256": "a6ffc729893c731dd1199374af15ac8f1de8ef1c1c7e4cfe9f651282a5ca04ba", + "measured_step": { + "ordinal": 25, + "text": "--- mutate\nbranch merge \"bench-source\" into \"bench-target\"\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 5, + "bound_point_id": "05561cc1bfc25ee6a98317ddb71c85ed5f1baecf2aefdb04be0e15e226a2bc83" + }, + "equal-current-narrow-one-batch": { + "planned_sha256": "944da755d2f8bba63769c901d2fe8a6507cf8448b39c60c6a0037131d373c901", + "recipe_sha256": "7628893a2bd794a4e2bd2250c24a61c0fc948032f1b06771bd3d4fc5161c6e69", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "2cd410e611ef5545b7f29e5191833d42aa754b0e2f5ec34415c35effb9c86c46", + "measured_step": { + "ordinal": 1, + "text": "--- query branch: main\nquery current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "e0bb1c2effb7c90fc153fc0148e5b14038973b9aa663237c72e9a165fa9a3d00" + }, + "equal-current-wide-four-batches": { + "planned_sha256": "7c733a8d16f7faddf0baf1bac0f14e0c13de2ab409d4bbec62a770b1f77d938b", + "recipe_sha256": "b6d202f55ff66dbaa80de913c9c3873240df659d6c6395003997d2ad67966795", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "2cd410e611ef5545b7f29e5191833d42aa754b0e2f5ec34415c35effb9c86c46", + "measured_step": { + "ordinal": 1, + "text": "--- query branch: main\nquery current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "f03599f77637072742bd06b1abb397b69bc5547c3002330198a4f126b2d918ec" + }, + "equal-current-wide-one-batch": { + "planned_sha256": "11e4f0979b96e09251f0630b1b294fa441703e382fbed87c5821543337a9ca50", + "recipe_sha256": "ed6bdf9e457b79db751b006d11bd61ff7e5f9c89af65d906c835e51135861522", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "2cd410e611ef5545b7f29e5191833d42aa754b0e2f5ec34415c35effb9c86c46", + "measured_step": { + "ordinal": 1, + "text": "--- query branch: main\nquery current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "75b32416fb1b9d01e413265fcf1d9332b8d27416406d23d92c4eb39ad2dd6cda" + }, + "finbench-disjoint-merge": { + "planned_sha256": "fa68eb6e74a3297d5e2014c9e7d868e36fd79b41102044bbff219bf9b10b7ef4", + "recipe_sha256": "41476a6e797e77f131c6146c40c9ef8f89d54340a0c66c722a50be65493653cb", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "a8140565e4595e5b5824f5bbb3dcdebb6fa9ba4e87319452fdd132e0fd7c6ec3", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nbranch merge \"bench-source\" into \"bench-target\"\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 600, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 5, + "bound_point_id": "cf41d8ea8f6c34dff16def2a502ed38d6efeb5d60f904aa3ad4b9ac285887e29" + }, + "hot-table-idle-base": { + "planned_sha256": "fc09c57c5f42905335ec0e902e242465f9e1a2fb3d24cbde07d1afa36c116796", + "recipe_sha256": "b4e3ef173926410d1c747f0a859cdcceadbe1d717b41efc50970db3eacba318b", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "41a30481a7c81300f0f1ba2637ccfe5f894b65f9b39e20e7c002ed79b85eb1fa", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery hot_write() { update Hot set { value: 1 } where key = \"hot\" }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "558a4433e0852cea05f1a27f5f97589894ef6d946d2bdf7d64615f6f94298945" + }, + "hot-table-idle-branches-4-aged": { + "planned_sha256": "b9b29f234de2c8c18641ae1c50c928558ebe256a380768cb7d9300c6f191a3c0", + "recipe_sha256": "84b87d96ecee06c11f418996e5ecb273d8f08f59955fdf4c16a3be74fba5fa22", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "23592c6c9ab32fd56cc0dca1216a09ef7f48d099cba75370b0e49b0a9db45610", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery hot_write() { update Hot set { value: 1 } where key = \"hot\" }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "473abbfcf26c56ff14ea9f026ee2ec2391f1542060cfab56255fc42476dbc940" + }, + "hot-table-idle-branches-4": { + "planned_sha256": "5873062f8101e26671ca396a606dda74fa458d53d3075a794f8473fcbd062394", + "recipe_sha256": "5925ef4f593121c780c599aecde366707ed6f2e0b8826172d6c835f9155e3411", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "23592c6c9ab32fd56cc0dca1216a09ef7f48d099cba75370b0e49b0a9db45610", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery hot_write() { update Hot set { value: 1 } where key = \"hot\" }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "b954972b30a9a7c48c906e071bda8c98337bca79c120e037f0937b71412d9da1" + }, + "hot-table-idle-tables-4": { + "planned_sha256": "d8e31bbe7783a5217c3bb491196e055f6a05fdde0b814343c7b3fc643f866830", + "recipe_sha256": "9788e0e6579a7b00ce11fce0ff8842a9f0ddefb9f84609de6bf38dfb59b9627a", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "875d141e4e8650fb14a57d5f1bc60b8107f288eee9fba42bee36452863a1694e", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery hot_write() { update Hot set { value: 1 } where key = \"hot\" }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "17733b0cc4f5dc6e9d198af04e744e08fbf3a3de8164eebdd42dbcad6ce6eea5" + }, + "identity-lifecycle": { + "planned_sha256": "ce1b027e275d6cdb332deb840db63de46f3e8e774deaad88fd01bf81838df4f8", + "recipe_sha256": "bbe06c0e7f7c9b34d68553ef0c0f7cfe4fe4428e36be9733127b2ca00ed5aa2b", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "368843ea03dded64beeb77c225f11f12c44c42432364ae220e4f9b78e8cd4517", + "measured_step": { + "ordinal": 1, + "text": "--- mutate branch: feature\nquery new_lifetime_write() { update Item set { value: 1 } where key = \"alice\" }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "2197f0eb6a1cf8e5d148ddedce8302b46b489c6d593b23d5eff3358ce6b17d76" + }, + "nearest-ranks-updated-embedding": { + "planned_sha256": "3924c636aecde87cea376f46e01ed44255fd06105efdb3b48e200f7367af8a6c", + "recipe_sha256": "a1046296a47d6a5318dcd6d55850dbf91afec416bd14599588c3d688f3ba09a7", + "needs_indices": true, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "9f6e3b64c4ce9380c85a4f5e3bc2384c535da1102f81b0abd6a765eef4fd5cd5", + "measured_step": { + "ordinal": 1, + "text": "--- query\nquery nearest_after_update($q: Vector(4)) {\n match { $d: Doc }\n return { $d.slug }\n order { nearest($d.embedding, $q) }\n limit 6\n}\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "59558ec916cb798ea37a1a48fb8bf8496e2e923f1ffd389503bbda6265ec1a6e" + }, + "nearest-skips-deleted-rows-and-fills-limit": { + "planned_sha256": "fdb29ab01b91ddbb1494f971aa12cc9005f094315d6798f58ba2f1b8f858283e", + "recipe_sha256": "9b79ab2b36bb3e9aa93e174dc3236b78c2cca9904ac1513baf4006a28d46159b", + "needs_indices": true, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "bcd3e6440e4f0e707cdc11de097216038fa589fc8a7af2f4176d9e17971f1f6c", + "measured_step": { + "ordinal": 1, + "text": "--- query\nquery nearest_after_delete($q: Vector(4)) {\n match { $d: Doc }\n return { $d.slug }\n order { nearest($d.embedding, $q) }\n limit 3\n}\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "b03372d8a3a224a3121981d34cfd0bd0ca0807f5062ec92745fe90841d8f4a47" + }, + "parallel-tables-1": { + "planned_sha256": "6a809ebafdbaeb2e63c357068070650e87f83ff96c6dcebdfe38c808126cb705", + "recipe_sha256": "a93baf07c040c531b3b7b5b9e17662f6f495bc8ddc74b512e2dcce1e7d0c4fb4", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "c5eb4a1edad883f1ae31662edca7e267effd01a5873e27b9962eb5df7bd61ac9", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery update_tables() {\n update T0 set { value: 1 } where key = \"row\"\n}\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "97ab7587e284aebea3bb3b85bf72dea4b820169a6099b4248451cb724915ac78" + }, + "parallel-tables-2": { + "planned_sha256": "0725c0eb1bf62980de62fb51afda22fa2b7bb996872b0b6a19f55a68a7eb5316", + "recipe_sha256": "a93baf07c040c531b3b7b5b9e17662f6f495bc8ddc74b512e2dcce1e7d0c4fb4", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "89792d9649cfd72864278101478028fca899f5a7256747a26221c136512c257f", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery update_tables() {\n update T0 set { value: 1 } where key = \"row\"\n update T1 set { value: 1 } where key = \"row\"\n}\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "dc454b7effa6acac773946c5785aee0d8d1c03f01cc9325aafceca081e5602fe" + }, + "parallel-tables-4": { + "planned_sha256": "e44c54a970697ec1fdae65b13ac5010c6c3e57f05bfbb77566507cfdfaf37918", + "recipe_sha256": "a93baf07c040c531b3b7b5b9e17662f6f495bc8ddc74b512e2dcce1e7d0c4fb4", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "c70501f2c099eb3ad05317073669c1d8aab64c3d4dd86e56ed9a80d1cdeb9d8b", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery update_tables() {\n update T0 set { value: 1 } where key = \"row\"\n update T1 set { value: 1 } where key = \"row\"\n update T2 set { value: 1 } where key = \"row\"\n update T3 set { value: 1 } where key = \"row\"\n}\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "f40a90fef2bfeda934b708e07f0429309666f343885ee2b909f6f5439e99e1d7" + }, + "repeated-deletion-recreation-branches": { + "planned_sha256": "c7efbf5c5147fc5884955f8e80dee1f8a63cd115fb9f3fbdd491b4d8e544bbc9", + "recipe_sha256": "56da50274b729be1b7601b30959cb29764e6d50d61923ffc412cbc722bc4c24a", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "e8a478f6b239595767a108dd829c5cb313ba4e67ce984f2d72bbcf2d6aa0d0e6", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nbranch create \"recycled\" from main\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "7bf85e25523ad239aa8aebd2da48a15b2786070b17f218f848b5119eb49ba538" + }, + "repeated-deletion-recreation-rows": { + "planned_sha256": "8fca672576ac37395b90a6104cb5149e0e887b55d72314c0db34ca26fe785b79", + "recipe_sha256": "8371a66502f86d582f8e22a544185a55f167df8097bf48a3ee59a4ab4e2aac90", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "c7c83aad1fba5497e2967546b864e7925954ea76179ddfa8cc8757b3d01b55f3", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery recreate_row() { insert Item { key: \"temporary\", value: 99 } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "ba04e2377b6a646b1541b01bd5d13601820d460b450ee6a1cc3843c6ae7f0bf3" + }, + "threshold-crossings-after": { + "planned_sha256": "816a7ab57ff1c8c452c90fa91b21d3fa11a6a17737538c2f2fa8e94031a37c74", + "recipe_sha256": "d2dd8680bef590f8220c29e1023ccda47e95013af346d1163235dce093dd98e6", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "2f264bedac246dbd8c798c31bfeb1d8f273de002118049e7047e0f0c829a185c", + "measured_step": { + "ordinal": 2, + "text": "--- mutate branch: b\nquery next_publish() { insert Person { name: \"carol\", age: 1 } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "e2bb568ed7242120e06c6fa9449c209cf82d5af82d2e5bbce23231a93017dfcd" + }, + "threshold-crossings-at": { + "planned_sha256": "76b6ab70aeb9138f55b2340925c55932992d24419f9855af3904987e2e3a9499", + "recipe_sha256": "08705667a0439cd0507831c3c55c74eff1f9c98d20140066d17c2bb2f8a3b734", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "2e71d38c22f1c287b33b5c2dde7becd2cbfd57a6aec8c4e7656c65e62a4d4283", + "measured_step": { + "ordinal": 2, + "text": "--- mutate branch: b\nquery next_publish() { insert Person { name: \"carol\", age: 1 } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "eaf136a2d8a42fce0ae6ae61b2d56c07f9426e6f52518a32c7cdbe6260b916b4" + }, + "threshold-crossings-before": { + "planned_sha256": "11e22c2493a374f1f79e327cf14923b35b75378f5e2711408b617654cb0ba680", + "recipe_sha256": "d964d0f0e9e7fe8ddd9982e7a2144af6597cab8803290b7910559bf91f8c8920", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "f6b48d1c7ed4d3c15e67bfcf331b92f6846ca1ceb51ad187266943cbb6368f2a", + "measured_step": { + "ordinal": 2, + "text": "--- mutate branch: b\nquery next_publish() { insert Person { name: \"carol\", age: 1 } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "d631107c5bd456586723cc9b20702e539a0038fb478c96a5b295b379e21d85f1" + }, + "threshold-crossings-production-control": { + "planned_sha256": "1017c799cc1785d9ca3080c3d26b7d50c7ce805f4db8c98b4abd5dbbdf13c303", + "recipe_sha256": "71d701e25eca6fc0fcb1a223008a09c2c035c389f1a6541a05603823d651b4da", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "afcf0001d2fb5af0dfa38cc2cbc7694b9747612c0bf97958c58b7c5821adc3b8", + "measured_step": { + "ordinal": 2, + "text": "--- mutate branch: b\nquery next_publish() { insert Person { name: \"carol\", age: 1 } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "cf2dd956484e7c25f246a23cc750284d928104a746e3d5a9368c660b0b0ca224" + }, + "tiny-branch": { + "planned_sha256": "7ee3201f7763dbff290a6503f1d5d92e848eedcf422375d22c6da7915b40c581", + "recipe_sha256": "1d10330d0bb50c068ec5e433870473b6ddee6e5e2613e31fb6504e40826c0b9f", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "fb3dbc37b64c5adeb40ba4067a075bd133b15d04e1aca62d4379d03aa4a1d6a4", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nbranch create \"child\" from main\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "cff4d6a67a719eaa7172bc9de183c61b879e2f282f8ad0ca1932e131bf02f3fe" + }, + "tiny-load": { + "planned_sha256": "47231690406745afee59fad8a61237be68aa2accac36c8c2fe166a6eff89abf3", + "recipe_sha256": "1d10330d0bb50c068ec5e433870473b6ddee6e5e2613e31fb6504e40826c0b9f", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "4abdf63aedfc03580b6375ef27f049c9dd1f8789e9678ba29254cfd355049eaa", + "measured_step": { + "ordinal": 1, + "text": "--- load generate: v1 seed: 0 mode: append\ntables:\n - kind: node\n name: Item\n rows: 1\n commits: 1\n batch_rows: 1\n columns:\n key: {kind: key, prefix: c, width: 1}\n val: {kind: literal, value: 3}\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "241e592a3046118b0c496292201f834143fbd10af2f0687cebd590905322880d" + }, + "tiny-mutate": { + "planned_sha256": "053419882a5a0e8695c2877bf132c7704d844b340b165045fb484d2458ecc9ef", + "recipe_sha256": "1d10330d0bb50c068ec5e433870473b6ddee6e5e2613e31fb6504e40826c0b9f", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "da588c79ed2cc82c98438e46a9c4efdc3d33bcc471a0a570195e7e6e3948ea92", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery add() { insert Item { key: \"c\", val: 3 } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "0de2d97dcb6d60102f6281a6411f41a4b389b065a7f3a6c7de620b03b0bc993d" + }, + "tiny-post-reopen": { + "planned_sha256": "e9e8911625e1905294d629c47e5d9ea831c0e83041a48886b1abbc2d72854d1f", + "recipe_sha256": "1d10330d0bb50c068ec5e433870473b6ddee6e5e2613e31fb6504e40826c0b9f", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "reopened-after-program", + "page_cache": "program-conditioned", + "program": "gqt-read-set-v1", + "iterations": 1 + }, + "workload_sha256": "0dafe18908eebbd8a00ce11fd76689d3c1a1466a2e14cc66f1ed670bca0e0609", + "measured_step": { + "ordinal": 3, + "text": "--- query branch: main\nquery items() {\n match { $i: Item }\n return { $i.key as key, $i.val as val }\n}\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "5803462bd7fece3f40df52eaf15114c2274a8c997555a6f1028d9705cf1d5246" + }, + "tiny-read": { + "planned_sha256": "fc4bfbd20cafacc800b01941141885f8f1a42f93bd3002ceb0d263b813c0f081", + "recipe_sha256": "1d10330d0bb50c068ec5e433870473b6ddee6e5e2613e31fb6504e40826c0b9f", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "cecbf5383cb61d652ad1e69eb96691441b2cb3eebeb732a0cba077f0a03c972d", + "measured_step": { + "ordinal": 1, + "text": "--- query branch: main\nquery items() {\n match { $i: Item }\n return { $i.key as key, $i.val as val }\n}\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "341e492f636cd3ea6228ca235b1cc1ef7fd45b1fa847c3a7338739384cf9749d" + }, + "tiny-restart": { + "planned_sha256": "4c9c06a103acc5bbcf5d490b2795cd3d65655a80a62b7a3e3fe8c90e9b2b3522", + "recipe_sha256": "1d10330d0bb50c068ec5e433870473b6ddee6e5e2613e31fb6504e40826c0b9f", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "653038c536b9f795bd807ae8d29beaa7a8290eb9ae0b9e28178becde929fdd98", + "measured_step": { + "ordinal": 1, + "text": "--- restart\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "5cea5d0175028cce37ae18fd1127230deec68588b88ffddfd43368bba5002760" + }, + "very-long-history-1000-read": { + "planned_sha256": "8632c258ed5512d2fb27e8f4e0c5340d3cb9bd2d9fed146003c2ef0acdecb3d2", + "recipe_sha256": "702aee2a81b264606e2ca936b2a27816f5b1e6f45b62ae525c559d11b73b7cbc", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "2cacff7b790f1d1758fb365aaff53184cd98591d1cb3a2fc7b0ebe17ba5c70e9", + "measured_step": { + "ordinal": 1, + "text": "--- query branch: main\nquery current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "566d461ac80b9a7f951bb2080941bd9d6b72aa7d4a5860d448c58043c385da12" + }, + "very-long-history-1000-reopen": { + "planned_sha256": "d9ce9bab827d737d2edef00930df5c2263777221db69f7d4a3f1a953441c81c7", + "recipe_sha256": "702aee2a81b264606e2ca936b2a27816f5b1e6f45b62ae525c559d11b73b7cbc", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "cf7ca965aaf3f1f21b86f15d404d076e9e32cb8f3f731613a365f9860e750bc0", + "measured_step": { + "ordinal": 1, + "text": "--- restart\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "7bdbb6de0708ebee2933dc3b3208d974a9120b68f132fb298b66dec0d0d45f4c" + }, + "very-long-history-1000-write": { + "planned_sha256": "bfa976efb74a7b8fcfa7f64204017a2f8164168e999a94de38956587d822de94", + "recipe_sha256": "702aee2a81b264606e2ca936b2a27816f5b1e6f45b62ae525c559d11b73b7cbc", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "0dce5117f90efb547b88a13fcf26ba7a1ae1c906394f8ca834488efc46ac9d40", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery next_write() { update HistoryRow set { value: 1 } where key = \"hot\" }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "e500048d07712d34f3b2f928c09c9f19a9af0c39fd24770a5c2fc178b5bea8ed" + }, + "very-long-history-10000-read": { + "planned_sha256": "fbd05e9a8d754620859a4f4091b13bafef89195b5f5b71192371561a1d6332ec", + "recipe_sha256": "20289499361183e537bf67c7c9ab50337ec3147d8303bebf93e9e93366242865", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "2cacff7b790f1d1758fb365aaff53184cd98591d1cb3a2fc7b0ebe17ba5c70e9", + "measured_step": { + "ordinal": 1, + "text": "--- query branch: main\nquery current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "8caef27559bd7a4b68cf915f771d546dc685690921357645d94fe56edfd8ebba" + }, + "very-long-history-10000-reopen": { + "planned_sha256": "48c6c5b1fe51d500750362cc2ff4702588341e9796607ed8bda9a40db50513a5", + "recipe_sha256": "20289499361183e537bf67c7c9ab50337ec3147d8303bebf93e9e93366242865", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "cf7ca965aaf3f1f21b86f15d404d076e9e32cb8f3f731613a365f9860e750bc0", + "measured_step": { + "ordinal": 1, + "text": "--- restart\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "ca7d63bf804e7a89fc6c99938c455d7bd8a1f84dcb0d5845cf29353fc107f5d0" + }, + "very-long-history-10000-write": { + "planned_sha256": "a5e2e906c9859ffec534ace301ecaa0461c862f28b9e081ac586cc55709bb357", + "recipe_sha256": "20289499361183e537bf67c7c9ab50337ec3147d8303bebf93e9e93366242865", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "0dce5117f90efb547b88a13fcf26ba7a1ae1c906394f8ca834488efc46ac9d40", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery next_write() { update HistoryRow set { value: 1 } where key = \"hot\" }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "9632a510a3daa6ce8638ce94309bd5cd6de5f260bc2a59afc5346bff2ab55f93" + }, + "very-long-history-100000-read": { + "planned_sha256": "596d6b25c1f395a7af86419457920c4d2f0068a9f0198f87e9321902acd695cb", + "recipe_sha256": "916364ba4b48d699405af7c35ade449c6116e3726718073545131e7720a53134", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "2cacff7b790f1d1758fb365aaff53184cd98591d1cb3a2fc7b0ebe17ba5c70e9", + "measured_step": { + "ordinal": 1, + "text": "--- query branch: main\nquery current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "983bdd0e2e2aef4ae4aea9d6a25a2d733f6581ddad483cb884271583d379fce2" + }, + "very-long-history-100000-reopen": { + "planned_sha256": "314c64f1d8245069077a984f2880e1c18629fba298c0a0ad6589978f80cc8d4e", + "recipe_sha256": "916364ba4b48d699405af7c35ade449c6116e3726718073545131e7720a53134", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "cf7ca965aaf3f1f21b86f15d404d076e9e32cb8f3f731613a365f9860e750bc0", + "measured_step": { + "ordinal": 1, + "text": "--- restart\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "c7471c25a0e8bf90fc2b84aadbc63da31820bf51375f15a699cd3091b163c8d3" + }, + "very-long-history-100000-write": { + "planned_sha256": "61d1a62b2520508c876b5cd4336d507727bffcbb65b30cd3f454c317ffe56ba9", + "recipe_sha256": "916364ba4b48d699405af7c35ade449c6116e3726718073545131e7720a53134", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "0dce5117f90efb547b88a13fcf26ba7a1ae1c906394f8ca834488efc46ac9d40", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery next_write() { update HistoryRow set { value: 1 } where key = \"hot\" }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "d4e7ac49cf8901991016475921275b60877ad01bb781a22e616806b20e632576" + }, + "very-long-history-32-read": { + "planned_sha256": "44b689c167d9927d4de356372cea0a22d0eb45b9e8c85f159cec4b349a8adf75", + "recipe_sha256": "ba69422e67a458a8461c55f67ccab8202288ba0e0ba8cdd127e4e3f1a76d5ff6", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "2cacff7b790f1d1758fb365aaff53184cd98591d1cb3a2fc7b0ebe17ba5c70e9", + "measured_step": { + "ordinal": 1, + "text": "--- query branch: main\nquery current_rows() { match { $r: HistoryRow } return { $r.key as key, $r.value as value, $r.payload as payload } }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "b83aa66b368c52be894df39a5a6c3a6d915d281bcb43fb79a0325261587cf52d" + }, + "very-long-history-32-reopen": { + "planned_sha256": "a85f951e4ee851aec468544db60d27fc9de16cf14298aacd857539df5e846f41", + "recipe_sha256": "ba69422e67a458a8461c55f67ccab8202288ba0e0ba8cdd127e4e3f1a76d5ff6", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "cf7ca965aaf3f1f21b86f15d404d076e9e32cb8f3f731613a365f9860e750bc0", + "measured_step": { + "ordinal": 1, + "text": "--- restart\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "003540c32207370748a2fc16f7d174c4692dbbaa3510ca83538b95270fecd992" + }, + "very-long-history-32-write": { + "planned_sha256": "15fcb19c7aad26eed7ebed80b4c48b88e25ca1018840859dd3f347022a00c1d4", + "recipe_sha256": "ba69422e67a458a8461c55f67ccab8202288ba0e0ba8cdd127e4e3f1a76d5ff6", + "needs_indices": false, + "cache_condition": { + "process": "fresh-per-repetition", + "engine": "preparation-only", + "page_cache": "uncontrolled", + "program": "none", + "iterations": 0 + }, + "workload_sha256": "0dce5117f90efb547b88a13fcf26ba7a1ae1c906394f8ca834488efc46ac9d40", + "measured_step": { + "ordinal": 1, + "text": "--- mutate\nquery next_write() { update HistoryRow set { value: 1 } where key = \"hot\" }\n" + }, + "environment": { + "backend": { + "kind": "local-fs", + "filesystem": "apfs", + "storage_class": "nvme-ssd" + } + }, + "protocol": { + "deadline_seconds": 60, + "attribution": "per-phase", + "schedule": "manual", + "reset": "local-clonefile", + "timer": "monotonic" + }, + "repetitions": 1, + "bound_point_id": "b7763606305654dbeeb984b352cc8ddfe35ffe47e73e12f3b161ab493a37428f" + } +} diff --git a/benchmarks/cases/branch-merge-d50-process-cold-xfs.case-v1.yaml b/crates/omnigraph-bench/tests/fixtures/legacy/branch-merge-d50-process-cold-xfs.case-v1.yaml similarity index 100% rename from benchmarks/cases/branch-merge-d50-process-cold-xfs.case-v1.yaml rename to crates/omnigraph-bench/tests/fixtures/legacy/branch-merge-d50-process-cold-xfs.case-v1.yaml diff --git a/benchmarks/cases/branch-merge-d50-warm.case-v1.yaml b/crates/omnigraph-bench/tests/fixtures/legacy/branch-merge-d50-warm.case-v1.yaml similarity index 100% rename from benchmarks/cases/branch-merge-d50-warm.case-v1.yaml rename to crates/omnigraph-bench/tests/fixtures/legacy/branch-merge-d50-warm.case-v1.yaml diff --git a/benchmarks/real-graph/finbench-2026-08-21-sf10-v1.run-v1.yaml b/crates/omnigraph-bench/tests/fixtures/legacy/finbench-2026-08-21-sf10-v1.run-v1.yaml similarity index 100% rename from benchmarks/real-graph/finbench-2026-08-21-sf10-v1.run-v1.yaml rename to crates/omnigraph-bench/tests/fixtures/legacy/finbench-2026-08-21-sf10-v1.run-v1.yaml diff --git a/crates/omnigraph-cli/tests/parity_matrix.rs b/crates/omnigraph-cli/tests/parity_matrix.rs index 752872ea5..3002bb3a5 100644 --- a/crates/omnigraph-cli/tests/parity_matrix.rs +++ b/crates/omnigraph-cli/tests/parity_matrix.rs @@ -16,12 +16,6 @@ use tempfile::TempDir; -#[path = "support/http_bench.rs"] -mod http_bench; -#[path = "support/http_perf_layout.rs"] -mod http_perf_layout; -#[path = "support/http_soak.rs"] -mod http_soak; mod support; use support::*; diff --git a/crates/omnigraph-core/Cargo.toml b/crates/omnigraph-core/Cargo.toml index 0488a94af..6be25c9bd 100644 --- a/crates/omnigraph-core/Cargo.toml +++ b/crates/omnigraph-core/Cargo.toml @@ -14,6 +14,7 @@ dst = ["omnigraph-storage/dst", "omnigraph-seams/install", "dep:lance-io"] test-util = [] [dependencies] +globset = { workspace = true } omnigraph-storage = { path = "../omnigraph-storage", version = "0.13.0" } omnigraph-seams = { path = "../omnigraph-seams", version = "0.13.0" } omnigraph-compiler = { path = "../omnigraph-compiler", version = "0.13.0" } diff --git a/crates/omnigraph-core/src/seams.rs b/crates/omnigraph-core/src/seams.rs index df87d621d..bfe846940 100644 --- a/crates/omnigraph-core/src/seams.rs +++ b/crates/omnigraph-core/src/seams.rs @@ -106,3 +106,5 @@ pub fn contention(seam: &'static DecideSeam) -> Result<()> { let _ = seam; Ok(()) } + +pub mod store; diff --git a/crates/omnigraph-core/src/seams/store.rs b/crates/omnigraph-core/src/seams/store.rs new file mode 100644 index 000000000..b7d9721b9 --- /dev/null +++ b/crates/omnigraph-core/src/seams/store.rs @@ -0,0 +1,85 @@ +/// What the decoration does to one targeted call. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum StoreAction { + Misdirect, + Lose, + Error, + Corrupt, + Delay, +} + +impl StoreAction { + pub const fn as_str(self) -> &'static str { + match self { + StoreAction::Misdirect => "misdirect", + StoreAction::Lose => "lose", + StoreAction::Error => "error", + StoreAction::Corrupt => "corrupt", + StoreAction::Delay => "delay", + } + } + + pub fn parse(name: &str) -> Option { + [ + StoreAction::Misdirect, + StoreAction::Lose, + StoreAction::Error, + StoreAction::Corrupt, + StoreAction::Delay, + ] + .into_iter() + .find(|action| action.as_str() == name) + } + + /// The store effect a decision seam declares for this action, or `None` + /// for an action no seam can fire. + pub const fn store_effect(self) -> Option { + match self { + StoreAction::Misdirect => Some(super::StoreEffect::Misdirect), + StoreAction::Lose | StoreAction::Error | StoreAction::Corrupt | StoreAction::Delay => { + None + } + } + } +} + +/// The largest `subject` a case may carry, the bound the known-failure +/// reason shares. +pub const SUBJECT_MAX_BYTES: usize = 2048; + +/// A case's `subject`, parsed: a `globset` glob over the object's +/// root-relative name with the dialect pinned the same on every host (`*` +/// within one segment, `**` across, case-sensitive, backslash escapes). +#[derive(Clone, Debug)] +pub struct Subject { + matcher: globset::GlobSet, +} + +impl Subject { + /// # Errors + /// Refuses an empty or over-long subject and a glob `globset` cannot + /// build. + pub fn parse(text: &str) -> Result { + if text.is_empty() || text.len() > SUBJECT_MAX_BYTES { + return Err(format!( + "invalid_case: subject must be 1 to {SUBJECT_MAX_BYTES} bytes" + )); + } + let glob = globset::GlobBuilder::new(text) + .literal_separator(true) + .case_insensitive(false) + .backslash_escape(true) + .build() + .map_err(|error| format!("invalid_case: subject is not a glob: {error}"))?; + let mut set = globset::GlobSetBuilder::new(); + set.add(glob); + let matcher = set + .build() + .map_err(|error| format!("invalid_case: subject is not a glob: {error}"))?; + Ok(Self { matcher }) + } + + pub fn matches(&self, name: &str) -> bool { + self.matcher.is_match(name) + } +} diff --git a/crates/omnigraph-dst/Cargo.toml b/crates/omnigraph-dst/Cargo.toml index c965e14b6..199c4841e 100644 --- a/crates/omnigraph-dst/Cargo.toml +++ b/crates/omnigraph-dst/Cargo.toml @@ -27,7 +27,6 @@ rand = { workspace = true } url = { workspace = true } async-trait = { workspace = true } futures = { workspace = true } -globset = { workspace = true } # test-util (Builder::start_paused, virtual clock) is DST-only; keeping # it off the workspace-wide tokio dep keeps it out of the shipping crates. tokio = { workspace = true, features = ["test-util"] } diff --git a/crates/omnigraph-dst/src/store_places.rs b/crates/omnigraph-dst/src/store_places.rs index 7d4372b32..d58739366 100644 --- a/crates/omnigraph-dst/src/store_places.rs +++ b/crates/omnigraph-dst/src/store_places.rs @@ -32,50 +32,7 @@ impl StorePlace { } } -/// What the decoration does to one targeted call. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum StoreAction { - Misdirect, - Lose, - Error, - Corrupt, - Delay, -} - -impl StoreAction { - pub const fn as_str(self) -> &'static str { - match self { - StoreAction::Misdirect => "misdirect", - StoreAction::Lose => "lose", - StoreAction::Error => "error", - StoreAction::Corrupt => "corrupt", - StoreAction::Delay => "delay", - } - } - - pub fn parse(name: &str) -> Option { - [ - StoreAction::Misdirect, - StoreAction::Lose, - StoreAction::Error, - StoreAction::Corrupt, - StoreAction::Delay, - ] - .into_iter() - .find(|action| action.as_str() == name) - } - - /// The store effect a decision seam declares for this action, or `None` - /// for an action no seam can fire. - pub const fn store_effect(self) -> Option { - match self { - StoreAction::Misdirect => Some(omnigraph::seams::StoreEffect::Misdirect), - StoreAction::Lose | StoreAction::Error | StoreAction::Corrupt | StoreAction::Delay => { - None - } - } - } -} +pub use omnigraph::seams::store::{SUBJECT_MAX_BYTES, StoreAction, Subject}; /// The adapter methods the put place covers, one variant per hook, so a hook /// and the row it is admitted against name the method once. @@ -185,47 +142,6 @@ pub fn misdirect_uri(uri: &str) -> String { } } -/// The largest `subject` a case may carry, the bound the known-failure -/// reason shares. -pub const SUBJECT_MAX_BYTES: usize = 2048; - -/// A case's `subject`, parsed: a `globset` glob over the object's -/// root-relative name with the dialect pinned the same on every host (`*` -/// within one segment, `**` across, case-sensitive, backslash escapes). -#[derive(Clone, Debug)] -pub struct Subject { - matcher: globset::GlobSet, -} - -impl Subject { - /// # Errors - /// Refuses an empty or over-long subject and a glob `globset` cannot - /// build. - pub fn parse(text: &str) -> Result { - if text.is_empty() || text.len() > SUBJECT_MAX_BYTES { - return Err(format!( - "invalid_case: subject must be 1 to {SUBJECT_MAX_BYTES} bytes" - )); - } - let glob = globset::GlobBuilder::new(text) - .literal_separator(true) - .case_insensitive(false) - .backslash_escape(true) - .build() - .map_err(|error| format!("invalid_case: subject is not a glob: {error}"))?; - let mut set = globset::GlobSetBuilder::new(); - set.add(glob); - let matcher = set - .build() - .map_err(|error| format!("invalid_case: subject is not a glob: {error}"))?; - Ok(Self { matcher }) - } - - pub fn matches(&self, name: &str) -> bool { - self.matcher.is_match(name) - } -} - /// One rule a case installs on the decoration for one step: the `occurrence`th /// call of `place` whose root-relative name matches `subject` takes `action`. #[derive(Debug)] diff --git a/crates/omnigraph-gqt-core/Cargo.toml b/crates/omnigraph-gqt-core/Cargo.toml new file mode 100644 index 000000000..49830225e --- /dev/null +++ b/crates/omnigraph-gqt-core/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "omnigraph-gqt-core" +version = "0.13.0" +edition = "2024" +description = "GQT format and execution over an existing engine session" +license = "MIT" +publish = false + +[lib] +doctest = false + +[dependencies] +arrow-array = { workspace = true } +arrow-schema = { workspace = true } +futures = { workspace = true } +libm = "=0.2.16" +omnigraph = { package = "omnigraph-engine", path = "../omnigraph", version = "0.13.0" } +omnigraph-compiler = { path = "../omnigraph-compiler", version = "0.13.0" } +omnigraph-planner = { path = "../omnigraph-planner", version = "0.13.0" } +serde = { workspace = true } +serde_json = { workspace = true } +serde_yaml = { workspace = true } +sha2 = { workspace = true } +tokio = { workspace = true } +unsafe-libyaml = "0.2.11" + +[dev-dependencies] +tempfile = { workspace = true } + +[lints] +workspace = true diff --git a/crates/omnigraph-gqt-core/src/concurrent.rs b/crates/omnigraph-gqt-core/src/concurrent.rs new file mode 100644 index 000000000..8dcda4c97 --- /dev/null +++ b/crates/omnigraph-gqt-core/src/concurrent.rs @@ -0,0 +1,428 @@ +use std::{fmt, str::FromStr}; + +pub const MAX_SESSIONS: usize = 4; +const RESERVED_LABELS: [&str; 4] = ["setup", "runner", "step", "order"]; + +/// The store verbs an `order:` entry may name. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Verb { + Get, + Head, + Put, + List, + Delete, + Copy, +} + +impl Verb { + const ALL: [Verb; 6] = [ + Verb::Get, + Verb::Head, + Verb::Put, + Verb::List, + Verb::Delete, + Verb::Copy, + ]; + + pub fn name(self) -> &'static str { + match self { + Verb::Get => "get", + Verb::Head => "head", + Verb::Put => "put", + Verb::List => "list", + Verb::Delete => "delete", + Verb::Copy => "copy", + } + } +} + +impl FromStr for Verb { + type Err = String; + + fn from_str(word: &str) -> Result { + Verb::ALL + .into_iter() + .find(|verb| verb.name() == word) + .ok_or_else(|| { + let names: Vec<&str> = Verb::ALL.iter().map(|verb| verb.name()).collect(); + format!("`order:` verb `{word}` is not one of {}", names.join(", ")) + }) + } +} + +impl fmt::Display for Verb { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.name()) + } +} + +/// What a session's statement is: the executor and the comparator differ. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SessionKind { + Query, + Mutation, +} + +impl SessionKind { + /// The step-kind word the labels and evidence rows carry. + pub fn name(self) -> &'static str { + match self { + SessionKind::Query => "query", + SessionKind::Mutation => "mutate", + } + } +} + +/// One session of a block: a labeled statement on a branch, and the outcome +/// the `--- expect` section after the block names for it. +#[derive(Debug)] +pub struct SessionOp { + pub label: String, + pub branch: String, + pub source: String, + pub name: String, + pub kind: SessionKind, + pub expect: SessionExpect, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SessionExpect { + Ok, + Error { needle: String }, +} + +/// A `--- concurrent` step: its sessions and the script. +#[derive(Debug)] +pub struct ConcurrentStep { + pub ordinal: usize, + pub sessions: Vec, + pub order: Vec, +} + +/// One `order:` entry: which session, and what event of it. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Entry { + pub session: usize, + pub event: Event, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Event { + /// The session's statement begins: the runner holds the session before + /// it, so a session can be made to start inside another's hold without + /// naming a request the engine makes under a lock. + Start, + /// The session's completion, written as the bare label. + Done, + /// The session's next request of `verb` on a key containing `suffix`. + /// `park` holds the session at the request's arrival until its next + /// entry is due, instead of running the request in turn. + Call { + park: bool, + verb: Verb, + suffix: String, + }, +} + +impl Event { + /// Whether `self` is the un-parked form of the parked request `parked`. + pub fn releases(&self, parked: &Event) -> bool { + match (self, parked) { + ( + Event::Call { + park: false, + verb, + suffix, + }, + Event::Call { + park: true, + verb: parked_verb, + suffix: parked_suffix, + }, + ) => verb == parked_verb && suffix == parked_suffix, + (Event::Done, Event::Call { park: true, .. }) => true, + _ => false, + } + } +} + +impl fmt::Display for Event { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Event::Start => f.write_str("start"), + Event::Done => f.write_str("done"), + Event::Call { park, verb, suffix } => { + if *park { + write!(f, "park {verb} {suffix}") + } else { + write!(f, "{verb} {suffix}") + } + } + } + } +} + +/// A session line of the block body before its statement is parsed: the +/// label, the branch (`main` unless `on `), the statement text and +/// the line the statement starts on. +#[derive(Debug, PartialEq, Eq)] +pub struct SessionLine { + pub label: String, + pub branch: String, + pub text: String, + pub line: usize, +} + +/// The block body split into session lines and the script. A session starts +/// at column 0 as `