Skip to content

fix: preserve offline tuner exposure evidence - #409

Merged
guangyu-reflexio merged 3 commits into
mainfrom
codex/offline-tuner-phase1-broad-final-fix
Aug 3, 2026
Merged

fix: preserve offline tuner exposure evidence#409
guangyu-reflexio merged 3 commits into
mainfrom
codex/offline-tuner-phase1-broad-final-fix

Conversation

@guangyu-reflexio

@guangyu-reflexio guangyu-reflexio commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

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

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.

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.
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: CHILL

Plan: Pro

Run ID: ab2db41f-939a-4c72-b005-e928e2ceed28

📥 Commits

Reviewing files that changed from the base of the PR and between 0d1052d and e2c10db.

📒 Files selected for processing (1)
  • tests/server/services/storage/test_storage_contract_retention.py
📝 Walkthrough

Walkthrough

The 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.

Changes

Search exposure identity

Layer / File(s) Summary
Exposure identity contract
reflexio/server/services/search_exposure.py
Exposure batches normalize user_id. Events record the retrieval user, playbook owner, and owner governance subject reference. Scoped retrieval rejects a playbook owned by another user.
Exposure identity validation
tests/server/services/test_search_exposure.py
Tests cover unscoped retrieval, blank subject normalization, owner identity preservation, and mismatched-owner rejection.

Retention minimum age

Layer / File(s) Summary
Retention age configuration
reflexio/server/services/storage/retention.py
Retention targets support minimum_age_seconds. Exposure events use a 14-day minimum age.
Age-aware retention cleanup
reflexio/server/services/storage/retention_mixin.py, reflexio/server/services/storage/sqlite_storage/base/_deletion.py
Cleanup computes an epoch cutoff and passes it through priority and fallback selection. SQLite filters selected rows by the ordering-column timestamp.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: yyiilluu

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: preserving offline tuner exposure evidence.
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 codex/offline-tuner-phase1-broad-final-fix

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

@guangyu-reflexio
guangyu-reflexio merged commit eb88f44 into main Aug 3, 2026
1 check passed
@guangyu-reflexio
guangyu-reflexio deleted the codex/offline-tuner-phase1-broad-final-fix branch August 3, 2026 21:38
yyiilluu added a commit that referenced this pull request Aug 4, 2026
## 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 -->
guangyu-reflexio added a commit that referenced this pull request Aug 6, 2026
## 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 -->
guangyu-reflexio added a commit that referenced this pull request Aug 7, 2026
## 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 -->
guangyu-reflexio added a commit that referenced this pull request Aug 10, 2026
## 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 -->
guangyu-reflexio added a commit that referenced this pull request Aug 11, 2026
## 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 -->
guangyu-reflexio added a commit that referenced this pull request Aug 13, 2026
## 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 -->
guangyu-reflexio added a commit that referenced this pull request Aug 14, 2026
## 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 -->
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