Skip to content

fix(retention): verify SQL page progress and expose GC frontiers (#4787) - #4798

Open
ScriptedAlchemy wants to merge 17 commits into
masterfrom
fix/4787-retention-sql-progress
Open

ScriptedAlchemy wants to merge 17 commits into
masterfrom
fix/4787-retention-sql-progress

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Scope — Refs #4787 (partial, not closure)

Publish the retention-only five-file transactional progress diagnostic and fail-closed guard against master so it can be reviewed and tested independently of the held, mixed draft #4776. No Kev/decision-model changes are included or moved; do not merge or auto-merge #4776.

  • Canonical-body GC now reports candidates actually discharged (including the FK-cascaded candidate rows from deleted bodies). In the same writer transaction it refuses to commit unless all selected candidates were discharged.
  • Replay-metadata compaction reports the durable store-ID frontier before and after a nonempty page, and refuses a nonadvancing page instead of silently retrying it.
  • The daemon logs both measurements alongside page size, reclamation counts, and has_more.
  • Real Rust database-backed regressions exercise 52 referenced bodies and 52 ineligible replay rows through distinct 48+4 pages, verify advancement without destructive cleanup, and verify quiescence.

Verification and limitation

  • Independently reviewed the exact five-file, single-parent patch against master; only the above retention implementation, logs, and regressions changed.
  • An independent disposable SQLite foreign-key/candidate-discharge and keyset-frontier probe asserted that 48+4 live candidates discharge without deletion and that replay advances 0→48→52. This is not the repository Bazel or native macOS test.
  • Pending: Bazel-only Rust tests and hosted CI on this PR's exact head; no Cargo. The original reported 90–110% CPU incident remains unproven resolved until consecutive affected-host SQL frontiers, candidate counts, actual tick cadence/duration and commit/rollback evidence establish whether work is stalled versus an advancing backlog. The separate cold-store JSON checkpoint is not either SQL frontier.
  • Do not reset authoritative SQL state or touch production, release chore(release): release 1.0.0-beta.99 #4763, tags, or credentials.
  • No Fixes #4787 claim. Leave the issue open, and do not auto-merge pending validation or qualification.

Report candidate discharge and replay SQL frontiers for each scanned page.
Reject incomplete candidate discharge or nonadvancing replay pages.
Add >48-row behavioral regressions for zero-reclamation backlogs.

Refs #4787
@changeset-bot

changeset-bot Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 4984a54

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Admit a size-bounded metadata prefix before running SQL JSON eligibility
checks, including rows that cannot be compacted. Resolve admitted IDs in
one query under the existing writer transaction. Preserve oversized
metadata while advancing past it without parsing or blocking later rows.

Expose examined metadata bytes through the page report and tracing span.
Add database-backed regressions for large ineligible backlogs and an
oversized stored document followed by valid compactable work.

Refs #4787

Copy link
Copy Markdown
Owner Author

Published replay CPU-amplification fix — Refs #4787

Follow-up commit 001b1ab is now on this issue-specific PR. It changes only replay_metadata.rs and its database-backed tests; the previous canonical-GC/frontier work remains intact.

Confirmed defect and correction

candidates() evaluated json_valid/json_type on up to 48 complete metadata documents before step() applied the 4 MiB verification budget. Large ineligible structured replay documents did not consume that later budget at all. The row cap therefore did not bound JSON eligibility work.

The fix first reads identities/sizes, admits a contiguous prefix under a 4 MiB metadata-parsing budget, then evaluates eligibility in one batched primary-key query under the same writer transaction. No per-row query loop is added. Individually oversized metadata is left byte-for-byte intact and advanced past without parsing; later valid work remains reachable. Existing body-verification budget, sanitizer receipts, guarded writes, rollback behavior, and 48-row cap remain in place.

metadata_bytes_examined reports admitted eligibility bytes, including ineligible or prefetched-but-deferred rows. The lcm.retention.replay_metadata.page tracing span exposes that field through the existing span-timing surface. This bounds JSON parsing, not every physical disk read; size discovery still has an I/O cost.

Behavioral evidence

A disposable SQLite 3.46.1 probe executed the original and replacement SQL, instrumenting actual json_valid input bytes. For 48 structured documents:

  • Original single page: 25,924,272 bytes submitted for eligibility validation.
  • Fixed pages: 3,780,623 bytes each for six 7-row pages, then 3,240,534 bytes for the final 6 rows.
  • Persisted frontier: 0 → 7 → 14 → 21 → 28 → 35 → 42 → 48, followed by an idle page. No document revisited or changed.
  • Oversized, external, NULL, and malformed metadata cases passed; later eligible work remained discoverable. The eligibility query plan uses INTEGER PRIMARY KEY probes rather than a full-table scan.

Added two real Rust database-backed regressions: (1) large ineligible documents require multiple bounded ticks, strictly advance the durable frontier, quiesce, and preserve complete messages/receipts; (2) oversized stored metadata stays unchanged while a subsequent valid row is actually compacted. Existing corruption rollback, stale-write, representation-preservation, and 48+4 progress regressions are unchanged.

Validation and ownership

Reviewed the exact two-file diff in a separate pass and verified one commit ahead of 8db58ec7. Published with expected_sha=8db58ec7ddbfbe29d295404cb37c84c4b2b458d0, force=false; verified PR head at 001b1abe.

The SQLite probe is not a repository Rust/Bazel pass. No local Bazel toolchain was available; no Cargo was invoked. New-head CI run https://github.com/ScriptedAlchemy/tracedecay/actions/runs/42434994670 is pending. The relevant Rust suite is bazel test //crates/tracedecay-lcm:unit_test --test_output=errors; new-head formatting, compilation and behavioral tests must pass before landing.

The original affected-host 90–110% CPU incident is not yet proven resolved. Its consecutive canonical candidate/frontier and actual tick/commit measurements remain required, and the cold-store JSON cursor is a separate authority. Keep #4787 open; no Fixes claim or master closure. Protected mixed #4776 remains draft and untouched; no Kev/decision-model work moved, no release #4763/production/infrastructure/credential changes, and no other task schedules changed.

Apply only the two exact Rustfmt changes identified by the blocked
repository formatting gate on the last PR head.

Refs #4787

Copy link
Copy Markdown
Owner Author

Refs #4787 — repaired the first exact-head CI failure on this isolated PR.

The Bazel //:rustfmt_check gate in CI run 42434994670 failed in //crates/tracedecay-lcm:rustfmt_check_2024 on two formatting differences in the new replay-metadata regression tests (tests.rs:428 and :520). No product logic failed in that gate. Published 2a42006eef255c577137620543f9fa25cdbe96c0 with only those exact two rustfmt transformations, via nonforce expected_sha=001b1abe47f636b05ed95c964e3cbd6f6ab5cdee; verified remote ref and PR head.

New exact-head CI run 42437993937 is queued; no passing Bazel/Rust test is claimed yet, and the previous run's Linux/Clippy work is not an accepted pass. Keep #4787 open pending exact-head tests and affected-host SQL-frontier/CPU/cadence evidence. No changes to draft #4776, release #4763, other owner work, or scheduled tasks.

Read back the replay frontier in the page's writer transaction before
reporting progress. Refuse ignored or rewritten checkpoint writes so the
existing transaction owner rolls back metadata changes rather than
committing a page that will be visited again. Idle pages do not write.

Add real database regressions for an ignored initial checkpoint, a
rewritten existing checkpoint, rollback and successful recovery, and
write-free idle pages. Preserve existing parsing and body budgets.

Refs #4787

@ScriptedAlchemy ScriptedAlchemy left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Retention implementation review — Refs #4787

Reviewed the published checkpoint repair at 91ffd680d7ec128dbf5cd14d9bcc721b4e457a21, including its two-file diff against 2a42006. This is a code update on this PR, not merely a proposed change.

The previous guard checked an advancing local after value but did not establish that set_gc_meta actually stored it. The new read-back occurs inside the same writer transaction, before returning a successful report; an ignored or rewritten checkpoint now returns an error through the existing rollback owner. Empty pages no longer initialize or rewrite the checkpoint. Existing metadata/body budgets and sanitizer checks remain intact.

The added database-backed Rust regressions cover an ignored initial checkpoint, an existing checkpoint rewritten after INSERT, and an idle page whose checkpoint writes are explicitly forbidden. The refusal tests prove that compaction happened before the failure, then verify restoration of the complete message/receipts, the prior checkpoint and summary revision, followed by successful compaction and quiescence once the injected fault is removed.

Validation remains open: the disposable SQLite reproduction passed 20 assertions, reproducing repeated identical 48-row pages under both injected checkpoint faults and recovery through 48+4 pages after removing the faults. That is not a Rust/Bazel test pass, and these injected faults are not established as the affected host's cause. No local Bazel was available; no Cargo was run. Exact-head CI run 42442366451 was queued when checked. Require the relevant Bazel unit tests and applicable CI on this head, rather than inheriting an earlier head's green checks.

Not an approval or incident-resolution claim. Keep Refs #4787: closure still requires the original CPU/frontier acceptance evidence in master. Consecutive committed frontiers/candidate discharge and measured tick timing are needed to distinguish a stalled page from an advancing backlog. No auto-merge; the separate mixed #4776 remains draft and excluded from merging.

// An advancing local key is not proof that its checkpoint was stored.
// Verify inside the same writer so a refused or rewritten checkpoint
// rolls back this page instead of committing a false progress report.
let persisted = frontier(conn).await?;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Reviewed the checkpoint fix here: read-back must remain inside this writer transaction. A monotone local key (or even a successful INSERT row count) is not sufficient when a checkpoint write is ignored or subsequently rewritten. This comparison now routes failure through the existing transaction rollback rather than returning false progress. The new fault-injection regressions exercise both cases, actual pre-error compaction, rollback, and recovery; their Rust/Bazel execution is still pending.

pub rows_skipped_oversized: u64,
/// Metadata bytes admitted to SQL eligibility parsing, including ineligible
/// rows and any prefetched rows deferred by the separate body byte budget.
pub metadata_bytes_examined: u64,

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Measurement/acceptance note: this is the admitted metadata size for eligibility parsing, including prefetched rows the body budget may defer. It is not total physical I/O, unique committed bytes, or a CPU measurement; the initial size-discovery query runs before this admission. Keep the scope explicit when evaluating #4787, and correlate it with committed frontiers and actual page/tick timings before claiming the sustained CPU incident is resolved.

Refuse an unchanged bootstrap page or a checkpoint that did not persist,
even when its SQL UPDATE reports one affected row. Roll back enrolled refs
and seed writes through the existing writer transaction on refusal.

Add a database-backed 52-owner regression proving repeated 48-row pages
fail closed when a trigger rewrites their frontier, then resume through
48+4 pages and quiesce without collecting the live shared body.

Refs #4787

Copy link
Copy Markdown
Owner Author

Published canonical-body bootstrap checkpoint guard — Refs #4787

Commit ad3729b860 is now on this existing issue-specific PR. It changes only canonical_body_gc.rs and its Rust database-backed tests, preserving every concurrent commit.

Bug class: the former save_progress accepted UPDATE ... affected-row count = 1 as proof that the raw/observation/body bootstrap frontier persisted. A database trigger can rewrite the row after that UPDATE and still return one affected row. If the writer commits the 48 newly enrolled refs while the frontier stays behind, subsequent maintenance ticks rescan the same 48 owners and repeatedly pay the bootstrap cost.

Fix: after each nonempty bootstrap stage, require a changed frontier, then read back all bootstrap progress fields within the same registered writer transaction and reject mismatches. The existing rollback owner aborts enrolled owner references and body-candidate seeds together. No SQL state is reset or discarded; the durable owner/candidate invariants remain unchanged.

Regression added: 52 raw owners sharing one still-live canonical body, with an AFTER UPDATE trigger that deliberately rewrites raw_through to zero. A 48-row page must fail closed after staging 48 refs; rollback must restore zero refs and the original frontier. Removing the injected fault must produce actual, distinct committed 48+4 raw pages, finish bootstrap and candidate discharge, retain the live body and quiesce. A separate disposable SQLite reproduction with recursive triggers enabled observed refused 48 / durable refs 0, then committed 0→48→52, then idle. This is a mechanistic reproduction, not an affected-host diagnosis or repository Bazel test pass.

Validation: compared the exact two-file commit diff against parent 91ffd680; no changes to metadata parsing, Kev/decision model, held draft #4776, release #4763, infrastructure, credentials or other owner work. Published with expected_sha=91ffd680d7ec128dbf5cd14d9bcc721b4e457a21, force=false and verified the PR head. Local runtime has no Bazel/toolchain or repository checkout; no Cargo. Exact-head hosted CI #42443962770 is queued. Require actual nonzero Bazel unit tests, Rust format/Clippy and reviews on this head.

Still open: this is a verified failure class and rollback guard, not proof this trigger or checkpoint rewrite caused the reported 90–110% production CPU. Correlate consecutive committed GC/replay frontiers and candidate discharge with per-tick duration, rollback diagnostics, and affected-host CPU before a Fixes #4787 claim. The cold-store JSON cursor is a distinct authority. Do not auto-merge; keep #4787 open and #4776 draft/unmerged.

Apply the exact formatting required by the failing Bazel rustfmt gate
in the new canonical-body frontier rollback regression.

Refs #4787

Copy link
Copy Markdown
Owner Author

Refs #4787 — fixed the next exact-head CI blocker on isolated PR #4798.

Bazel CI run 42443962770 failed only the repository Rust formatting gate at crates/tracedecay-global-db/src/observation/canonical_body_gc/tests.rs:598: the new 52-owner checkpoint regression's assert_eq! required a multiline rustfmt layout. Published 21032e3de2e90d2860d8d73b8e10e3c8faf6ffd7 with only the exact formatting change. Verified it is one fast-forward commit after ad3729b, and updated the PR using expected_sha=ad3729b..., force=false. No production behavior or other owner files changed.

Exact-head CI run 42446728946 is queued, not passing yet. Repository Rust/Bazel regressions, affected-host 90–110% CPU and consecutive SQL frontiers/tick timings still require validation. Keep this PR unmerged until the relevant gates pass, keep issue #4787 open until master-proven acceptance, and leave mixed draft #4776 and release #4763 untouched.

Bound replay eligibility admission by the conservative body verification
budget before parsing metadata. Deferred rows no longer incur repeated
JSON validation on successive ticks. Assert exactly-once metadata admission
across database-backed multi-page body-budget regressions.

Refs #4787

Copy link
Copy Markdown
Owner Author

Refs #4787 — published focused replay-CPU work to this issue-specific PR at 8e044d4, a single-parent, nonforce expected-old-head fast-forward from 21032e3. Only crates/tracedecay-lcm/src/retention/replay_metadata.rs and its existing database-backed tests changed.

Defect found in the previous bounded-parsing fix: candidates() enforced its 4 MiB metadata-admission budget before evaluating JSON eligibility, but could still parse eligibility for future eligible rows that step() could not visit because the independent 4 MiB body-verification budget was exhausted. Those deferred rows were JSON-parsed again on later ticks, amplifying CPU despite strictly advancing SQL frontiers. The repair conservatively admits inline candidates under both metadata and body byte estimates before the batched eligibility query. Individually oversized rows still advance without loading or rewriting their bodies; non-inline rows remain ineligible; no per-row database round trips or weakened checks were added.

Falsifiable behavioral regression: extended the real Rust row_and_byte_budgets_advance_a_durable_frontier_and_finished_pages_are_noops fixture to retain each row's actual stored metadata byte length and assert that each body-budgeted page's metadata_bytes_examined equals only its scanned rows, including the final and idle pages. The previous implementation fails the middle-page assertion: it prefetched metadata for more rows than it could scan. Existing receipt, body-preservation, rollback and frontier tests are unchanged.

An independent disposable SQLite size-admission analog with four ~700 KiB canonical/replay rows reproduced the discrepancy: the old 48-row admission submitted 2,800,244 bytes for eligibility despite processing only two rows (1,400,122 bytes of those rows); the corrected admission submits 1,400,122 bytes and resumes the remaining two on the next page. This is not a repository Rust/Bazel or affected-host CPU pass. No Bazel toolchain/checkout is available locally; no Cargo was run. Exact-head CI run 42451037206 is queued; exact-head Rust tests/formatting/Clippy must still pass.

Keep issue #4787 open and retain Refs #4787: the 90–110% affected-host CPU incident is not proven resolved without consecutive committed SQL frontiers, candidate discharge, real per-tick span timings and the CPU trend, followed by master acceptance. Protected mixed #4776 remains draft / never merge, and release #4763, production/infra, tags, credentials and other owner branches/schedules are untouched.

Measure each canonical-body GC and replay-metadata pass from admission
through successful writer commit. Include elapsed milliseconds and
admitted metadata bytes in the existing daemon progress events so an
affected host can distinguish stalled page retries from costly but
advancing backlogs. Preserve the transactional progress guards.

Refs #4787

Copy link
Copy Markdown
Owner Author

Refs #4787 — published focused instrumentation on this issue-specific PR, commit a1b2bcf. The new daemon retention page events report wall-clock elapsed_ms through successful writer commit for both canonical-body GC and replay compaction. Replay events now also report metadata_bytes_examined alongside the already-published durable frontier_before/after, while canonical events retain actual candidates_discharged. This gives affected-host logs real per-page time/cost and transactional progress for deciding whether 48-row ticks are stalled or merely advancing through a backlog. The durations are elapsed wall time, not process CPU samples; metadata_bytes_examined measures admitted SQL eligibility input, not total physical bytes read. No budgets or scheduling were weakened.

I independently checked the exact three-file, single-parent diff against 8e044d4, then published the update with expected_sha=8e044d4..., force=false, and verified the PR head is a1b2bcf. Existing database-backed 48+4, checkpoint-refusal, rollback, and quiescence regressions remain present. No local Bazel executable or repository checkout is available in this runtime; no Rust/Bazel test pass is claimed and no Cargo was used. Exact-head hosted CI is queued.

This is a diagnostic improvement, not an affected-host incident resolution. Affected-host CPU samples and consecutive committed SQL frontier/candidate/tick measurements are still needed. Keep issue #4787 open and PR #4798 under validation, without auto-merge. Protected mixed #4776 remains draft and excluded from merging; release #4763, production, and other issue-owner branches are unchanged.

Apply the exact three rustfmt transformations in the latest failed
repository gate without changing retention behavior.

Refs #4787

Copy link
Copy Markdown
Owner Author

Refs #4787 — published CI remediation 3924b363 to this isolated retention PR. Previous exact-head CI run 42453542610 failed Repository gates only because Bazel rustfmt found three layout diffs: the if let chain in replay_metadata.rs:167 and two elapsed_ms.map_or_else calls in daemon/maintenance.rs:388,441. The new commit applies exactly those three formatting transformations; no behavior or tests were changed. Verified an exact-old-head (a1b2bcf...), nonforce fast-forward and confirmed both remote branch and PR head at 3924b363. New CI run 42458529667 is queued; repository Bazel Rust tests and Clippy are not yet confirmed on this commit. No Cargo used.

Reviewed concurrency: #4813 also edits daemon/maintenance.rs (separate writer admission path); its branch was not touched or rebased. #4776 remains draft and excluded from merging; release #4763 and master untouched. This is not evidence that the original 90–110% affected-host CPU incident is resolved. Keep #4787 open, do not use Fixes, and do not merge or auto-merge without acceptance evidence.

Copy link
Copy Markdown
Owner Author

Refs #4787 — exact-head Bazel Rust validation is now available on CI run 42458529667, head 3924b36324044b9770ebb81fc201b40ae0e55a10 (2026-11-08). The prior “tests queued” status is superseded.

Relevant results: //crates/tracedecay-global-db:unit_test PASSED (121.5s) and //crates/tracedecay-lcm:unit_test PASSED (30.9s), including the published database-backed canonical/replay pagination and checkpoint regressions. Repository formatting/policy gates, Clippy, Dashboard, and Feature gates also passed.

New CI blocker, not a proven #4787 regression: Test Linux (fleet) FAILED four suites:

  • //crates/tracedecay:automation_runner_test: 3 scheduler tests return backend_unconfigured instead of the expected due/lock outcomes. The same three failures at the same lines also occur on unchanged master SHA 91c72aba, master CI 42328697300; not introduced by this retention-only patch.
  • //crates/tracedecay:daemon_suite: unrelated mounted fan-out journey reports workflow.reset_required.
  • //crates/tracedecay:dashboard_api_test: fact detail test times out on fact_store_add.
  • //crates/tracedecay-session-memory:unit_test: canonical temporal-digest test times out. These last three may be environmental/load-sensitive but are not yet baseline-qualified, so their failure cannot be waived.

The separate Linux and Windows legs were still queued/in progress on last check. No CI was weakened and no unrelated owner branches were edited. Keep this PR unmerged until required gates are resolved and independently reviewed. The underlying affected-host 90–110% CPU incident still lacks post-fix repeated-tick SQL-frontier, candidate-count, wall-time and CPU observations; this exact-head Bazel pass establishes code regressions, not production incident resolution. Issue #4787 remains open. #4776 must remain draft/unmerged; #4763 read-only.

Use SQLite record byte lengths without materializing raw text. Defer
storage-kind reads and unnecessary canonical lookups until admission,
and do not read canonical size scalars beyond an oversized BLOB.
Skip eligibility parsing when the stored representations already exceed
the page budget, while preserving the rows and advancing the frontier.

Add an isolated Linux database regression measuring actual read syscall
bytes for oversized inline, metadata, and canonical payloads. Verify
subsequent valid compaction, complete byte preservation, and quiescence.

Refs #4787

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@ScriptedAlchemy ScriptedAlchemy left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Refs #4787 — independent review of the new replay read-cost patch at a945a8b85b4a1f3f146872ff226d3319014b9b21 (one nonforce fast-forward after 3924b363). This changes only the replay size/admission path and a Linux process-I/O behavioral regression; it does not move or duplicate the protected #4776 work.

I exercised the exact new size-discovery SQL in a disposable SQLite 3.46.1 database with 52 inline rows, multibyte/NUL text and a deliberately lowered SQLITE_LIMIT_LENGTH=1024: pages returned 48, then 4, then 0, with exact byte lengths. An ordinary full-content read failed at that limit. A separate file-backed overflow fixture (8 MiB inline body, 8 MiB metadata, 8 MiB canonical BLOB, mmap off) observed only ~8–16 KiB /proc/self/io rchar per isolated size-probe query; that corroborates the avoided full-text materialization, not a daemon CPU benchmark. The older LENGTH(CAST(... AS BLOB)) implementation fails the tight-limit probe.

Review scope: the new conditional canonical join, query budget admission, durable frontier guard and the child-process read-cost regression; no independent correctness issue found in those paths. The new read_cost test is Linux-only and exact-head Bazel CI is still queued, so this is not Rust/Bazel/macOS/Windows execution evidence or proof the affected-host 90–110% CPU incident is resolved. Require exact-head CI and real successive committed frontiers/candidates, per-tick timing, rollback evidence and CPU samples before closing #4787. No approval to merge is implied.

Apply the exact Bazel rustfmt_check_2024 correction at read_cost.rs:62.
No runtime or test behavior changes.

Refs #4787

Copy link
Copy Markdown
Owner Author

Refs #4787 — published CI-format repair ee4dc4cb18947177d78862ed4e1c9f400a7a02d2 to this existing issue-specific PR, preserving all concurrent work with expected_sha=a945a8b85b4a1f3f146872ff226d3319014b9b21, force=false.

Exact-head blocker: run 42470152899 failed Repository gates at //crates/tracedecay-lcm:rustfmt_check_2024, solely on a one-line layout change in crates/tracedecay-lcm/src/retention/replay_metadata/read_cost.rs:62. This commit applies exactly the formatter's displayed transformation. No production SQL or regression semantics changed. The remote PR head has been verified at ee4dc4c.

The superseding exact-head CI run 42477719995 is queued, not a pass. No local Bazel executable available; no Cargo used. The earlier 3924b36 relevant Bazel Rust tests passed, but this new Linux read-cost test still needs an exact-head pass. Keep #4787 open pending full CI and affected-host consecutive committed frontier, candidate discharge, elapsed page/tick and CPU evidence. No Fixes claim. Keep #4776 draft/unmerged; #4813, release #4763 and operator systems untouched.

Refs #4787

Use a fresh exact-SQL test connection for each measured replay page,
so SQLite cannot reuse a warmed per-connection page cache. Remove the
cache/mmap/shrink PRAGMAs rejected by the registered SQL authority.
Keep the byte-read thresholds, 48-row semantics, frontier assertions,
post-repair replay equivalence, and idle checks unchanged.

Copy link
Copy Markdown
Owner Author

Refs #4787 — repaired the exact-head Linux Bazel regression in the isolated issue PR.

CI run 42477719995, head ee4dc4cb, failed //crates/tracedecay-lcm:unit_test because the new oversized_rows_skip_payload_io fixture attempted PRAGMA cache_size / PRAGMA mmap_size through the registered exact-SQL test authority. SQLite refused execute_batch with SQLITE_AUTH (23), not authorized at read_cost.rs:55, before any read-cost assertions ran. PRAGMA shrink_memory used later in the fixture was subject to the same restriction.

Published 33988f731c8d as a single-file test-only correction. It removes the unauthorized PRAGMAs and opens a fresh TestConnection for each measured page, retaining cold per-connection SQLite caches instead of relaxing the process-read assertion. The three oversized cases, retained-byte checks, exact SQL frontier, replay-equivalence assertion and idle termination are unchanged. The commit is a one-parent, expected-old-head ee4dc4cb, force=false fast-forward; remote PR head verified.

New exact-head Bazel CI 42491853590 is pending. I did not run Cargo or claim local Bazel/native macOS tests. The older fleet run also had three scheduler tests known red on master and other broad-suite timeouts; those are not solved by this retention-only correction. Keep #4798 unmerged until exact-head tests and review pass. Original 90–110% affected-host CPU condition still lacks consecutive post-fix candidate discharge, durable SQL frontiers, tick durations and CPU measurements. Issue #4787 remains open; #4776 remains draft/unmerged, #4763 read-only, #4813 separately owned.

Copy link
Copy Markdown
Owner Author

Refs #4787 — exact-head Bazel CI update for 33988f731c8d8de09b2fbeca18fe4572e5599a8c (run 42491853590, 2026-11-08).

The issue-owned regression now passes: //crates/tracedecay-lcm:unit_test (7.2s), including the Linux isolated oversized-replay read-cost test corrected in 33988f7; //crates/tracedecay-global-db:unit_test also passes (280.7s). Repository gates, Clippy, Dashboard and Feature gates are green. This is hosted Bazel execution, not a local Cargo run or a macOS affected-host measurement.

Remaining new CI blockers: Linux fleet still fails automation_runner_test in the same three backend_unconfigured scheduler cases already reproduced on unmodified master 91c72aba (master run 42328697300); do not copy/rework that active ownership into this retention PR. It also fails runtime_acceptance_suite::runtime_surface_acceptance::stdio_bridge_exits_successfully_after_client_shutdown_and_exit with LSP gateway request deadline elapsed; explicit detach failed: ... authority is unavailable. Unlike the scheduler failures, this test passed on that master fleet run, so it is an unqualified new CI failure, not a proven #4787 regression or a known baseline red. The Linux summary job therefore fails. Windows was still in progress at this check. CI remains unweakened.

No new retention-source defect was established from these failures and no unrelated owner code was altered. Keep #4798 unmerged and #4787 open. The original ~90–110% affected-host CPU still requires successive committed GC candidate discharges and replay SQL frontiers, per-page/tick wall-time/CPU observations, and stable host CPU after the fix before incident closure. Protected mixed #4776 remains DRAFT/unmerged; #4813 is separately owned; #4763 and production/infra/tags/credentials remain untouched.

Refs #4787

Validate the selected candidate hashes are absent inside the same writer
transaction after DELETE. An AFTER DELETE trigger can reinsert all 48 rows
while SQLite reports 48 affected deletes, producing false progress and
repeat page work. The readback fails closed so the caller rolls back.

Add a 52-body database-backed regression proving reinserted pages are
refused without losing candidates, then recover as distinct 48+4 pages.
Refs #4787

Remove an extra blank line introduced with the candidate-count helper.

Copy link
Copy Markdown
Owner Author

Refs #4787 — published a focused false-progress guard on issue-specific PR #4798: 370e91d, followed by the test-helper formatting correction fd2ac3d. Both were nonforce, exact expected-old-head fast-forwards; the verified PR head is now fd2ac3d.

Newly proven failure class: the existing GC candidate discharge check used DELETE affected-row count (+ body cascades) to prove that 48 candidates were discharged. An AFTER DELETE trigger can reinsert those same 48 rows while SQLite still reports 48 changed rows, leaving has_more=true and the same batch selected on the next tick. The repair verifies, inside the same writer transaction, that none of the selected candidate hashes remain after deletion; otherwise the existing caller rolls back and reports an explicit failure rather than false committed progress. It does not reset any SQL state or change GC eligibility.

Nonvacuous regression: 52 distinct referenced canonical bodies reach candidate collection; a fixture trigger re-enqueues every deleted candidate. The 48-row page must fail with the new typed DB integrity diagnostic and preserve all 52 candidates across rollback. After removing the fixture trigger, two committed pages must discharge 48 then 4, delete no referenced bodies, and become idle. A disposable SQLite analog independently verified the old false-positive (DELETE rowcount=48, all 52 candidates still present) and post-trigger recovery (48 deleted, 4 remain); that is not Bazel execution.

New exact-head Bazel CI is queued, not a pass. Local Bazel is unavailable; no Cargo was used. Previous head 33988f7 passed the relevant global-db/LCM Bazel suites; this head still requires confirmation. Broad Linux fleet had known-master scheduler failures and an unqualified LSP shutdown timeout, with Windows previously still running. The original affected-host 90–110% CPU cause and post-fix per-tick SQL frontier/CPU measurements remain unverified; do not claim resolved or merge yet. Keep issue #4787 open; #4776 stays DRAFT/unmerged, #4813 separately owned, release #4763 read-only.

Copy link
Copy Markdown
Owner Author

Refs #4787 — verified the latest issue-specific PR head d21084185df37bd8230545e25cd18524b625980b. The preceding exact-head Bazel run 42521052221 failed the repository gate on two Rust formatting diffs in crates/tracedecay-global-db/src/observation/canonical_body_gc/tests.rs (lines 670 and 694); the new commit applies only those two rustfmt layouts. Compared fd2ac3d..d210841: exactly one fast-forward commit, one changed test file, 7 additions/2 deletions, no runtime behavior changes. The new exact-head CI 42522861982 has Repository gates running; relevant Bazel unit suites and broader fleet gates are not yet established on this head. No local Bazel executable/checkout; no Cargo run.

Reviewed current root AGENTS.md, relevant nested guidance locations, full #4787 discussion, changed GC/replay/daemon source and behavioral test paths, master baseline, PR review threads and related #4813 ownership. master still does not contain the six-file #4798 patch. Affected-host CPU and consecutive committed-frontier/per-tick measurements remain unavailable; the separate cold-store JSON cursor is not the canonical/replay SQL frontier. Keep #4787 open and #4798 unmerged pending exact-head tests and master/host acceptance. Protected mixed #4776 and Kev qualification #4797 remain DRAFT/unmerged; #4813 remains separately owned. No production/infra/release #4763/credential or other-branch change.

Repair three hosted automation_runner_test failures by supplying the
configured executable identity required by the production prefilter.
Use the same identity for the prefilter and retained runner, preserving
manual-schedule, exact-ledger, live-lock and lock-race assertions.

Add a production-prefilter regression for unconfigured refusal,
deduplication and same-occurrence recovery after binding, with zero
backend calls and no effectful terminal. Do not relax backend admission,
change timeouts, or alter the graph publication changes.

Refs #4532

Copy link
Copy Markdown
Owner Author

Refs #4787 — new issue-PR scope/validation blocker on current head 57bae69e909ec818e9238f26cbf1bfe41dcba69f (Nov 8, 2026).

The new single-parent commit after d210841 changes only crates/tracedecay/tests/automation_runner_test/jobs.rs: it supplies a configured test backend for three scheduler cases known red on unchanged master and adds a backend-recovery scheduler regression. That is useful CI-baseline work, but it is not a canonical-body/replay-retention fix or an acceptance test for #4787. The issue-specific #4798 now changes seven files, although its description still claims a five-file retention-only scope. Do not treat a green scheduler test on this mixed head as evidence of incident resolution. Preserve that concurrently published commit and coordinate the scheduler CI repair with its owner; do not overwrite or force-push it. The retention changes can still be reviewed independently against master once ownership/scope is reconciled.

The preceding exact-head CI run 42522861982 was cancelled when the head moved (not a passing Rust/Bazel run). New exact-head CI 42527459668 is queued; no relevant tests on 57bae69 have passed yet. Local Bazel/checkout is unavailable; no Cargo used. The affected macOS host still lacks post-fix consecutive committed candidate discharge, replay frontier, page/tick wall time and CPU evidence. master remains 91c72aba without this retention patch. Keep #4787 OPEN and #4798 unmerged pending qualification. Kev/decision-model and mixed #4776 remain DRAFT/unmerged; #4813 separately owned; #4763/release and production untouched.

This branch has not been deployed

No deployments
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