Skip to content

fix(storage): declare the v44 index delta and gate schema-versioning by default - #3384

Merged
Sinity merged 2 commits into
masterfrom
feature/chore/tracker-accuracy-and-derived-transition-gate
Jul 29, 2026
Merged

fix(storage): declare the v44 index delta and gate schema-versioning by default#3384
Sinity merged 2 commits into
masterfrom
feature/chore/tracker-accuracy-and-derived-transition-gate

Conversation

@Sinity

@Sinity Sinity commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

An index schema bump merged without its delta declaration, the live archive silently fell back to full raw replay, and the repo CLI could not read it at all. The check that catches this already existed and ran nowhere. This declares the missing delta, moves the check into the gating path, and corrects the comment that made the cost look unavoidable. It also lands a tracker pass correcting stale bead state found while diagnosing it.

Problem

index_fast_forward_plan(43, 44) returned None, so archive_tiers/bootstrap.py fell through to full rebuild and every repo-CLI query against the live v43 archive failed:

$ polylogue --json find 'repo:polylogue'
Error: unexpected error: OperationalError: no such column: s.title_ref

devtools lab policy schema-versioning reported the violation correctly and continuously:

undeclared index schema deltas found: 1
Index fast-forward declaration drift:  missing: [44]

It is appended inside if lab: at devtools/verify.py. Default devtools verify does not run it; verify --quick (pre-push) does not run it; the CI lint job runs render all --check, verify public-claims and ruff, not this. Three other policies behind the same gate are also currently red (demo-tour-freshness, backlog-hygiene, bead-graph) — tracked in polylogue-ze5i.

Solution

