Evidence: Representative local selection measurements
Revision: ade35a65 application; PHP 8.1.2 CLI, PDO SQLite; 128 MiB PHP limit, 60-second timeout
Fixture: Real minimal read-model schema built outside repository, posts/threads replaced by exactly 1000 or 10000 synthetic quotes; 2048-byte bodies, 1024-byte previews; equal timestamps, zero-padded IDs; oldest quote pinned. Other fixture tables remain fixed, not production-representative.
Method: Separate setup process; three fresh PHP processes per mode/count, sequential order recorded in raw results. First sample is first for that mode/shape, not cold OS cache. No cache eviction; fixtures were just written and earlier modes warm later modes. Timing variance is large; do not project production savings from these numbers.
Instrumentation: PDOStatement subclass counts fetch/fetchAll arrays and root_post_body bytes. Reported PDO rows exclude fetchColumn scalars (including TagPage existence checks), SQLite internal examined rows, allocation copies and network/browser bytes. Bodies materialized counts returned full-body rows; not maximum concurrently retained objects. RSS covers the measured PHP/timeout process tree via GNU time, separate from PHP allocator peak. Instrumentation adds overhead.
Scope: qdb25 exercises ThreadRepository + QdbBoardPolicy eligibility/paginate; welcome5 exercises the same load + eligibility + first-five selection. Neither is full dispatch/rendering; qdb25 intentionally does not exercise BoardPageController sorting/pinned precedence. tag25 calls current TagPage::page directly, a delivered bounded-hydration control, not a proposed QDB replacement or semantic parity test.
Assertions: Exact selected IDs and total fixture count, fail with nonzero exit on mismatch. All 18 samples exit 0. No failed measurement samples. Exploratory source lookups at guessed paths returned missing-file errors; corrected paths were used before classification.
Results: qdb25 and welcome5 each materialize 1000/10000 bodies (2,048,000/20,480,000 body bytes) to select 25/5. PHP peak 8/60 MiB. Tag25 materializes 25 bodies (51,200 bytes) for either corpus, peak 2 MiB; 26 candidate metadata rows + 25 body rows. SQL examined rows unknown for all modes.
Timing medians milliseconds: qdb25 232.388/1874.599; welcome5 144.017/635.317; tag25 28.358/36.910 (1000/10000 respectively). Full samples and RSS in reader_results.txt; memory/body-count growth is the stronger evidence here.
Reproduction: From source checkout, use a fresh directory from mktemp -d outside the repository. Extract reader_probe_source.txt starting with <?php into that directory/probe.php. Set project to the absolute checkout, probe_dir to that temporary directory.
Setup command: php -d memory_limit=128M "$probe_dir/probe.php" "$project" "$probe_dir" setup 1000
Setup command: php -d memory_limit=128M "$probe_dir/probe.php" "$project" "$probe_dir" setup 10000
Sample command: /usr/bin/time -f 'Process peak RSS KiB: %M' timeout 60s php -d memory_limit=128M "$probe_dir/probe.php" "$project" "$probe_dir" qdb25 1000
Repeat: Substitute welcome5 and tag25, and 10000; run each combination three times. Capture stdout/stderr/exit separately per sample, retaining failure. Setup is not included in reported wall time or PHP peak. Do not reuse production databases.
Limitations: No host PHP 8.3, real corpus, full HTTP/UI, concurrent workload, maximum record/thread or independent native SQLite scan instrumentation. No lower-budget capacity acceptance. No failure/recovery or speedup claim.

Maintenance probe: Extract maintenance_probe_source.txt into external maintenance.php. Same setup modes/fixture; run the sample command with maintenance.php and offline200 for 1000/10000, three fresh processes each. Existing reader fixtures were reused, so caches may be warm. All six samples exit 0, exact IDs/pinned-first order/count pass.
Measured path: Reflection invokes actual PublicOfflineSnapshotBuilder::snapshotThreadRows, isolating discovery before snapshot writes, post copying and size failures. 201 selected = oldest pinned + newest 200 non-pinned. Not a full build/activation test; no reflection code enters application.
Maintenance results: 1000/10000 full candidate rows transferred/materialized before selection of 201. Rows contain 1024-byte body previews, not full root bodies; body counter correctly reports zero and does not imply no content transferred. PHP peak 4/24 MiB; median 9.739/54.570 ms. Raw RSS/times in maintenance_results.txt. SQL examined rows unknown; transferred preview-byte volume is 1,024,000/10,240,000 by fixture construction, not a separate native counter.