Experiment 164: EQP Rowid Dirty Elision

Date: 2026-06-14

Status: Rejected

Direction:stream-rerun-dispatch, measurement-system

Archive:archive/exp-164

Problem

Exp 134 showed that row-level dirty precision can collapse keyed-PK miss-path

work: only writes touching watched rowids need to re-query a stream shaped like

WHERE id = ?. That implementation was rejected because it relied on a custom

SQL recognizer.

The remaining question was whether SQLite could provide enough evidence to keep

the same optimization private without growing a resqlite SQL grammar.

Hypothesis

Use SQLite's planner instead of parsing SQL text. If EXPLAIN QUERY PLAN

reports an INTEGER PRIMARY KEY rowid lookup for a one-parameter, one-table

stream query, then StreamEngine can attach a private rowid dependency and the

native writer can publish dirty rowids captured by the preupdate hook.

The change would be worth keeping if rowid stream setup or keyed-PK dispatch

improved while unrelated stream registration and stream dispatch guardrails

stayed neutral.

Approach

The archived candidate added:

whenever row precision is absent or unreliable;

one-int-parameter, one-table streams and looks for SQLite's rowid lookup

detail;

registrations share the planner inspection;

setup as the primary lane and text/indexed-int stream setup as guardrails;

invalidation wins cannot hide slower initial stream registration.

The production runtime candidate was removed after measurement. The Tracelite

guardrail additions remain because they make future setup-heavy stream changes

easier to evaluate.

Results

Focused initial-drain Tracelite A/B:

 dart run benchmark/run_tracelite_experiment.dart \ --tracelite-root=/Users/dan/Coding/tracelite \ --baseline-root=/Users/dan/.codex/worktrees/resqlite-exp163-baseline \ --candidate-root=/Users/dan/.codex/worktrees/resqlite-exp164-eqp-rowid-elision \ --label=exp-164-rowid-plan-cache \ --direction=stream-initial-drain \ --runs=2 --min-repetitions=5 --max-repetitions=12 \ --out-dir=build/tracelite-experiments/exp-164-rowid-plan-cache 
ScenarioDeltaVerdictMax CVp
stream-initial-drain-rowid-2.33%neutral10.97%0.945
stream-initial-drain-indexed-int+1.49%neutral/pass7.38%0.323
stream-initial-drain-text+5.69%too_noisy33.10%0.370

Decision: inconclusive. Trace health passed, but the primary rowid setup lane

did not show a stable win.

Broader stream-dispatch guard run:

 dart run benchmark/run_tracelite_experiment.dart \ --tracelite-root=/Users/dan/Coding/tracelite \ --baseline-root=/Users/dan/.codex/worktrees/resqlite-exp163-baseline \ --candidate-root=/Users/dan/.codex/worktrees/resqlite-exp164-eqp-rowid-elision \ --label=exp-164-rowid-plan-cache-stream-guard \ --direction=stream-rerun-dispatch \ --runs=2 --min-repetitions=5 --max-repetitions=12 \ --out-dir=build/tracelite-experiments/exp-164-rowid-plan-cache-stream-guard 
ScenarioDeltaVerdictMax CVp
high-cardinality-fanout+0.70%neutral1.02%0.123
keyed-pk-subscriptions-10.65%too_noisy13.73%1.44e-8
many-streams-writer-throughput-0.08%neutral1.11%0.684

Decision: inconclusive. The clean guardrails stayed mostly neutral, but the

targeted keyed-PK evidence was too noisy and the initial-drain run did not show

the setup win needed to justify the extra layer.

Decision

Rejected. SQLite EQP is a better exploratory tool than a custom SQL parser,

but this candidate still required a bespoke native rowid set, a new dependency

type, plan inspection during stream registration, cache invalidation policy, and

planner-detail coupling. The Tracelite evidence did not show enough rowid setup

or end-to-end dispatch improvement to carry that production complexity.

No runtime code was kept. The implementation is preserved at archive/exp-164

because it is a useful reference if a future real workload changes the

cost/benefit case.

Future Notes

dependency model changes the value side of the equation.

bounded probe, but the production design still needs a clearer win than this.

for stream changes that move setup cost.