Declare index v44 as SEMANTIC_REPARSE. v44 adds sessions.title_ref / title_confidence (polylogue-ih67, #3378). The DDL surface is two nullable columns on an 18,871-row table — trivially clone-safe — but the values come from the v44 Codex title resolver, affecting 3,201 of 18,871 sessions (100% of codex-session). A shape-only fast-forward would leave those NULL where a cold rebuild populates them, and that divergence must not be silently promoted.

DerivedDeltaClass has no class for "clone-safe shape, values via bounded targeted reprocess", so SEMANTIC_REPARSE is the truthful classification today. Operational behaviour is unchanged — full rebuild is what already happens. polylogue-9rw0.1 owns extending the vocabulary so this delta becomes a shape fast-forward plus a Codex-scoped reprocess.

Gate the policy by defaultdevtools/verify.py default step list plus the CI lint job. Static, archive-independent, measured at 0.63s.

Rewrite the stale comment above INDEX_SCHEMA_VERSION, which claimed index.db has no migration chain and that a stale generation needs ops reset --index. It predates the declared fast-forward mechanism and is the direct reason the rebuild cost was mistaken for unavoidable. (archive_tiers/embeddings.py:19-22 makes the same claim and is left alone — it is accurate, that tier has no declarations.)

Verification

devtools verify --quick                     exit 0  (58.03s, 18 steps)
devtools lab policy schema-versioning       exit 0  "Schema evolution policy intact"

Anti-vacuity — the gate fails on a real violation, not just passes on a clean tree:

INDEX_SCHEMA_VERSION -> 45 (undeclared)     exit 1  "undeclared index schema deltas found: 1 / missing: [45]"
reverted to 44                              exit 0

Tracker changes in this commit

Nine beads filed, each with bounds measured in this session rather than a single noticed instance:

bead measured bound
9rw0.1 delta-class vocabulary gap; v44 witness, 3,201/18,871 sessions
ze5i 4 of 10 lab policies red behind --lab
cijx.1 repo identity: 106 distinct repo_ids for one repo (sinex 28, sinnix 31)
cuxz.4 tool_result outcome NULL undifferentiated: 1,333,201 rows; codex 86%, claude-code 53%, claude-ai 0%
cuxz.5 26,188 unpaired tool_use blocks
4ts.10 session_links.status/.method empty on 9,179 of 9,179 rows
b5l.3 fast-forward sprawl: 5 modules, 2,713 lines, one per-version fork
5xng paste_spans = 4 rows / 3 sessions across 5,042,564 blocks
1hal backlog-hygiene X2: 5 of 6 findings are false positives

Corrections to existing beads:

  • m3p9 headline was 12× stale — "79% / 65,946 sessions" re-measured to 5.9% / 1,117; the original figure predated the hook de-inflation that moved the denominator 4.5×. Retitled and re-scoped.
  • ih67 — 3,101 → 3,201, and it is 100% of the Codex population, not a subset.
  • hjpx.2 — raw-frontier 15,264 → 2,593 and draining; the monotonic growth that justified hjpx's P0 escalation is not the current behaviour.
  • z9gh AC7 bounded. It read "Every residual symptom is mapped to one class mechanism" — an unbounded quantifier with no enumeration procedure, making the bead unclosable by construction and causing cold agents to report the P0 as long-horizon. Intent preserved; the set must now be enumerated from a stated snapshot. Snapshot figures refreshed (18,428 → 18,871 sessions, 4.85M → 5,042,564 blocks).
  • yla8 / lkrc / hjpx — the standing "No live apply is authorized" note was reading as a permanent prohibition and is the direct cause of an ask-defer loop running since 2026-07-15. The single operator input that lifts it is now written out once on yla8, with the agent-side prerequisites that must be reported first. No authorization is asserted in this PR — the note makes the question answerable in a line.
  • de2a / 623q / xikl — acceptance criteria added (all three were P1 with none). de2a carries a live writer-starvation baseline; xikl's "operator decision" was already made on 2026-07-19 and it appears in blocked-on-decision sweeps only because the phrase occurs in its text.
  • Reference corrections on yla8, 1xc.14, yyvg.7 distinguishing agent session ids from bead ids.

Ref polylogue-9rw0, polylogue-ih67, polylogue-ze5i

Summary by CodeRabbit

  • Bug Fixes
    • Updated schema-version validation so version 44 changes are correctly recognized during verification.
    • Ensured version 44 index updates rebuild/reprocess instead of taking an ineligible fast-forward path.
  • Documentation
    • Clarified version 44 schema changes (including session title fields) and when rebuild behavior applies.
  • Chores
    • Enhanced CI lint verification with an additional devtools policy/schema-versioning step.

…by default

Problem
An index schema bump merged without its lifecycle.py delta declaration, and
nothing caught it. index_fast_forward_plan(43, 44) returned None, so the live
archive fell back to full raw replay and every repo-CLI query against it failed
with "no such column: s.title_ref" -- diagnosed by hand days later.

The check that exists for exactly this (`devtools lab policy schema-versioning`)
reported the violation correctly the whole time. It sits inside the `if lab:`
branch of devtools/verify.py, which neither default verify, nor `verify --quick`
(the pre-push hook), nor the CI lint job runs.

What changed
- Declare index v44 (sessions.title_ref/title_confidence) as SEMANTIC_REPARSE.
  That is the truthful classification under the current DerivedDeltaClass
  vocabulary: the DDL surface is two nullable columns, but the values come from
  the v44 Codex title resolver, so a shape-only fast-forward would leave all
  3,201 codex-session rows NULL where a cold rebuild populates them. Behaviour
  is unchanged (full rebuild is what already happens); the declaration records
  why. polylogue-9rw0.1 owns removing the need for that classification.
- Move `lab policy schema-versioning` from the --lab branch into the default
  verify step list and the CI lint job. It is static, archive-independent and
  measured at 0.63s.
- Rewrite the stale comment above INDEX_SCHEMA_VERSION. It claimed index.db has
  no migration chain and that a stale generation needs `ops reset --index`,
  written before the declared fast-forward mechanism existed. It is the reason
  this cost was mistaken for unavoidable.

Verification
  devtools verify --quick                    exit 0 (58.03s, 18 steps)
  lab policy schema-versioning               exit 0, "Schema evolution policy intact"
  anti-vacuity: INDEX_SCHEMA_VERSION -> 45   exit 1, "missing: [45]"; reverted -> exit 0

Ref polylogue-9rw0, polylogue-ih67, polylogue-ze5i
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ad1d2fdd-b813-4b13-8ce6-652352e9ab71

📥 Commits

Reviewing files that changed from the base of the PR and between 21695bb and db924e7.

📒 Files selected for processing (2)
  • .beads/issues.jsonl
  • devtools/verify.py
💤 Files with no reviewable changes (1)
  • devtools/verify.py

📝 Walkthrough

Walkthrough

The change declares SQLite index schema version 44 as requiring semantic reparse, updates its versioning documentation, and runs the schema-versioning policy check in general verification and CI lint.

Changes

Schema versioning lifecycle

Layer / File(s) Summary
Declare schema version 44 lifecycle behavior
polylogue/storage/sqlite/archive_tiers/index.py, polylogue/storage/sqlite/lifecycle.py
Documents the v44 schema change and classifies it as a semantic-reparse delta with no SQL fast-forward operations.
Run schema-versioning checks in verification
devtools/verify.py, .github/workflows/ci.yml
Moves the schema-versioning gate outside the lab-only block and adds its command to the lint job.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: declaring v44 and moving schema-versioning into the default path.
Description check ✅ Passed The PR description covers Summary, Problem, Solution, and Verification with enough detail; missing template sections appear non-critical here.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/chore/tracker-accuracy-and-derived-transition-gate

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.

@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: 1

🤖 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 `@devtools/verify.py`:
- Around line 1775-1781: Move the “lab policy schema-versioning” verification
step out of the general not-commit branch and into the later `if not quick and
not commit` block within `build_verify_steps`, preserving its existing command
and behavior for non-quick, non-commit runs while excluding it from quick
verification.
🪄 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: 374c4be5-b24e-4c72-a3bc-9baf80225de4

📥 Commits

Reviewing files that changed from the base of the PR and between a57b9ca and 21695bb.

📒 Files selected for processing (5)
  • .beads/issues.jsonl
  • .github/workflows/ci.yml
  • devtools/verify.py
  • polylogue/storage/sqlite/archive_tiers/index.py
  • polylogue/storage/sqlite/lifecycle.py

Comment thread devtools/verify.py
Comment on lines +1775 to +1781
# Static, archive-independent, sub-second: an index bump that
# lands without its lifecycle.py delta declaration silently
# downgrades every existing generation to a full raw replay
# (polylogue-9rw0). Gated here, not behind --lab, because the
# failure surfaces as an unqueryable live archive rather than
# as a test failure.
("lab policy schema-versioning", _devtools_cmd("lab policy schema-versioning")),

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

Keep this check out of quick verification.

Because the step is added under if not commit, build_verify_steps(quick=True, commit=False) still runs it. The stated scope is non-quick, non-commit; append it inside the later if not quick and not commit block, or explicitly confirm that quick mode should include this policy.

Proposed placement
-                ("lab policy schema-versioning", _devtools_cmd("lab policy schema-versioning")),
             ]
         )

     if not quick and not commit:
