Repository source: docs/plans/backlog/read_model_maintenance_followups.md
Read-model maintenance follow-ups (from viewer_tag_read_model_and_memoization)
Two cross-cutting items surfaced during the viewer_tag_read_model_and_memoization
cycle (completed and archived; see
docs/plans/archive/viewer_tag_read_model_and_memoization/viewer_tag_read_model_and_memoization_step4_implementation_summary.md).
Neither was in that cycle's scope; both are recorded here so they are not lost
when the cycle is archived.
1. Derive dropSchema() from ReadModelSchema::statements() — DONE (2026-10-25)
Resolved. ReadModelBuilder::dropSchema() now derives its table list from
ReadModelSchema::tableNames() (parsed from the CREATE TABLE statements), so a
new table is dropped-and-recreated on in-place rebuild automatically with no
hand-maintained list. Covered by tests/ReadModelDropSchemaTest.php (tableNames
matches the schema; in-place rebuild recreates every table without collision) and
documented in docs/specs/read_model_schema_v1.md (Schema-change contract).
Original note (for history):
ReadModelBuilder::dropSchema() hand-maintains a hardcoded DROP TABLE IF EXISTS
list. Any new read-model table must be added there too, or in-place rebuilds
fail with table <name> already exists. This bit the viewer_tags cycle (Stage 2)
and was caught only by the read_model_hot_indexes startup-rebuild regression
test. Indexes are safe (dropping a table drops its indexes), so the earlier
hot-index cycle never had to touch dropSchema, which is why the list looked
complete.
Proposal: derive the drop set from the table names in
ReadModelSchema::statements()(parseCREATE TABLE <name>), so adding a table to the schema automatically drops it on rebuild. Removes a silent footgun for every future read-model table.Risk/size: small, localized to
ReadModelBuilder/ReadModelSchema; needs a test that a schema-only table addition rebuilds in place without collision.
2. Remove inactive / excludedPublicationPosts exclusions from thread-label derivation
During the cycle the user indicated "we're getting rid of" the
inactive/publication exclusions. The cycle applied that only to the
viewer_tags projection (so viewer like/flag/vote/label state is byte-identical
to the former file scan, including on retracted/removed-source threads). The
broader removal — dropping those exclusions from the thread-label score / label
/ vote-count derivation in ReadModelBuilder::indexThreadLabels() and
IncrementalReadModelUpdater — was explicitly not done, because it changes
observable board listings, scores, and vote totals on retracted/removed-source
threads.
Proposal: a dedicated cycle to decide and implement whether (and how) retracted/removed-source thread labels should continue to affect scores, labels, and vote counts, with parity/behavior-change acceptance notes.
Risk/size: medium–large, cross-cutting (board, Forte, qdb listings and scores; incremental + full rebuild paths; retraction semantics). Needs its own solution assessment.
3. Keep the canonical archive README committed in the repository
From the archive_export_efficiency cycle (2026-10-26). The repository archive
(/downloads/repository.tar.gz / .zip) currently overrides whatever
README.md the content repo tracks with the canonical recipient guide
(resources/repository-archive/README.md), injected at export time by
RepositoryArchiveReadme::write(). This override is load-bearing today (there is
a contract + test that the archive always contains the guide, and a 500 path when
the tracked README.md can't be replaced).
User preference (deferred): instead of overriding at build time, keep the proper (guide) README committed in the content repository, so
git archivecarries the correct README with no override step. This would simplify the export (git archivebecomes fully sufficient for the committed tree, no README injection) and remove the replace-failure path.Caveats to resolve in its own cycle: (a) who keeps the committed README in sync with
resources/repository-archive/README.mdwhen the guide changes (injection guarantees freshness; a committed file does not); (b) existing instances (incl. qdb.us) have their ownREADME.mdor none, so this needs a one-time seed and a decision about replacing an instance's own README; (c) update the export tests/contract that currently assert the override.Risk/size: small code, but a content/data decision (what README ships in the archive) and a sync-maintenance question; needs a solution assessment.