Skip to content

test: add reindex derived-model differential - #3726

Merged
Sinity merged 1 commit into
masterfrom
feature/test/reindex-insight-differential
Aug 4, 2026
Merged

test: add reindex derived-model differential#3726
Sinity merged 1 commit into
masterfrom
feature/test/reindex-insight-differential

Conversation

@Sinity

@Sinity Sinity commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a test-only, DDL-censused oracle that compares incremental convergence with two independently rebuilt inactive index generations.

Problem

Rebuildable index state had no real-route assertion that incremental convergence and repeat full rebuilds produce the same logical derived model.

Solution

The new test infrastructure classifies every ordinary current-DDL table, declares volatile columns explicitly, compares logical rows and public insight reads, and separately checks FTS readiness, materialization markers, and unresolved convergence debt. The survivor seeds only a temporary archive through production raw replay and repair routes, then proves four corruptions are rejected.

Acceptance matrix

Bead Acceptance criteria Evidence
polylogue-hjwr Two full rebuilds and incremental convergence agree; current DDL cannot gain an unclassified table; a seeded divergence is caught. Two owned inactive generations plus the incremental route compare equal. A DDL census fails on unclassified tables or virtual indexes, and controls cover omitted repair, missing session_profiles, stale FTS text, and a same-row-count stale profile.
polylogue-5wp Derived materialization cannot silently appear current when stale or partial. Snapshots compare public reads, FTS ledger and searches, materialization markers, and open debt. Omitted repair and each stale/partial control raise an assertion.

Verification

  • direnv exec . devtools test tests/unit/storage/test_reindex_derived_model_differential.py : 1 passed in 1.40s.
  • direnv exec . devtools verify --quick : success, including format, lint, strict mypy, generated-surface checks, and policy checks.

Ref polylogue-5wp. Ref polylogue-hjwr.

Summary by CodeRabbit

  • Tests
    • Added comprehensive validation for incremental updates and full reindexing.
    • Verifies that both workflows produce equivalent searchable data and derived results.
    • Detects stale search content, missing profiles, incomplete repairs, and outdated records—even when row counts appear unchanged.
    • Adds readiness checks for unresolved synchronization work and stale indexes.

Problem: incremental convergence and full inactive-generation rebuilds lacked a common derived-model oracle.

What changed: add a DDL-censused, volatility-aware snapshot helper and a real temporary-archive survivor covering two full rebuilds, incremental convergence, public reads, FTS, materialization markers, debt, and four mutation controls.

Ref polylogue-5wp. Ref polylogue-hjwr.

Co-Authored-By: Codex <noreply@openai.com>
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a read-only differential snapshot framework for archive-derived models and an end-to-end test that compares incremental convergence with full reindex generations, including FTS, public reads, markers, and convergence debt.

Changes

Derived model differential verification

Layer / File(s) Summary
Snapshot contracts and table census
tests/infra/reindex_differential.py
Defines snapshot structures, classifies ordinary index tables from DDL, validates explicit comparison policies, and normalizes durable table rows.
Derived state collection and readiness
tests/infra/reindex_differential.py
Snapshots derived tables, public insight reads, FTS state, materialization markers, and unresolved debt. Equivalence checks report focused differences, while readiness checks reject stale FTS indexes and open debt.
Incremental and full-generation differential test
tests/unit/storage/test_reindex_derived_model_differential.py
Builds deterministic archive input, runs replay and repair routes, compares incremental and full-generation snapshots, and detects missing profiles, stale FTS text, and altered profile data.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Archive
  participant ReplayAndRepair
  participant IndexGeneration
  participant SnapshotFramework
  participant DifferentialAssertions
  Archive->>ReplayAndRepair: provide source evidence
  ReplayAndRepair->>IndexGeneration: replay and repair derived state
  SnapshotFramework->>IndexGeneration: read tables, FTS, markers, and debt
  SnapshotFramework->>ReplayAndRepair: read public insights and searches
  SnapshotFramework-->>DifferentialAssertions: return normalized snapshots
  DifferentialAssertions->>DifferentialAssertions: compare generations and readiness
Loading

Possibly related PRs

  • Sinity/polylogue#3165: The differential snapshots validate derived-store, FTS, and reindex-generation parity.
  • Sinity/polylogue#3278: The tests validate repair, rebuild convergence, materialization markers, FTS readiness, and convergence debt.
  • Sinity/polylogue#3282: The snapshots validate deferred FTS repair and post-write convergence state.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the addition of a differential test for reindex-derived models.
