Skip to content

fix(maintenance): gate reindex on durable schema currency (#3851) - #3851

Closed
Sinity wants to merge 1 commit into
masterfrom
feature/fix/schema-currency-gate
Closed

fix(maintenance): gate reindex on durable schema currency (#3851)#3851
Sinity wants to merge 1 commit into
masterfrom
feature/fix/schema-currency-gate

Conversation

@Sinity

@Sinity Sinity commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

Add a durable schema-currency preflight to the managed index rebuild route and expose the same read-only diagnostic through rebuild-index --preflight.

Problem

The live source tier reached v28 while the installed package expected v24 and the current package expects v29. The rebuild operation previously accepted a source tier whose durable schema did not match the parsing package. Source v28 is a valid predecessor of v29, but it must be migrated with the selected v29 package before that package rebuilds index.db.

Solution

The shared rebuild implementation probes source.db and user.db before provenance receipt validation, archive ownership, lease acquisition, or candidate creation. index.db is deliberately exempt because replacing it is the rebuild operation's purpose. The CLI preflight emits structured JSON, and the maintenance guide records the ordered migration, deployment, preflight, and managed rebuild sequence.

Verification

  • direnv exec . devtools test tests/unit/maintenance/test_rebuild_index_ownership.py -k schema_behind_runtime: 1 passed, 6 deselected.
  • direnv exec . devtools test tests/unit/cli/test_archive_maintenance_cli.py -k durable_schema_currency: 1 passed, 62 deselected.
  • direnv exec . devtools render all: completed without generated changes.

Acceptance criteria

Criterion Disposition Evidence
Live source migration matches deployed package Not run Production mutation was excluded from this lane.
user.db is current or migrated Read-only evidence only Live user.db was observed at v10; no migration ran.
Matching Sinnix package is deployed and daemon restarted Not run Production deployment and daemon restart were excluded.
Durable schema alerts clear, leaving only the derived-index gap Not run The live archive remains parked pending the operator sequence.
No Polylogue code changes Misframed for this PR The requested bounded guard is commit f2ae88e2d918510cf1fcfff4afb5c69680d9eb27; the whole bead remains partial.

Remaining live migration, deployment, and managed rebuild work is carried by polylogue-a7gmk.

Problem
A rebuild accepted a source.db whose user_version lagged the package that
would parse and rebuild from it. The live archive reached that state at
source v28 while the installed package expected v24 and master expects v29.

What changed
The rebuild route now checks source.db and user.db before provenance,
ownership, or candidate creation. A read-only --preflight option exposes the
same structured diagnostic. index.db remains exempt because rebuilding it is
the operation's purpose.

Compatibility/migration
Operators must migrate durable tiers and deploy the matching package before
rebuilding index.db. The maintenance runbook records the ordered recovery
sequence.

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

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Sinity, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 57 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 514b4d82-b342-4200-bb3a-eb6a17e3a4d3

📥 Commits

Reviewing files that changed from the base of the PR and between 685f2ca and f2ae88e.

📒 Files selected for processing (5)
  • docs/maintenance.md
  • polylogue/cli/commands/maintenance/_rebuild_index.py
  • polylogue/maintenance/rebuild_index.py
  • tests/unit/cli/test_archive_maintenance_cli.py
  • tests/unit/maintenance/test_rebuild_index_ownership.py

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 changed the title fix(maintenance): gate reindex on durable schema currency fix(maintenance): gate reindex on durable schema currency (#3851) Aug 6, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2ae88e2d9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

log_mapped_bytes_budget_check(logger, check_mapped_bytes_budget_against_cgroup_limit())
validate_rebuild_index_request(request)
root = request.archive_root
require_rebuild_schema_currency(root)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Recheck schema currency after acquiring ownership

When a newer package migrates source.db or user.db after this probe succeeds but before this process acquires OwnedArchiveLocation, the rebuild continues using the now-mismatched durable schema. This is possible because, unlike the provenance receipt, schema currency is never revalidated under ownership; a migration that only changes schema/version also is not guaranteed to affect the later source-evidence snapshot. Repeat this check immediately after ownership acquisition so the schema cannot change between validation and replay.

Useful? React with 👍 / 👎.

Comment on lines +95 to +96
for tier in (ArchiveTier.SOURCE, ArchiveTier.USER):
probe = probe_archive_tier(tier, root / f"{tier.value}.db")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Initialize user.db in the source-only rebuild fixtures

The existing _init_empty_source() helper in tests/unit/maintenance/test_rebuild_index_ownership.py creates only source.db, but six tests using it invoke the rebuild and expect ownership, liveness, or successful empty-source behavior. This loop now classifies the absent user.db as blocking first, so those tests instead raise RebuildSchemaCurrencyError; update the fixture to create the user tier, or preserve source-only rebuild support by not treating a missing user tier as a version mismatch. The commit's two -k verification commands did not cover these affected cases.

AGENTS.md reference: AGENTS.md:L325-L328

Useful? React with 👍 / 👎.

log_mapped_bytes_budget_check(logger, check_mapped_bytes_budget_against_cgroup_limit())
validate_rebuild_index_request(request)
root = request.archive_root
require_rebuild_schema_currency(root)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Run the currency gate before the empty-source shortcut

For local CLI execution when source.db.raw_sessions is empty, _rebuild_index.py returns an empty-source success before calling rebuild_index_from_source_sync, so this newly added guard never runs. The same v28 fixture used by the new ownership test therefore remains accepted through the actual polylogue ops maintenance rebuild-index command whenever it has no raw rows, making the surface disagree with the shared implementation and the documented execution guarantee; invoke the shared preflight before the CLI's raw-count shortcut.

AGENTS.md reference: AGENTS.md:L37-L40

Useful? React with 👍 / 👎.

Comment on lines +450 to +453
if preflight:
from polylogue.maintenance.rebuild_index import rebuild_schema_currency_preflight

payload = rebuild_schema_currency_preflight(root)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject or honor --daemon during preflight

When --preflight is combined with --daemon, this branch silently ignores both use_daemon and daemon_url and probes the client's local archive_root() instead. If the CLI is controlling a daemon with a different archive root, it can report ready for the wrong databases—or block because of an unrelated local archive—while the subsequent daemon rebuild targets another root. Either reject this option combination like --daemon --plan, or expose and call a daemon-side preflight endpoint.

Useful? React with 👍 / 👎.

Comment on lines +95 to +96
for tier in (ArchiveTier.SOURCE, ArchiveTier.USER):
probe = probe_archive_tier(tier, root / f"{tier.value}.db")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include the audit tier in durable currency checks

The canonical durable migration set already includes ArchiveTier.AUDIT (storage/sqlite/migration_runner.py:34), and the archive's tier-schema verifier treats a missing or mismatched audit.db as an error (maintenance/archive_verification.py:379-405). Because this loop checks only source and user, the new diagnostic can nevertheless report ready while a required durable tier is absent or belongs to another package schema, contradicting its durable-currency result and the runbook's requirement to clear durable-tier mismatches. Derive these checks from the canonical durable-tier set, excluding only tiers for which rebuild currency is intentionally irrelevant.

Useful? React with 👍 / 👎.

@Sinity

Sinity commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

Superseded by the stacked hardening PR #3856, which carries this implementation plus the later audit, post-lock, daemon-bulk, empty-source, and HTTP-diagnostic fixes. The durable migration and live transition remain tracked by the named Beads successors.

@Sinity Sinity closed this Aug 6, 2026
@Sinity
Sinity deleted the feature/fix/schema-currency-gate branch August 10, 2026 13:11
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