+        steps.append(("lab policy schema-versioning", _devtools_cmd("lab policy schema-versioning")))

Also applies to: 1860-1860

🤖 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 `@devtools/verify.py` around lines 1775 - 1781, Move the “lab policy
schema-versioning” verification step out of the general not-commit branch and
into the later `if not quick and not commit` block within `build_verify_steps`,
preserving its existing command and behavior for non-quick, non-commit runs
while excluding it from quick verification.

Sinity added a commit that referenced this pull request Jul 29, 2026
…ctive index path (#3389)

## Summary
Fixes a real bug class discovered while closing out `polylogue-l2cd`: ~60
call sites across daemon status/health/cursor-lag tracking, storage
embeddings, schemas, sources/live, and coordination code derived a sibling
durable-tier path (`ops.db`/`embeddings.db`/`user.db`/`source.db`) via
`<index_path>.with_name("<tier>.db")`, where `<index_path>` was resolved
through pointer-aware logic (`resolve_active_index_path()`/
`ArchiveLocation.active_index_path`/`Config.db_path`).

## Problem
Once a `.index-active-pointer` file exists (written the first time
`IndexGenerationStore` bootstraps against an archive whose `index.db` is
already a promoted-generation symlink), `active_index_path` resolves to the
pointer's target — e.g. `configured_root/.index-generations/<gen-id>/index.db`
— and `.with_name("<tier>.db")` on that path lands inside the generation
subdirectory, which never contains the other durable tiers (they only ever
live in `configured_root`).

Verified not currently live-broken on the real archive (`index.db` is
already a symlink but no `.index-active-pointer` file exists yet, so
resolution currently falls through to the safe branch) — this activates the
next time a rebuild-and-promote cycle bootstraps `IndexGenerationStore`
against an archive for the first time.

## Solution
Two mechanical patterns applied per-site after tracing each anchor's actual
data flow (not blindly wrapping every grep hit):

- **Daemon-global code** (bare `archive_root()` already in scope, never
  unit-tested with an injected path): swap `resolve_active_index_path(archive_root()).with_name(...)`
  for `archive_root() / "<tier>.db"` directly.
- **Small pure functions** tested by passing an arbitrary `tmp_path` file
  with no ambient config (`cursor_lag_summary_info`, `catchup_status`,
  `convergence_debt_status`, etc.): added an explicit optional tier-path
  parameter (defaulting to the old `.with_name()` derivation for
  backward compatibility) threaded from the caller, which already has
  `archive_root()` in scope — kept these functions pure/testable rather
  than reaching into global config internally.
- Config-based sites route through the existing `archive_file_set_root()`
  helper (from the just-merged `archive_file_set_root_for_paths` migration)
  to honor the `polylogue-yla8.1` split-root override contract.

A handful of sites were investigated and deliberately left untouched,
documented in the PR: 4 `storage/fts/fts_lifecycle.py` call sites (bounded-risk
best-effort telemetry) and 2 `sources/live/batch.py` `source.db` derivations
pending further research into `CursorStore`'s tier semantics.

## Verification
- `mypy --strict` clean (1091 files); `ruff check`/`format --check` clean.
- `devtools verify --quick` exit 0.
- Broad sweep (`tests/unit/{daemon,storage,cli,coordination,core,maintenance,sources,schemas}`,
  ~11k tests): 50 failures on the branch. Compared against a clean
  `origin/master` worktree (not the shared checkout, which had drifted to
  another session's branch) by exact test name: the 3 branch-only entries
  are all false positives — 2 are pre-existing on clean master (the
  still-unmerged `ih67`/v44 schema-declaration gap, tracked by #3384,
  unrelated to this diff) and 1 passes in isolation on both branches
  (order-dependent asyncio-cancellation flake under parallel test load).
  Zero real regressions.

Ref polylogue-aaj9
…er-accuracy-and-derived-transition-gate

# Conflicts:
#	.beads/issues.jsonl
@Sinity
Sinity merged commit 4137244 into master Jul 29, 2026
3 checks passed
@Sinity
Sinity deleted the feature/chore/tracker-accuracy-and-derived-transition-gate branch July 29, 2026 04:43
Sinity added a commit that referenced this pull request Jul 29, 2026
The rebase onto master (after #3384 merged) left literal conflict markers in
.beads/issues.jsonl and two intermediate commits with the file emptied. This
restores the union: 1141 beads, every line parsing, no markers.

Content is unchanged from the union of both sides — for each id the row with
the later updated_at wins, which is the documented recovery for this file.

Co-Authored-By: Claude <noreply@anthropic.com>
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