Skip to content

test(dst): name unreachable crash windows and fix index-build reach - #1035

Merged
ragnorc merged 7 commits into
ModernRelay:mainfrom
ragnorc:test/dst-reach-census-floor
Oct 22, 2026
Merged

ragnorc merged 7 commits into
ModernRelay:mainfrom
ragnorc:test/dst-reach-census-floor

Conversation

@ragnorc

@ragnorc ragnorc commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The DST reach census (dst_window_reach_probe, an ignored instrument no workflow runs) asserted crossed.len() >= 48, a floor set when the crash-window catalog had 66 windows. Windows were removed since, so the census failed on every run, and a count could not say which window went dark. Reviewing that census and the dead-staging work from #1036 also turned up two reach defects in the same harness code, fixed here.

Named unreachable windows

harness::REACH_EXPECTED_DARK lists each window no seeded universe can cross, with its reason.

  • The census fails, naming the window, when a window outside the list stays dark, a listed window crosses, or no seed of a window crosses and one of them trips an oracle (errored). The first seed that crosses wins, since the census asks whether a window is reachable. The floor caught an errored window only when the count dropped.
  • A lib test (expected_dark_windows_are_catalog_windows) keeps every listed name in catalog::CRASH_WINDOWS on every run.
  • The hunt and the fleet's window arm no longer schedule listed windows. The hunt spent 24 crash cells and 8 probe cells on each of the seven listed windows it can schedule: a run now takes 227 universes instead of 451, hits the same 37 windows, and has no window left under "never reached", so a new entry there is a finding.

Each census universe is a pure function of its seed, so a change in reach comes from a code change, and no date or count needs upkeep.

