fix: preserve offline tuner exposure evidence - #409
Conversation
Keep retrieval subjects distinct from served playbook owners and protect the fixed evidence window at the shared retention selection boundary.
Treat blank and whitespace retrieval user IDs as unscoped at the shared exposure boundary so attribution, mismatch checks, and storage use one canonical representation.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 33 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe change separates retrieval-user and playbook-owner identity in exposure events. It also adds a 14-day minimum age to exposure-event retention and applies age cutoffs during retention key selection. ChangesSearch exposure identity
Retention minimum age
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
## Summary - Revert #407 and restore session outcomes, governance erasure, billing, and search behavior to the pre-open-world-evidence contracts. - Also revert #408 and #409 because their finalization-receipt and exposure-retention changes depend entirely on APIs introduced by #407. - Preserve the independent incremental aggregation work from #405 and #410. - Address every valid CodeRabbit finding, including SQLite downgrade compatibility and retry-safe metering. - Fix callback drop-rate anomaly emission on hosts with less than one hour of monotonic uptime, discovered by the full validation run. ## Changes ### Evidence foundation rollback - Remove search-exposure recording and session-outcome identity helpers. - Restore the prior session outcome schemas, client surface, and SQLite/storage contracts. - Restore the prior governance erase/claim flow and retention behavior. - Restore the prior resumable extraction and learning-billing behavior. ### Dependent follow-ups - Remove receipt-winner finalization behavior from #408. - Remove the exposure ownership and protected-retention behavior from #409. ### Review follow-ups - Rebuild #407-era SQLite `session_outcomes` tables into the restored schema, preserving `success`/`failure` rows, backfilling governance subject references, and explicitly dropping unrepresentable `unknown` outcomes with a warning. - Restore the SQLite 3.35 minimum required by existing `RETURNING` and `DROP COLUMN` usage. - Make outcome erasure resilient to governance-secret rotation and return a stable `session_outcomes` deletion count. - Acquire SQLite governance write locks before state checks, serialize idempotent purge begin/prepare flows across connections, and roll back failed target writes so SQLite cannot retain a stale writer transaction.\n- Reject legacy session-outcome schemas with empty governance-subject defaults and rebuild them with derived subject references.\n- Make synchronous playbook/profile persistence atomic while keeping scheduler dispatch strictly post-commit. - Meter resumable extraction from persisted survivors only, use retry-stable fallback keys, and emit learning billing from incremental aggregation. - Treat post-persist optimization and aggregation scheduling failures as best-effort side effects. ### Validation follow-up - Represent the callback executor's last anomaly time with an explicit unset sentinel so the first threshold crossing is never suppressed by low system uptime. ## Test Plan - `uv run ruff check reflexio tests` - `uv run ruff format --check reflexio tests` - Pyright on all 23 staged Python files: 0 errors, 0 warnings - Latest affected review files: 301 passed - OSS non-E2E suite: 5,535 passed, 73 skipped, 6 subtests passed - OSS E2E suite: 47 passed, 51 skipped - `npm --prefix docs run lint`: 0 errors (3 existing warnings) - `cd docs && npx tsc --noEmit` - `python -c "import reflexio"` Reverts `85a4b2255a96ef2a5b50f4cbe7c10758439e76b3`, plus dependent follow-ups `785a9e053ff771f40704bb7b0b5bbbe36048806a` and `eb88f44fd3b53457b76e8500ac1a30ba7d4ab16e`. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Changes** - Session outcomes now support only success or failure, with simpler responses and retry behavior. - Governance data erasure workflows have streamlined retry and completion handling, including session-outcome removal. - Search exposure event recording has been removed; search results and metering remain available. - Learning-generation billing supports durable per-record tracking, retry-stable keys, and count-based fallback. - Scheduler failures during playbook processing are logged without preventing other scheduled actions. - **Documentation** - Quick Start prerequisites now list Node.js without the previous SQLite verification step. - Billing and extraction guidance has been updated. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary - preserve every user-playbook exposure ingested within the fixed 14-day evidence window, even when the generic row cap is exceeded - separate the optional retrieval subject from the served playbook owner so unscoped searches remain attributable without becoming join-eligible - normalize blank retrieval subjects to the unscoped representation while retaining fail-closed owner checks for scoped searches ## Why The Phase 1 offline-tuner evidence foundation requires complete, reviewable exposure evidence. Generic row-cap retention could delete current-window events, and the original exposure envelope overloaded playbook ownership as the retrieval subject for unscoped searches. Both behaviors could distort later evidence eligibility and exact-user governance. ## Behavior - exposure rows younger than 14 days are protected from row-cap deletion - an exposure may carry a retrieval subject and a playbook owner independently - blank or whitespace retrieval subjects become unscoped - scoped retrieval still rejects a user playbook owned by another user before persistence ## Verification - 46 shared exposure and retention contract tests passed after rebasing onto current `main` - final affected enterprise matrix: 164 passed, 9 adapter-applicability skips - Ruff formatting/lint, Pyright, import, diff, and gitlink checks passed - correctness, security-resilience, architecture, and verification-testing review lenses are clean ## Related PRs - Enterprise Phase 1 stack: ReflexioAI/reflexio-enterprise#936 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Exposure records now preserve the playbook owner separately from the person retrieving it. * Blank retrieval identifiers are normalized consistently. * Playbook exposure data now includes governance subject references where available. * **Bug Fixes** * Prevented exposure records from being created when a playbook belongs to a different scoped user. * Added safeguards for unscoped exposure scenarios. * **Data Retention** * Open-world evidence, including playbook exposure records, is retained for at least 14 days before cleanup. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary - preserve every user-playbook exposure ingested within the fixed 14-day evidence window, even when the generic row cap is exceeded - separate the optional retrieval subject from the served playbook owner so unscoped searches remain attributable without becoming join-eligible - normalize blank retrieval subjects to the unscoped representation while retaining fail-closed owner checks for scoped searches ## Why The Phase 1 offline-tuner evidence foundation requires complete, reviewable exposure evidence. Generic row-cap retention could delete current-window events, and the original exposure envelope overloaded playbook ownership as the retrieval subject for unscoped searches. Both behaviors could distort later evidence eligibility and exact-user governance. ## Behavior - exposure rows younger than 14 days are protected from row-cap deletion - an exposure may carry a retrieval subject and a playbook owner independently - blank or whitespace retrieval subjects become unscoped - scoped retrieval still rejects a user playbook owned by another user before persistence ## Verification - 46 shared exposure and retention contract tests passed after rebasing onto current `main` - final affected enterprise matrix: 164 passed, 9 adapter-applicability skips - Ruff formatting/lint, Pyright, import, diff, and gitlink checks passed - correctness, security-resilience, architecture, and verification-testing review lenses are clean ## Related PRs - Enterprise Phase 1 stack: ReflexioAI/reflexio-enterprise#936 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Exposure records now preserve the playbook owner separately from the person retrieving it. * Blank retrieval identifiers are normalized consistently. * Playbook exposure data now includes governance subject references where available. * **Bug Fixes** * Prevented exposure records from being created when a playbook belongs to a different scoped user. * Added safeguards for unscoped exposure scenarios. * **Data Retention** * Open-world evidence, including playbook exposure records, is retained for at least 14 days before cleanup. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary - preserve every user-playbook exposure ingested within the fixed 14-day evidence window, even when the generic row cap is exceeded - separate the optional retrieval subject from the served playbook owner so unscoped searches remain attributable without becoming join-eligible - normalize blank retrieval subjects to the unscoped representation while retaining fail-closed owner checks for scoped searches ## Why The Phase 1 offline-tuner evidence foundation requires complete, reviewable exposure evidence. Generic row-cap retention could delete current-window events, and the original exposure envelope overloaded playbook ownership as the retrieval subject for unscoped searches. Both behaviors could distort later evidence eligibility and exact-user governance. ## Behavior - exposure rows younger than 14 days are protected from row-cap deletion - an exposure may carry a retrieval subject and a playbook owner independently - blank or whitespace retrieval subjects become unscoped - scoped retrieval still rejects a user playbook owned by another user before persistence ## Verification - 46 shared exposure and retention contract tests passed after rebasing onto current `main` - final affected enterprise matrix: 164 passed, 9 adapter-applicability skips - Ruff formatting/lint, Pyright, import, diff, and gitlink checks passed - correctness, security-resilience, architecture, and verification-testing review lenses are clean ## Related PRs - Enterprise Phase 1 stack: ReflexioAI/reflexio-enterprise#936 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Exposure records now preserve the playbook owner separately from the person retrieving it. * Blank retrieval identifiers are normalized consistently. * Playbook exposure data now includes governance subject references where available. * **Bug Fixes** * Prevented exposure records from being created when a playbook belongs to a different scoped user. * Added safeguards for unscoped exposure scenarios. * **Data Retention** * Open-world evidence, including playbook exposure records, is retained for at least 14 days before cleanup. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary - preserve every user-playbook exposure ingested within the fixed 14-day evidence window, even when the generic row cap is exceeded - separate the optional retrieval subject from the served playbook owner so unscoped searches remain attributable without becoming join-eligible - normalize blank retrieval subjects to the unscoped representation while retaining fail-closed owner checks for scoped searches ## Why The Phase 1 offline-tuner evidence foundation requires complete, reviewable exposure evidence. Generic row-cap retention could delete current-window events, and the original exposure envelope overloaded playbook ownership as the retrieval subject for unscoped searches. Both behaviors could distort later evidence eligibility and exact-user governance. ## Behavior - exposure rows younger than 14 days are protected from row-cap deletion - an exposure may carry a retrieval subject and a playbook owner independently - blank or whitespace retrieval subjects become unscoped - scoped retrieval still rejects a user playbook owned by another user before persistence ## Verification - 46 shared exposure and retention contract tests passed after rebasing onto current `main` - final affected enterprise matrix: 164 passed, 9 adapter-applicability skips - Ruff formatting/lint, Pyright, import, diff, and gitlink checks passed - correctness, security-resilience, architecture, and verification-testing review lenses are clean ## Related PRs - Enterprise Phase 1 stack: ReflexioAI/reflexio-enterprise#936 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Exposure records now preserve the playbook owner separately from the person retrieving it. * Blank retrieval identifiers are normalized consistently. * Playbook exposure data now includes governance subject references where available. * **Bug Fixes** * Prevented exposure records from being created when a playbook belongs to a different scoped user. * Added safeguards for unscoped exposure scenarios. * **Data Retention** * Open-world evidence, including playbook exposure records, is retained for at least 14 days before cleanup. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary - preserve every user-playbook exposure ingested within the fixed 14-day evidence window, even when the generic row cap is exceeded - separate the optional retrieval subject from the served playbook owner so unscoped searches remain attributable without becoming join-eligible - normalize blank retrieval subjects to the unscoped representation while retaining fail-closed owner checks for scoped searches ## Why The Phase 1 offline-tuner evidence foundation requires complete, reviewable exposure evidence. Generic row-cap retention could delete current-window events, and the original exposure envelope overloaded playbook ownership as the retrieval subject for unscoped searches. Both behaviors could distort later evidence eligibility and exact-user governance. ## Behavior - exposure rows younger than 14 days are protected from row-cap deletion - an exposure may carry a retrieval subject and a playbook owner independently - blank or whitespace retrieval subjects become unscoped - scoped retrieval still rejects a user playbook owned by another user before persistence ## Verification - 46 shared exposure and retention contract tests passed after rebasing onto current `main` - final affected enterprise matrix: 164 passed, 9 adapter-applicability skips - Ruff formatting/lint, Pyright, import, diff, and gitlink checks passed - correctness, security-resilience, architecture, and verification-testing review lenses are clean ## Related PRs - Enterprise Phase 1 stack: ReflexioAI/reflexio-enterprise#936 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Exposure records now preserve the playbook owner separately from the person retrieving it. * Blank retrieval identifiers are normalized consistently. * Playbook exposure data now includes governance subject references where available. * **Bug Fixes** * Prevented exposure records from being created when a playbook belongs to a different scoped user. * Added safeguards for unscoped exposure scenarios. * **Data Retention** * Open-world evidence, including playbook exposure records, is retained for at least 14 days before cleanup. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary - preserve every user-playbook exposure ingested within the fixed 14-day evidence window, even when the generic row cap is exceeded - separate the optional retrieval subject from the served playbook owner so unscoped searches remain attributable without becoming join-eligible - normalize blank retrieval subjects to the unscoped representation while retaining fail-closed owner checks for scoped searches ## Why The Phase 1 offline-tuner evidence foundation requires complete, reviewable exposure evidence. Generic row-cap retention could delete current-window events, and the original exposure envelope overloaded playbook ownership as the retrieval subject for unscoped searches. Both behaviors could distort later evidence eligibility and exact-user governance. ## Behavior - exposure rows younger than 14 days are protected from row-cap deletion - an exposure may carry a retrieval subject and a playbook owner independently - blank or whitespace retrieval subjects become unscoped - scoped retrieval still rejects a user playbook owned by another user before persistence ## Verification - 46 shared exposure and retention contract tests passed after rebasing onto current `main` - final affected enterprise matrix: 164 passed, 9 adapter-applicability skips - Ruff formatting/lint, Pyright, import, diff, and gitlink checks passed - correctness, security-resilience, architecture, and verification-testing review lenses are clean ## Related PRs - Enterprise Phase 1 stack: ReflexioAI/reflexio-enterprise#936 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Exposure records now preserve the playbook owner separately from the person retrieving it. * Blank retrieval identifiers are normalized consistently. * Playbook exposure data now includes governance subject references where available. * **Bug Fixes** * Prevented exposure records from being created when a playbook belongs to a different scoped user. * Added safeguards for unscoped exposure scenarios. * **Data Retention** * Open-world evidence, including playbook exposure records, is retained for at least 14 days before cleanup. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
Why
The Phase 1 offline-tuner evidence foundation requires complete, reviewable exposure evidence. Generic row-cap retention could delete current-window events, and the original exposure envelope overloaded playbook ownership as the retrieval subject for unscoped searches. Both behaviors could distort later evidence eligibility and exact-user governance.
Behavior
Verification
mainRelated PRs
Summary by CodeRabbit
New Features
Bug Fixes
Data Retention