Description check ✅ Passed The description covers the change, problem, solution, acceptance criteria, and exact verification commands; changelog and risks are appropriately omitted for a test-only change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/test/reindex-insight-differential

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Sinity
Sinity merged commit c662b7e into master Aug 4, 2026
2 of 3 checks passed
@Sinity
Sinity deleted the feature/test/reindex-insight-differential branch August 4, 2026 06:19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/infra/reindex_differential.py`:
- Around line 26-29: Update the census parsing around _CREATE_TABLE and
_CREATE_VIRTUAL_TABLE so every CREATE TABLE declaration is either classified or
explicitly rejected. Support valid declarations without IF NOT EXISTS and quoted
object names, preferably by reading names from a temporary SQLite catalog;
otherwise detect unparsed CREATE TABLE statements and fail instead of omitting
them from the census and missing/stale checks.
- Around line 185-192: Update assert_derived_model_ready to reject any FTS
ledger whose state is not ready and any nonzero missing_rows, excess_rows, or
duplicate_rows, in addition to the existing source/indexed row-count check. Use
the corresponding fields on snapshot.fts and preserve the current AssertionError
behavior and messages where applicable.

In `@tests/unit/storage/test_reindex_derived_model_differential.py`:
- Around line 149-151: Update _assert_control_rejected and its related cases so
the control differs only in public_reads while tables, FTS, markers, and debt
remain equal. Ensure the assertion reaches public-read comparison and verifies
the expected “public insight reads differ” failure, rather than passing due to
an earlier table mismatch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fe962aff-f8db-4b0b-a0e2-3e24e998d437

📥 Commits

Reviewing files that changed from the base of the PR and between fe3588e and e750495.

📒 Files selected for processing (2)
  • tests/infra/reindex_differential.py
  • tests/unit/storage/test_reindex_derived_model_differential.py

Comment on lines +26 to +29
_CREATE_TABLE = re.compile(r"CREATE\s+TABLE\s+IF\s+NOT\s+EXISTS\s+([A-Za-z_][A-Za-z0-9_]*)", re.IGNORECASE)
_CREATE_VIRTUAL_TABLE = re.compile(
r"CREATE\s+VIRTUAL\s+TABLE\s+IF\s+NOT\s+EXISTS\s+([A-Za-z_][A-Za-z0-9_]*)", re.IGNORECASE
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject unparsed DDL in the census.

_CREATE_TABLE and _CREATE_VIRTUAL_TABLE accept only unquoted names with IF NOT EXISTS. A valid table declaration that omits the clause or quotes the name is absent from both census sets. The missing and stale checks then pass without requiring a classification.

Read object names from a temporary SQLite catalog, or reject every CREATE TABLE statement that the parser cannot classify.

Also applies to: 111-123

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/infra/reindex_differential.py` around lines 26 - 29, Update the census
parsing around _CREATE_TABLE and _CREATE_VIRTUAL_TABLE so every CREATE TABLE
declaration is either classified or explicitly rejected. Support valid
declarations without IF NOT EXISTS and quoted object names, preferably by
reading names from a temporary SQLite catalog; otherwise detect unparsed CREATE
TABLE statements and fail instead of omitting them from the census and
missing/stale checks.

Comment on lines +185 to +192
def assert_derived_model_ready(snapshot: DerivedModelSnapshot) -> None:
"""Keep a matching but jointly stale generation from passing the lane."""
if snapshot.fts.source_rows != snapshot.fts.indexed_rows:
raise AssertionError(
f"FTS is not ready: source_rows={snapshot.fts.source_rows}, indexed_rows={snapshot.fts.indexed_rows}"
)
if snapshot.open_debt:
raise AssertionError(f"convergence debt remains: {snapshot.open_debt}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Check all FTS freshness fields.

Equal row counts do not prove a correct FTS index. One missing source block plus one duplicate or excess FTS row keeps the totals equal. The ledger already includes state, missing_rows, excess_rows, and duplicate_rows, but this readiness check ignores them.

Reject a non-ready ledger state and any nonzero discrepancy count.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/infra/reindex_differential.py` around lines 185 - 192, Update
assert_derived_model_ready to reject any FTS ledger whose state is not ready and
any nonzero missing_rows, excess_rows, or duplicate_rows, in addition to the
existing source/indexed row-count check. Use the corresponding fields on
snapshot.fts and preserve the current AssertionError behavior and messages where
applicable.

Comment on lines +149 to +151
def _assert_control_rejected(expected: DerivedModelSnapshot, root: Path, index_path: Path) -> None:
with pytest.raises(AssertionError):
assert_derived_models_equivalent(expected, _snapshot(root, index_path))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Isolate the public_reads control.

The session_profiles update changes a compared table. assert_derived_models_equivalent() raises during the table comparison before it reaches public_reads. _assert_control_rejected() therefore succeeds even if public-read collection or comparison is removed.

Add a control with equal tables, FTS, markers, and debt but a different public read. Alternatively, assert the expected public insight reads differ failure.

Also applies to: 236-243

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/storage/test_reindex_derived_model_differential.py` around lines
149 - 151, Update _assert_control_rejected and its related cases so the control
differs only in public_reads while tables, FTS, markers, and debt remain equal.
Ensure the assertion reaches public-read comparison and verifies the expected
“public insight reads differ” failure, rather than passing due to an earlier
table mismatch.

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