Window Reason
init.after_coordinator_init, init.post_manifest_create Graph birth happens before the universe's probe; dst_birth_contract_sweep owns them
blob_read.post_capture The DST schema has no Blob property
mutation.post_no_effect_pre_gate Crossed only by a no-effect mutation that carries an expected graph head; the workload sends none
branch_merge.between_delete_chunks Needs a merge that deletes more than one chunk of rows (8,192 ids or the write budget's bytes)
classify.fresh_read, cleanup.resolve_branch_snapshot Crossed only for a table with native fork trees, a table fork from before format v11
branch_merge.adopt_after_append_pre_upsert, branch_merge.adopt_after_upsert_pre_delete, branch_merge.adopt_between_insert_chunks A merge adopts a delta only from a forked source table (adopt_advances_head)

No per-window ledger of the 2026-08-12 run was checked in, so that baseline could not be diffed; this list is that ledger from now on.

The dead-staging setup needs its aftermath

A recorded setup crash arms its target. The dead-staging window's setup was ensure_indices.post_phase_b_pre_manifest_commit, which an index build with nothing to build also crosses (table_ops.rs, the no-work branch). In 12 of 30 hunt cells (seeds 1–30, skip 0), such a build recorded the setup without stranding any staging, and the target was then scheduled on a cleanup it could not reach. The setup is now ensure_indices.post_table_effect, which is crossed only after a detached index commit exists. With it, those 12 cells record no setup, and every cell that hit before still hits. dst_setup_crash_needs_its_aftermath pins seed 2, showing both behaviours.

Index-build reach is structural

Index maintenance builds only missing indexes, and so does an Optimize. A sampled Optimize before the recipe's index build therefore left ensure_indices nothing to build. That had made ensure_indices.post_table_effect dark under its old recipe in all three census seeds, and it made the dead-staging setup miss. While a recipe still owes its EnsureIndicesMain, the sampler now draws again instead of emitting an Optimize, so the first index build is an EnsureIndices with the fixture's unbuilt indexes. Over seeds 70001–70020, with the census's probe scenario:

Window Without the hold-back With it
ensure_indices.post_table_effect 15/20 20/20
cleanup.sweep_pre_dead_manifest_delete 16/20 20/20

Only recipes containing EnsureIndicesMain (the ensure_indices family and the dead-staging window) see a different op stream.

Recipes

  • branch_merge.post_table_effect is crossed only when a merged table stages its own effect. A merge into an unchanged main is AdoptSourceState, which only switches pins; AdoptWithDelta and AdoptPureInserts need adopt_advances_head, which no current branch satisfies. The window now shares the diverged-main recipe of branch_merge.rewrite_after_insert_pre_update, which forces RewriteMerged.
  • ensure_indices.post_table_effect takes the family default (insert, then index build). Its old recipe named the milestone branch, but the harness runs every index build on main whatever branch the op names, so the branch was never the cause of it going dark; a sampled Optimize was. The EnsureIndicesBranch milestone had no other user and is removed.
  • milestone_steps also drives the nightly fleet's window arm, so these recipes apply there too.

Smaller fixes

Evidence

Reach census (cd crates/omnigraph-dst && cargo test --locked --test scenarios dst_window_reach_probe -- --ignored --nocapture).

On main before this change (fb984d21), which fails the old floor of 48:

REACH CENSUS: 41/53 windows crossed in ONE seeded universe each
still dark (12): ["blob_read.post_capture", "branch_merge.adopt_after_append_pre_upsert", "branch_merge.adopt_after_upsert_pre_delete", "branch_merge.adopt_between_insert_chunks", "branch_merge.between_delete_chunks", "branch_merge.post_table_effect", "classify.fresh_read", "cleanup.resolve_branch_snapshot", "ensure_indices.post_table_effect", "init.after_coordinator_init", "init.post_manifest_create", "mutation.post_no_effect_pre_gate"]
errored (milestone tripped an oracle — separate finding) (0): []

With this change:

REACH CENSUS: 43/53 windows crossed in ONE seeded universe each
still dark (10): ["blob_read.post_capture", "branch_merge.adopt_after_append_pre_upsert", "branch_merge.adopt_after_upsert_pre_delete", "branch_merge.adopt_between_insert_chunks", "branch_merge.between_delete_chunks", "classify.fresh_read", "cleanup.resolve_branch_snapshot", "init.after_coordinator_init", "init.post_manifest_create", "mutation.post_no_effect_pre_gate"]
errored (milestone tripped an oracle — separate finding) (0): []

Hunt (cargo test --locked --test scenarios dst_hunt_crash_window_sweep -- --exact --ignored --nocapture):

HUNT COMPLETE (227 universes): 37 hit, 3 crossed-but-absorbed, 0 never reached, 3 unschedulable, 10 expected dark
never reached (workload/path gap): []
unschedulable (need schema/init workload ops): ["open.before_schema_contract_read", "read.refresh_post_state_pre_lineage", "storage.local_create_if_absent_probe"]
expected dark (harness::REACH_EXPECTED_DARK, not scheduled): ["blob_read.post_capture", "branch_merge.adopt_after_append_pre_upsert", "branch_merge.adopt_after_upsert_pre_delete", "branch_merge.adopt_between_insert_chunks", "branch_merge.between_delete_chunks", "classify.fresh_read", "cleanup.resolve_branch_snapshot", "init.after_coordinator_init", "init.post_manifest_create", "mutation.post_no_effect_pre_gate"]

Fleet window arms (DST_FLEET_SEEDS=1 DST_FLEET_SEED_BASE=<seed> cargo test --locked --test scenarios dst_fleet -- --exact --ignored --nocapture, seeds 10016, 10028 and 10039):

dst fleet report seed=10016 arm=window:cleanup.sweep_pre_dead_manifest_delete crashes=1 crossed=false hit=false writes=0 acks_lost=0 retries=0 lance=0 legal=0 engine_effects=0 writes_after_effect=0 verdicts=[("crash:ensure_indices.post_table_effect@op0", "Applied", "query"), ("deferred:cleanup.sweep_pre_dead_manifest_delete@op4", "Deferred", "cleanup")] issues=[]
FLEET COMPLETE: 1 seeds, 8 universes, 0 failures
dst fleet report seed=10028 arm=window:branch_merge.post_table_effect crashes=1 crossed=false hit=false writes=0 acks_lost=0 retries=0 lance=0 legal=0 engine_effects=0 writes_after_effect=0 verdicts=[("crash:branch_merge.post_table_effect@op3", "NotApplied", "query")] issues=[]
FLEET COMPLETE: 1 seeds, 8 universes, 0 failures
dst fleet report seed=10039 arm=window:ensure_indices.post_table_effect crashes=1 crossed=false hit=false writes=0 acks_lost=0 retries=0 lance=0 legal=0 engine_effects=0 writes_after_effect=0 verdicts=[("crash:ensure_indices.post_table_effect@op1", "Applied", "query")] issues=[]
FLEET COMPLETE: 1 seeds, 8 universes, 0 failures

Tests

  • cd crates/omnigraph-dst && cargo test --locked --no-fail-fast: lib 54 passed; integration 2 passed, 3 ignored; scenarios 56 passed, 28 ignored (main 584f6f6e merged in)
  • New: dst_setup_crash_needs_its_aftermath (scenarios) and catalog::tests::expected_dark_windows_are_catalog_windows (lib).
  • cargo fmt --all --check, cargo clippy -p omnigraph-dst --all-targets --locked -- -D warnings -W clippy::dbg_macro, the crate's banned_words_lint.
  • cargo deny --locked check passes on the merged lockfile, which carries main's rustls-webpki 0.103.16 and webpki-roots/webpki-root-certs 1.0.10 (RUSTSEC-2026-0381/0382/0383).

The reach census asserted 48 crossed windows, a floor set when the
catalog had 66; on main it measured 40/52 and failed every run.

Two windows had gone dark because their recipes aimed at shapes that
existed only while branches created table forks. branch_merge.post_table_effect
needs a merged table that stages its own effect, and a merge into an
unchanged main only switches pins, so it now takes the diverged-main
rewrite recipe. ensure_indices.post_table_effect built indexes on the
milestone branch; on main the first index build of a table crosses it,
so it now takes the family default, and the branch milestone goes.

The census measures 42/52. The floor is 40, and its comment names why
each of the ten dark windows cannot be reached.
@cursor

cursor Bot commented Oct 17, 2026

Copy link
Copy Markdown

Review of 97ff9339 — recommendation: approve

No blocking findings. Three optional findings and one PR-description note, each as an inline comment.

Why, what, how, impact

Why. The reach census (dst_window_reach_probe) is an ignored instrument. Its floor was >= 48, set when the catalog had 66 windows. The catalog now has 52. On main the census crosses 40 windows, so it fails on every run and cannot report a regression.

What. The PR sets the floor to 40 (measured 42) and names the ten dark windows with their reasons. It gives two windows new milestone recipes. branch_merge.post_table_effect now uses the diverged-main recipe. ensure_indices.post_table_effect now uses the family default (an insert, then an index build on main). It removes the unused EnsureIndicesBranch milestone.

How I checked. I used clean worktrees at the exact base and head commits. I ran the census, the full DST crate suite, and the nightly fleet's window arm for the two changed windows. I read the engine sites of every window that the floor comment names.

Impact. The change is in the test harness only. It does not change the engine, storage, format, or API. No DST cost-golden row changes: no labeled_cost_rows scenario uses reach_target. The recipe change also affects the nightly dst_fleet window arm, because that arm uses reach_target too (see the inline note on harness.rs:825).

Validation

Commit Command (from crates/omnigraph-dst) Result
base 0b5e17fa cargo test --locked --test scenarios dst_window_reach_probe -- --exact --ignored --nocapture REACH CENSUS: 40/52, 12 dark, panic milestone reach regressed below the measured 50 (40 crossed): fails, as the PR says
head 97ff9339 same REACH CENSUS: 42/52, 10 dark (both recipe windows left the dark list), 1 passed
head 97ff9339 cargo test --locked --no-fail-fast lib 53 passed; integration 2 passed, 3 ignored; scenarios 51 passed, 28 ignored
head 97ff9339 DST_FLEET_SEEDS=1 DST_FLEET_SEED_BASE=10047 and =10006 cargo test --locked --test scenarios dst_fleet -- --exact --ignored --nocapture crash:branch_merge.post_table_effect@op5 (NotApplied), crash:ensure_indices.post_table_effect@op2 (Applied); each run reports 0 failures
base 0b5e17fa same fleet seeds also crash at op5 and op3; each run reports 0 failures
head + temporary edit (reverted) census with the old ensure-indices sequence, but EnsureIndicesMain still dark (41/52); see the inline comment on harness.rs:786

The CI and DST workflows passed on exact head 97ff9339, including DST pinned suite, Lint (clippy), and Format (rustfmt). CI does not run the census.

Regression proof. The same command fails on base for the predicted reason (40 < 48). It passes on head (42 ≥ 40), and the two re-pointed windows move from dark to crossed. GQT cannot express this defect. It is in the recipes and floor of a DST instrument, not in rows, counts, column types, or errors. The existing owner is the DST scenario test, and the PR changes that test.

Findings

Blocking: none.

Optional:

  1. scenarios.rs:3482-3498: replace the count floor with an executable expected-dark set. This is the main liability point; details are inline.
  2. harness.rs:786: the reason given for the ensure-indices recipe does not match the code. The new recipe also depends on seed order: an earlier sampler Optimize pre-empts the window.
  3. scenarios.rs:3417: stale probe text just outside the hunk (66-window ignore message, "recovery internals", a run command that does not work from the root).

Note: harness.rs:825: please say in the PR body that this change also affects the nightly fleet's window arm.

Tradeoffs and liability

  • Removed: an instrument that was always red. Also removed: a misleading milestone. EnsureIndicesBranch claimed branch scope, but exec_op runs db.ensure_indices() on the session's branch, which is main. Net −7 lines.
  • Added: a new magic number (40) and a dated prose list ("42/52 on 2026-10-16"). Both need a manual edit after every catalog change. test(dst): reach the dead-staging sweep window #1034 already makes the list stale (53 windows). With a fixed floor, each new crossing window adds slack. After test(dst): reach the dead-staging sweep window #1034, three existing windows could go dark without a failure. This PR had to exist for the same reason: no per-window ledger was checked in. Optional finding 1 removes that liability, and it is about the same amount of code.
  • Overlap. test(dst): reach the dead-staging sweep window #1034 adds the 53rd window, and test(cleanup): qualify sweep retries across storage and DST scheduling #1036 replaces census_setup and edits the census body. The conflicts are text only. The PR that lands second must measure again and restate the dark list. With finding 1 it adds one entry instead.
  • Lance direction. optimize.rs notes that Lance 11 folds indexes only through a linear commit. A later Lance version can change how optimize and index builds behave, and with that, which maintenance windows cross. A named set reports the exact window that changed. A count does not.

Limits

  • I ran the census once per commit on one machine. Universes are pure functions of their seeds, so I did not repeat the runs.
  • I did not run the full nightly fleet or the hunt. My fleet evidence covers only the two seeds that land on the changed windows.
  • I did not run clippy locally. I rely on the exact-head Lint (clippy) job.
  • This review makes no performance claims.

Comment thread crates/omnigraph-dst/tests/scenarios.rs Outdated
Comment thread crates/omnigraph-dst/src/harness.rs
Comment thread crates/omnigraph-dst/src/harness.rs
Comment thread crates/omnigraph-dst/tests/scenarios.rs Outdated
A count floor could not say which window went dark, and its slack grew
with every window added. REACH_EXPECTED_DARK lists each window the census
cannot cross, with its reason; the census now fails, naming the window,
when another window stays dark, a listed one crosses, a listed name left
the catalog, or a universe trips an oracle.

ensure_indices.post_table_effect went dark because a sampled Optimize
builds the missing indexes before the first EnsureIndices in all three of
its seeds, not because its recipe named a branch: the harness runs every
index build on main. The recipe note says so.

The probe's doc describes the current census and a run command that
works. Two nits from the dead-staging review: the pin drops its redundant
window_hit check, and the fleet comment says a setup crash runs first.
@ragnorc ragnorc changed the title test(dst): re-baseline the reach census floor test(dst): name the windows the reach census cannot cross Oct 20, 2026

ragnorc commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Review of b0dc0e94 — recommendation: approve

No blocking findings. Two optional findings. The three optional findings from the review of 97ff9339 are resolved. One sentence in the ensure-indices note is still false.

Why, what, how, impact

Why. The reach census is an ignored DST instrument. Its old check was a count (crossed >= 48). A count cannot name the window that went dark. The allowed gap also grows each time a window is added.

What. REACH_EXPECTED_DARK is now the list the census checks. The census fails, and the message names the window, when a window outside the list stays dark, a listed window crosses, or a listed name is no longer in catalog::CRASH_WINDOWS. An oracle trip fails the census when no seed of that window crosses. The two milestone recipes are the ones from the previous head. branch_merge.post_table_effect uses the diverged-main rewrite. ensure_indices.post_table_effect uses an insert, then an index build on main. The probe doc now describes this census.

How I checked. I used a clean worktree at b0dc0e94. I ran the documented census on current main (85a46138, same DST code as fb984d21) and on this head. I then edited the list in that worktree, reran the census, and restored the file. I read the engine sites the ten reasons name. I logged the ops for the recipe seeds and for fleet seeds 10028 and 10039.

Impact. The change is in the DST harness only. It does not change the engine, storage, format, or API. No DST cost-golden row changes. The same recipes drive the nightly fleet window arm.

Prior findings

  1. Resolved. The count floor is gone. REACH_EXPECTED_DARK is the check. A temporary list (I removed blob_read.post_capture, and I added branch_control.pre_gates and renamed.away) failed in one run:
milestone reach changed: newly dark ["blob_read.post_capture"], listed dark but crossed ["branch_control.pre_gates"], listed but not in the catalog ["renamed.away"], errored []

I restored the file. Nothing from that edit is in the branch.

  1. Resolved on the mechanism. One sentence is still false. The branch was never the cause. exec_op runs db.ensure_indices() on the session branch, which stays main. Optimize and EnsureIndices both build only a missing index (has_btree_index is true once any btree exists). An earlier Optimize leaves this window nothing to build. The new note says that. Its last sentence does not match the seeds. Details are inline.

  2. Resolved. The ignore line no longer says 66. The doc no longer mentions recovery windows. The documented command is cd crates/omnigraph-dst && cargo test --locked --test scenarios dst_window_reach_probe -- --ignored --nocapture, and that command works from the crate directory. The function doc says the loop tries up to three seeds. The tally line still prints ONE seeded universe each.

Fleet note: resolved. The PR body says these recipes also drive the nightly fleet window arm. On this head, seed 10028 crashes at branch_merge.post_table_effect@op3 (NotApplied, the mstone merge after the diverged-main steps). Seed 10039 crashes at ensure_indices.post_table_effect@op1 (Applied, the index build, with no Optimize before it).

The list

REACH_EXPECTED_DARK is the right single source of truth for which windows this census can cross. The names are the check. The reason strings sit beside the names. Nothing executes the reasons. A new dark window, a window that starts to cross, or a rename fails the census by name. The next change of this kind adds or removes one entry.

The ten reasons still match the engine on this head (Lance 13, including #1016):

  • The probe is installed after Omnigraph::init_with_storage. dst_birth_contract_sweep owns the two init windows.
  • The DST schema has no Blob property (lib.rs still says there is no blob workload).
  • mutation.post_no_effect_pre_gate runs only when the caller set an expected graph head and the mutation staged nothing. The DST workload never sets that head.
  • branch_merge.between_delete_chunks runs only between delete chunks. A chunk ends at 8,192 ids or at the write budget's filter bytes. The workload's deletes stay in one chunk.
  • classify.fresh_read and cleanup.resolve_branch_snapshot run only when a table has native fork trees. branch_create clones __manifest only. Current writers do not create a table fork.
  • The three adopt_* windows need adopt_advances_head: the source entry has native_dataset_branch, and the target has none. A current branch does not create that fork.

Tradeoffs and liability

Removed: an instrument that failed on every run, and a floor that could not name the window.

Added: one list that must change when reach changes. That edit is the record. The reasons can go stale, because nothing reads them. They stay cheap while they sit in the same const as the names.

ensure_indices.post_table_effect is reached by one of its three census seeds. Seeds 40022 and 60022 sample Optimize before the first EnsureIndices and stay dark. Seed 50022 does not, and it crosses. If that seed also samples Optimize first, the census fails with newly dark ["ensure_indices.post_table_effect"]. That is the outcome the list is for.

Lance 13 stores an index as separate segments, and a segment need not cover every fragment. OmniGraph treats an existing btree as present even when a later fragment is uncovered (has_btree_index in dataset_index.rs). A later Lance release can change that check, and with it which maintenance windows cross. The named list reports the window. A count would not.

Open PRs #1086, #1096, and #1097 also edit scenarios.rs. Their patches do not touch this census. This head merges cleanly with main 85a46138 (git merge-tree --write-tree exit 0). The only commit on main after the branch's merge of fb984d21 is the server route fix #1091.

Validation

Commands for the census start in crates/omnigraph-dst.

Commit Command Result
main 85a46138 cargo test --locked --test scenarios dst_window_reach_probe -- --ignored --nocapture REACH CENSUS: 41/53, 12 dark (the ten listed windows plus branch_merge.post_table_effect and ensure_indices.post_table_effect), errored empty, panic milestone reach regressed below the measured 50 (41 crossed)
head b0dc0e94 same REACH CENSUS: 43/53, the 10 dark names are exactly REACH_EXPECTED_DARK, errored empty, 1 passed in 135.77s
head, temporary list, then restored same panic names newly dark ["blob_read.post_capture"], listed dark but crossed ["branch_control.pre_gates"], listed but not in the catalog ["renamed.away"]
head b0dc0e94 cargo test --locked --no-fail-fast lib 53 passed. integration 2 passed, 3 ignored. scenarios 53 passed, 28 ignored
head b0dc0e94 cargo clippy -p omnigraph-dst --all-targets --locked -- -D warnings -W clippy::dbg_macro exit 0, finished in 4m 23s

CI on this exact commit is green, including DST pinned suite and Lint (clippy). CI does not run the census. Local results above are separate from that CI.

Regression proof. GQT cannot express this defect. The defect is the floor and the recipes of a DST instrument. The owner is dst_window_reach_probe. The same command fails on main 85a46138 for the predicted reason (41 crossed, old floor 48, message cites the measured 50). It passes on b0dc0e94 (43 crossed, dark set equals the list).

Limits

  • I ran each census once, on one machine. Each universe is a pure function of its seed.
  • Fleet evidence here is the window arm for seeds 10028 and 10039. I did not run the other seven universes of dst_fleet for those seeds.
  • This review makes no performance claims.

Optional inline findings

1. crates/omnigraph-dst/src/harness.rs:865

Optional. The first two sentences match the code. The last sentence does not.

exec_op runs EnsureIndices as db.ensure_indices() on the session branch, which stays main. plan_index_work_node adds a btree only when has_btree_index is false, and has_btree_index is true once any btree exists. apply_optimize_table_effects builds that same missing index. An earlier Optimize leaves ensure_indices.post_table_effect nothing to commit.

I logged the three census seeds for this window (catalog index 22, so seeds 40000 + 22, 50000 + 22, 60000 + 22):

  • seed 40022: Optimize at op1, then EnsureIndices at op2. crossed=false
  • seed 50022: EnsureIndices at op1, and no Optimize before it. crossed=true
  • seed 60022: Optimize at op0, then EnsureIndices at op4. crossed=false

The census reports the window as crossed because seed 50022 crosses. Two of the three seeds do sample Optimize first.

Please change the last sentence. The census crosses this window on seed 50022 only. The PR body says the same false sentence ("none of them samples an Optimize first").

2. crates/omnigraph-dst/tests/scenarios.rs:3692

Optional. The loop below keeps a cross over an earlier error. The arm Ok(report) if report.crossed sets the verdict and breaks. The comment on the loop says "first cross wins".

This sentence says no universe may trip an oracle. The PR body says the same. An error fails the census when no seed of that window crosses. A later seed that crosses replaces the error.

Please say that here, and in the PR body. The loop is the right rule. The census asks whether the window is reachable.

A recorded setup crash arms its target, but the dead-staging window's
setup, ensure_indices.post_phase_b_pre_manifest_commit, is crossed by an
index build with nothing to build as well. In 12 of 30 hunt cells such a
build recorded the setup without stranding any staging, and the target
was then scheduled on a cleanup it could not reach. The setup is now
ensure_indices.post_table_effect, crossed only after a detached index
commit; dst_setup_crash_needs_its_aftermath pins seed 2.

An Optimize builds missing indexes too, so while a recipe still owes its
index build the sampler draws again instead of emitting one: the first
index build is an EnsureIndices with the fixture's indexes to build,
which makes ensure_indices.post_table_effect structural rather than a
property of its seeds.

REACH_EXPECTED_DARK moves into the harness. The census asserts it, a lib
test keeps its names in the catalog, and the hunt and the fleet no
longer schedule its windows.
@ragnorc ragnorc changed the title test(dst): name the windows the reach census cannot cross test(dst): name unreachable crash windows and fix index-build reach Oct 20, 2026

ragnorc commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Review of 1488664c — recommendation: approve

No blocking findings. One optional finding, carried forward from b0dc0e94.

Why, what, how, impact

Why. A recorded setup crash arms its target. The old setup seam also runs when an index build has nothing to commit. The dead-staging window then waits for a staging that does not exist.

What. The setup is now ensure_indices.post_table_effect. That seam runs only after a detached index commit. While a recipe still owes EnsureIndicesMain, the sampler draws again when the draw is Optimize. REACH_EXPECTED_DARK now lives in the harness. The census, a lib test, the hunt, and the fleet read that one list.

How I checked. I read the empty-target branch and the cleanup sweep in the engine. I read has_btree_index_on. I read the Lance index page and the Lance transaction page for the commit rule this seam sits on. I ran the new pin, the dead-staging pin, the catalog guard, and the reach census at this head. I then put the old setup window back for one run of the new pin, and restored the file.

Impact. The change is in the DST harness only. It does not change the engine, storage, format, or API. No cost-golden row changes. The redraw changes the op stream only for a recipe that still contains EnsureIndicesMain.

Prior findings from b0dc0e94

  1. Resolved. The false last sentence is gone. The sampler holds Optimize back while the recipe still owes its index build. Census index 22, ensure_indices.post_table_effect, now crosses on seed 40022. That seed stayed dark at b0dc0e94. The census stops at the first cross, so this run did not execute seeds 50022 and 60022.

  2. Open. The probe doc still says that no universe may trip an oracle. The loop still keeps a later cross over an earlier error. The PR body says the same thing ("any universe trips an oracle"). Details are inline.

The delta

maintain_indices_for_branch takes the empty-target branch when targets is empty. That branch calls fail on ENSURE_INDICES_POST_PHASE_B_PRE_MANIFEST_COMMIT and does not call commit_staged_detached. ENSURE_INDICES_POST_TABLE_EFFECT sits after commit_staged_detached. A crash there leaves a detached version. sweep_table calls CLEANUP_SWEEP_PRE_DEAD_MANIFEST_DELETE only when dead_stagings() is non-empty.

Hunt cell seed 2 does not set reach_target, so the redraw does not apply. DST_OP_LOG=1 shows Optimize at op 2 and EnsureIndices at op 13. With the old setup, the cell records crash:ensure_indices.post_phase_b_pre_manifest_commit@op13 (Applied) and does not hit the cleanup window. With the new setup, the same cell records no crash.

dst_dead_staging_sweep_window_is_reached_and_retried still reaches the window. Fleet seed 40052 records crash:ensure_indices.post_table_effect@op4 (Applied) and deferred:cleanup.sweep_pre_dead_manifest_delete@op8. Hunt seed 9 records the same pair at op 4 and op 11.

The census at this head reports 43/53. The 10 dark names are exactly REACH_EXPECTED_DARK. errored is empty. These four windows each cross on their first seed: ensure_indices.post_phase_b_pre_manifest_commit (40020), ensure_indices.post_stage_pre_commit_btree (40021), ensure_indices.post_table_effect (40022), and cleanup.sweep_pre_dead_manifest_delete (40052). No listed window crossed. No unlisted window stayed dark.

catalog::tests::expected_dark_windows_are_catalog_windows checks that every listed name is in CRASH_WINDOWS. The census no longer repeats that check. The list has one home.

has_btree_index_on is true when any user index on the column carries BTreeIndexDetails. It does not read fragment_bitmap. Lance says index segments need not cover every fragment, and an index enters the table when its transaction commits a manifest. OmniGraph writes that manifest as a detached commit. The empty-target path never asks Lance to commit.

GQT cannot express this defect. The defect is which DST seam a setup crash arms, and whether a hunt cell records a crash. The owner is the DST scenario test. The PR adds dst_setup_crash_needs_its_aftermath.

Tradeoffs and liability

Removed: a setup that armed a cleanup crash when no staging existed. Also removed: seed order as the reason ensure_indices.post_table_effect crosses under a reach recipe.

Added: one redraw rule. The loop has no trip limit. Optimize is one face of the data die, so the loop ends. A later change that rejects more ops should give the loop a bound.

The hunt and the fleet no longer schedule the ten dark windows. A window that starts to cross stays out of those runs until someone removes its list entry. The census still names it. The census stays ignored, as before.

The next change of this kind adds or removes one list entry, or one setup pair. It does not add a second list. The redraw must name any new op that builds the missing indexes. Today that op is Optimize, through the same plan_index_work_on_dataset_for_catalog path as EnsureIndices.

This head merges cleanly with main b692610c (git merge-tree --write-tree exit 0). Open PRs #1092, #1096, #1097, and #1102 also touch the tree. Their overlap with this diff is text in shared files, where they touch them at all.

Validation

Commands start in crates/omnigraph-dst. The before row uses this head with setup_crash_for restored to the pre-manifest window, then restored again. Engine sources match b0dc0e94. The hunt cell does not set reach_target, so the redraw is off on both sides of that row.

Commit Command Result
head with the old setup window cargo test --locked --test scenarios dst_setup_crash_needs_its_aftermath -- --exact --nocapture fail. left: 1, right: 0. Verdict crash:ensure_indices.post_phase_b_pre_manifest_commit@op13 (Applied). The cleanup window is absent
1488664c same 1 passed in 3.51s. DST_OP_LOG=1: seed 2 has Optimize at op 2 and EnsureIndices at op 13. The new setup records no crash
1488664c cargo test --locked --test scenarios dst_dead_staging_sweep_window_is_reached_and_retried -- --exact --nocapture 1 passed in 11.23s. Fleet and hunt both defer the cleanup window after the new setup
1488664c cargo test --locked --test scenarios dst_setup_crash_waits_for_a_crossed_window -- --exact --nocapture 1 passed
1488664c cargo test --locked --lib catalog::tests::expected_dark_windows_are_catalog_windows -- --exact 1 passed
1488664c cargo test --locked --test scenarios dst_window_reach_probe -- --ignored --exact --nocapture REACH CENSUS: 43/53. Dark set equals REACH_EXPECTED_DARK. errored empty. 1 passed in 120.75s

CI on exact head 1488664c: DST run 39488091975 success, including DST pinned suite. Format (rustfmt), Lint (clippy), and Test Workspace success (run 39488091995). CI Gate fails because Dependency Guard (cargo deny) reports RUSTSEC-2026-0382 on rustls-webpki 0.103.15. main b692610c has the same lock line. main CI succeeded at 16:08 UTC. This run failed at 19:59 UTC. This diff does not change Cargo.lock. CI does not run the census.

Limits

  • The before row is the old setup window on this head, not a rebuild of b0dc0e94. The engine files are the same. The hunt cell does not use the redraw.
  • I did not re-run the hunt. The PR body reports 227 universes, 37 hit, and 0 never reached.
  • I did not re-run the 20-seed table in the PR body. The census shows that seed 40022 now crosses.
  • I ran each test once. Each universe is a pure function of its seed.
  • This review makes no performance claims.

Inline comment

crates/omnigraph-dst/tests/scenarios.rs line 3699, side RIGHT:

Optional. This sentence is still false. The loop below keeps a cross over an earlier error. The arm Ok(report) if report.crossed sets the verdict and breaks. The comment on the loop says "first cross wins".

An error fails the census when no seed of that window crosses. A later seed that crosses replaces the error. The PR body says the same thing ("any universe trips an oracle").

Please say that here, and in the PR body. The loop is the right rule. The census asks whether the window is reachable.

The census keeps the first seed that crosses a window, so a seed that
trips an oracle fails the census only when no seed of that window
crosses. The doc said no universe may trip an oracle.
@ragnorc

ragnorc commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Thanks. The open finding is fixed in 910ea3f: the probe doc now says that the first seed that crosses a window wins, so a seed that trips an oracle fails the census only when no seed of that window crosses (errored), and the PR body says the same. Main (584f6f6e) is merged in for the cargo deny advisories (RUSTSEC-2026-0381/0382/0383), which it fixed with rustls-webpki 0.103.16 and webpki-roots/webpki-root-certs 1.0.10; cargo deny --locked check passes locally. On the merged head the DST suite passes, the census reports 43/53 with exactly REACH_EXPECTED_DARK dark, and clippy is clean.

@ragnorc
ragnorc enabled auto-merge October 22, 2026 02:28

ragnorc commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Review of 3df1edf9 — recommendation: approve

No blocking findings. No optional findings. The open finding from the review of 1488664c is resolved.

Why, what, how, impact

Why. The review of 1488664c asked for one documentation change. The census keeps the first seed that crosses a window. A seed that trips an oracle fails the census only when no seed of that window crosses. The probe doc said that no universe may trip an oracle.

What. 910ea3fb rewrites that doc. The probe doc now states the rule above. The PR body states the same rule. Two merges bring main in: 538582d0 (through 584f6f6e) and 3df1edf9 (through 7fff9dfd). The diff against main is still the four DST files. This branch changes no engine, storage, or API behavior.

How. I compared the new doc with the seed loop. I checked the engine changes in those merges against the census, the index-build hold-back, and the publication seams. I ran the census at this head.

Impact. The comment matches the loop. The merged engine leaves the reach set unchanged. 43 of 53 windows cross. The 10 dark names are REACH_EXPECTED_DARK. errored is empty. A successful manifest put returns on the first answer, so the re-issue path does not move a census window.

Earlier finding

Resolved. In dst_window_reach_probe, the arm Ok(report) if report.crossed sets the verdict and stops the seed loop. An Err remains only while no later seed of that window crosses. The function doc in crates/omnigraph-dst/tests/scenarios.rs and the PR body now say this. The census still fails when errored is not empty.

The findings from the review of 97ff9339 stay resolved: the named dark list, the ensure-indices note, the probe wording, and the fleet note in the PR body. This delta does not reopen them.

Merged main and the harness

main since fb984d21 (the parent base of 1488664c) changes publication, table writes, and the loader. Those commits add no seam. They leave harness.rs unchanged.

  • A manifest put that succeeds records ManifestRequest::Landed and returns. Re-issue runs after an ambiguous failure (resolve_manifest_request in crates/omnigraph-core/src/lance_clone.rs). Lance writes that manifest with put-if-not-exists. The census injects no storage fault. Each publication still crosses graph_publish.before_commit_append and graph_publish.after_manifest_commit once. Both names are in the crossed list at this head.
  • optimize still plans missing indexes through plan_index_work_on_dataset_for_catalog. The sampler still holds Optimize back while a recipe owes EnsureIndicesMain. No new sampler op builds indexes. ensure_indices.post_phase_b_pre_manifest_commit, ensure_indices.post_stage_pre_commit_btree, ensure_indices.post_table_effect, and cleanup.sweep_pre_dead_manifest_delete each cross on the first census seed.
  • The second merge (97788d37, 7fff9dfd) changes the server WWW-Authenticate header, docs, and the README. It leaves the engine and DST untouched.
  • The first merge adds writer_buffer_cost_rows, dst_publication_requests_get_a_definite_outcome_issue_1067, and dst_successor_takes_over_a_dead_owners_lease_issue_1067. None of them sets reach_target. cost_table.txt matches main.

Tradeoffs and liability

The doc change removes a false sentence. The code rule stays the rule the census already runs. A window is reachable when one seed crosses. An oracle trip with no cross stays a census failure. This commit adds no type, list, or branch.

A later edit of the same kind is one sentence beside the loop. The hold-back still names only Optimize. A new op that builds indexes has to join that match. main added no such op.

Open PR #1124 changes publication_in_doubt from a bool to an option and edits one assertion in harness.rs. That is a text overlap with this branch. Open PR #818 changes write cost and cost_table.txt. This branch leaves that file equal to main. The two diffs compose.

Validation

Head 3df1edf945b587ba5a4daaa6e3a1fd3373bc3128. Commands run from crates/omnigraph-dst.

Commit Command Result
3df1edf9 cargo test --locked --test scenarios dst_window_reach_probe -- --ignored --exact --nocapture REACH CENSUS: 43/53. Dark names equal REACH_EXPECTED_DARK. errored empty. 1 passed in 128.59s
3df1edf9 cargo test --locked --test scenarios dst_setup_crash_needs_its_aftermath -- --exact --nocapture 1 passed in 3.65s
3df1edf9 cargo test --locked --lib catalog::tests::expected_dark_windows_are_catalog_windows -- --exact 1 passed

Census dark names: blob_read.post_capture, branch_merge.adopt_after_append_pre_upsert, branch_merge.adopt_after_upsert_pre_delete, branch_merge.adopt_between_insert_chunks, branch_merge.between_delete_chunks, classify.fresh_read, cleanup.resolve_branch_snapshot, init.after_coordinator_init, init.post_manifest_create, mutation.post_no_effect_pre_gate.

CI on this head: DST run 39711550558 success (DST pinned suite). Format (rustfmt), Lint (clippy), Test Workspace, and Dependency Guard (cargo deny) success in run 39711550552. GQ Logic Tests run 39711550485 success. The CI workflow is red because Azure Deployment Validation could not pull mcr.microsoft.com/azure-cli (connection reset by peer, exit 125). The CI Gate job succeeded. main 7fff9dfd CI succeeded (run 39709020616). CI does not run the census.

Regression proof. This delta changes a comment. GQT cannot express that comment. A test cannot fail before the change for a reason the comment causes. The reach contract under the merged engine is the census above. I added no temporary case.

Limits

  • I ran the census once. Each universe is a pure function of its seed.
  • I did not re-run the hunt or the fleet. This delta changes no recipe.
  • I did not re-run the full DST crate locally. The pinned suite on this head succeeded in CI.
  • This review makes no performance claims.

Findings

Blocking: none.

Optional: none.

@ragnorc
ragnorc added this pull request to the merge queue Oct 22, 2026
Merged via the queue into ModernRelay:main with commit e60eb01 Oct 22, 2026
52 of 53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant