Skip to content

feat(lineage)!: B3 Task 7 — hard-remove mentioned_profiles + retire legacy ProfileChangeLog read path - #213

Merged
yilu331 merged 2 commits into
mainfrom
feat/lineage-b3-task7
Jun 23, 2026
Merged

feat(lineage)!: B3 Task 7 — hard-remove mentioned_profiles + retire legacy ProfileChangeLog read path#213
yilu331 merged 2 commits into
mainfrom
feat/lineage-b3-task7

Conversation

@yilu331

@yilu331 yilu331 commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Breaking change (B3 / Track A Task 7). Releases as 0.3.0 (pre-1.0 minor-as-breaking; major_on_zero=false). Pairs with the enterprise PR that bumps this submodule pointer.

BREAKING

mentioned_profiles is removed from the ProfileChangeLog / ProfileChangeLogView API + SDK response shape. Read added_profiles / removed_profiles instead. The field has always been an empty list (reconstruction never populated it) and was deprecated in T5.

Changes

  • Remove mentioned_profiles from the domain + view models, the reconstruction output, the UI converter, SDK exports + client, and the SQLite/Supabase/Postgres storage shapes. The frozen _DDL CREATE TABLE is untouched (Task 8).
  • Retire the legacy-vs-reconstruction parity machinery (reconstruction STAYS): delete lib/_lineage_parity.py, scripts/lineage_b3_parity_check.py, the Task-4 gate + classifier tests; remove the storage get_profile_change_logs + add_profile_change_log methods + converters; remove the RetentionTarget.
  • Relocate the reconstruction's storage protocol out of the parity module into lib/_profiles.py, renamed ChangeLogReadStorage.
  • Repoint the @skip_low_priority e2e tests off the removed storage read method.
  • major_on_zero = false so this pre-1.0 breaking change releases as 0.3.0.

Kept for Task 8

The legacy profile_change_logs table + _DDL, and the delete_all / delete_for_user storage methods (the GDPR remap + table rename/drop land in Task 8 — see the plan).

Verification

3005 OS unit+integration tests pass; ruff + pyright clean; full collection clean (3666 OS + 2895 enterprise, no import errors from the deletions).

Summary by CodeRabbit

Release Notes

  • New Features

    • Profile change logs are now reconstructed from lineage events instead of reading from the legacy stored records.
  • Breaking Changes

    • Removed mentioned_profiles from profile change log API responses and view models.
    • Profile change log results now focus on added_profiles, removed_profiles, and created_at metadata.

…ChangeLog read path (B3 Task 7)

BREAKING CHANGE: the always-empty `mentioned_profiles` field is removed from the
ProfileChangeLog / ProfileChangeLogView API + SDK response shape. Read
`added_profiles` / `removed_profiles` instead. (T5 deprecated it; it has always
been an empty list, and reconstruction never populated it.)

- remove `mentioned_profiles` from the domain + view models, the reconstruction
  output, the UI converter, SDK exports + client, and the SQLite/Supabase/Postgres
  storage shapes (NOT the frozen `_DDL` CREATE TABLE — that is Task 8).
- retire the legacy-vs-reconstruction parity machinery (reconstruction STAYS):
  delete `lib/_lineage_parity.py`, `scripts/lineage_b3_parity_check.py`, the
  Task-4 gate + classifier tests; remove the storage `get_profile_change_logs` +
  `add_profile_change_log` methods + their converters; remove the
  `RetentionTarget` for profile_change_logs.
- relocate the reconstruction's storage protocol out of the parity module into
  `lib/_profiles.py`, renamed `ChangeLogReadStorage` (dropping `get_profile_change_logs`).
- repoint the low-priority e2e tests off the removed storage read method.
- set `major_on_zero = false` so this pre-1.0 breaking change releases as 0.3.0,
  not 1.0.0.

KEEP (Task 8): the legacy `profile_change_logs` table + the `delete_all` /
`delete_for_user` storage methods (the GDPR remap + table rename/drop land there).
@coderabbitai

coderabbitai Bot commented Jun 23, 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: CHILL

Plan: Pro Plus

Run ID: 9c2d9cdc-41d0-4acd-8763-0ef57b641072

📥 Commits

Reviewing files that changed from the base of the PR and between 41c0d37 and fb8a3c8.

📒 Files selected for processing (2)
  • reflexio/lib/_profiles.py
  • tests/server/services/storage/test_storage_contract_extras.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • reflexio/lib/_profiles.py

📝 Walkthrough

Walkthrough

Removes the B3 lineage parity check infrastructure (_lineage_parity.py, lineage_b3_parity_check.py, three parity test files) and finalizes reconstruction-only change log delivery. Introduces a ChangeLogReadStorage protocol to replace ParityReadStorage, drops mentioned_profiles from ProfileChangeLog/ProfileChangeLogView, removes add_profile_change_log/get_profile_change_logs from storage interfaces, and updates all tests to use the public reconstruction API. Also adds major_on_zero = false to semantic release config.

Changes

B3 parity retirement and reconstruction finalization

Layer / File(s) Summary
Remove mentioned_profiles from ProfileChangeLog and ProfileChangeLogView
reflexio/models/api_schema/domain/entities.py, reflexio/models/api_schema/ui/entities.py, reflexio/models/api_schema/ui/converters.py
ProfileChangeLog drops the mentioned_profiles field; ProfileChangeLogView replaces it with explicit added_profiles, removed_profiles, and created_at fields; the converter stops populating mentioned_profiles.
ChangeLogReadStorage protocol and reconstruct_profile_change_log signature
reflexio/lib/_profiles.py
Introduces ChangeLogReadStorage Protocol defining the minimal read-only surface required by reconstruction; changes reconstruct_profile_change_log to accept that protocol instead of ParityReadStorage; docstrings updated to reflect frozen legacy table and tombstone omission behavior; ProfileChangeLog constructor no longer passes mentioned_profiles.
RestStorageReader cleanup and parity module/script deletion
reflexio/lib/_lineage_parity_readers.py, reflexio/lib/_lineage_parity.py, scripts/lineage_b3_parity_check.py
Removes get_profile_change_logs from RestStorageReader; rewrites module docstring and constants to focus on reconstruction; deletes entire _lineage_parity.py module (ParityReadStorage, ParityClass, ParityResult, classify_change_log_parity, run_parity_check) and lineage_b3_parity_check.py CLI.
Storage interface and retention cleanup
reflexio/server/services/storage/storage_base/_extras.py, reflexio/server/services/storage/sqlite_storage/_extras.py, reflexio/server/services/storage/sqlite_storage/_base.py, reflexio/server/services/storage/retention.py
Removes abstract add_profile_change_log and get_profile_change_logs from ExtrasMixin; removes concrete implementations and _row_to_profile_change_log converter from SQLiteStorage; removes profile_change_logs RetentionTarget entry.
Test suite updates: parity tests removed, reconstruction API adopted
tests/lib/test_lineage_parity_readers.py, tests/e2e_tests/test_*.py, tests/models/test_view_models.py, tests/server/...
Deletes test_lineage_parity.py, test_lineage_b3_parity_classifier_integration.py, and test_lineage_b3_parity_gate_integration.py; rewrites reader tests for reconstruction pipeline; switches all e2e and integration tests from direct storage access to reflexio_instance.get_profile_change_logs().profile_change_logs; removes mentioned_profiles and legacy write assertions; adds deletion-only contract coverage.

CI/Semantic release

Layer / File(s) Summary
Add major_on_zero = false to semantic release config
pyproject.toml
Adds major_on_zero = false with explanatory comments to [tool.semantic_release].

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ReflexioAI/reflexio#203: Directly adds the _lineage_parity.py module with ParityClass, ParityResult, classify_change_log_parity, and profile_reconstructible_request_ids that this PR deletes entirely.
  • ReflexioAI/reflexio#210: Adds/extends the parity components (run_parity_check, ParityReadStorage, RestStorageReader) that this PR removes from _lineage_parity.py and _lineage_parity_readers.py.
  • ReflexioAI/reflexio#191: Directly implements the reconstruct_profile_change_log function in reflexio/lib/_profiles.py whose storage protocol type and shape this PR changes (replacing ParityReadStorage with ChangeLogReadStorage and dropping mentioned_profiles).

Poem

🐰 The parity tables have served their time,
No more legacy reads, no more two-step climb.
mentioned_profiles gone, reconstruction reigns,
ChangeLogReadStorage flows through cleaner veins.
The rabbit hops on—B3's work is done! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: removing mentioned_profiles field and retiring the legacy ProfileChangeLog read path, which are the core objectives of this breaking change PR.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feat/lineage-b3-task7

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.

🧹 Nitpick comments (2)
reflexio/lib/_profiles.py (1)

585-589: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Trim the unused per-request methods from ChangeLogReadStorage.

reconstruct_profile_change_log now reads additions via get_all_generated_profiles, so keeping get_distinct_generated_from_request_ids and get_profiles_by_generated_from_request_id in this protocol makes new readers implement legacy hooks the function no longer needs.

♻️ Proposed protocol cleanup
-    def get_distinct_generated_from_request_ids(self) -> list[str]: ...
-
-    def get_profiles_by_generated_from_request_id(
-        self, request_id: str
-    ) -> list[UserProfile]: ...
-
     def get_all_generated_profiles(self) -> list[UserProfile]: ...
🤖 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 `@reflexio/lib/_profiles.py` around lines 585 - 589, Remove the unused method
signatures get_distinct_generated_from_request_ids and
get_profiles_by_generated_from_request_id from the ChangeLogReadStorage
protocol. Since reconstruct_profile_change_log now uses
get_all_generated_profiles for reading additions, these per-request methods are
no longer needed and their removal will prevent new implementations from being
forced to implement legacy hooks that are no longer utilized.
tests/server/api_endpoints/test_profile_change_log_api_integration.py (1)

73-87: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert removed-field absence in the raw API payload.

To lock the v0.3.0 contract, add an explicit raw-JSON assertion that mentioned_profiles is absent for the reconstructed row (model parsing alone can miss extra keys depending config).

Suggested test hardening
 resp = client.get("/api/profile_change_log")
 assert resp.status_code == 200, resp.text

-parsed = ProfileChangeLogViewResponse(**resp.json())
+payload = resp.json()
+parsed = ProfileChangeLogViewResponse(**payload)
 assert parsed.success is True

 rows = {row.request_id: row for row in parsed.profile_change_logs}
 assert run_id in rows, (
@@
 row = rows[run_id]
+raw_row = next(r for r in payload["profile_change_logs"] if r["request_id"] == run_id)
+assert "mentioned_profiles" not in raw_row

 assert [p.profile_id for p in row.added_profiles] == ["p-new-1"]
🤖 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 `@tests/server/api_endpoints/test_profile_change_log_api_integration.py` around
lines 73 - 87, The test currently validates the parsed
ProfileChangeLogViewResponse model but doesn't explicitly verify that the
`mentioned_profiles` field is absent from the raw JSON payload for the
reconstructed row. Add an explicit assertion after obtaining the row from
rows[run_id] that checks the raw JSON data from resp.json() to confirm the
`mentioned_profiles` field is not present in that row's data, ensuring the API
contract is properly locked and prevents unexpected fields from being served
even if the model parsing might miss them.
🤖 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.

Nitpick comments:
In `@reflexio/lib/_profiles.py`:
- Around line 585-589: Remove the unused method signatures
get_distinct_generated_from_request_ids and
get_profiles_by_generated_from_request_id from the ChangeLogReadStorage
protocol. Since reconstruct_profile_change_log now uses
get_all_generated_profiles for reading additions, these per-request methods are
no longer needed and their removal will prevent new implementations from being
forced to implement legacy hooks that are no longer utilized.

In `@tests/server/api_endpoints/test_profile_change_log_api_integration.py`:
- Around line 73-87: The test currently validates the parsed
ProfileChangeLogViewResponse model but doesn't explicitly verify that the
`mentioned_profiles` field is absent from the raw JSON payload for the
reconstructed row. Add an explicit assertion after obtaining the row from
rows[run_id] that checks the raw JSON data from resp.json() to confirm the
`mentioned_profiles` field is not present in that row's data, ensuring the API
contract is properly locked and prevents unexpected fields from being served
even if the model parsing might miss them.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: def9fb71-640f-460c-9997-8388a3ef7761

📥 Commits

Reviewing files that changed from the base of the PR and between 4072565 and 41c0d37.

📒 Files selected for processing (26)
  • pyproject.toml
  • reflexio/lib/_lineage_parity.py
  • reflexio/lib/_lineage_parity_readers.py
  • reflexio/lib/_profiles.py
  • reflexio/models/api_schema/domain/entities.py
  • reflexio/models/api_schema/ui/converters.py
  • reflexio/models/api_schema/ui/entities.py
  • reflexio/server/services/storage/retention.py
  • reflexio/server/services/storage/sqlite_storage/_base.py
  • reflexio/server/services/storage/sqlite_storage/_extras.py
  • reflexio/server/services/storage/storage_base/_extras.py
  • scripts/lineage_b3_parity_check.py
  • tests/e2e_tests/test_complete_workflows.py
  • tests/e2e_tests/test_interaction_workflows.py
  • tests/e2e_tests/test_profile_workflows.py
  • tests/lib/test_lineage_parity.py
  • tests/lib/test_lineage_parity_readers.py
  • tests/lib/test_profiles_unit.py
  • tests/models/test_view_models.py
  • tests/server/api_endpoints/test_profile_change_log_api_integration.py
  • tests/server/services/profile/test_dedup_always_soft_integration.py
  • tests/server/services/profile/test_profile_generation_service.py
  • tests/server/services/storage/test_lineage_b3_parity_classifier_integration.py
  • tests/server/services/storage/test_lineage_b3_parity_gate_integration.py
  • tests/server/services/storage/test_lineage_b3_reconstruct_changelog_integration.py
  • tests/server/services/storage/test_storage_contract_extras.py
💤 Files with no reviewable changes (15)
  • tests/server/services/storage/test_lineage_b3_parity_gate_integration.py
  • tests/lib/test_profiles_unit.py
  • reflexio/models/api_schema/ui/converters.py
  • tests/lib/test_lineage_parity.py
  • scripts/lineage_b3_parity_check.py
  • reflexio/models/api_schema/ui/entities.py
  • tests/server/services/storage/test_lineage_b3_parity_classifier_integration.py
  • reflexio/server/services/storage/storage_base/_extras.py
  • reflexio/lib/_lineage_parity.py
  • reflexio/server/services/storage/retention.py
  • reflexio/models/api_schema/domain/entities.py
  • tests/models/test_view_models.py
  • reflexio/server/services/storage/sqlite_storage/_extras.py
  • tests/server/services/storage/test_storage_contract_extras.py
  • reflexio/server/services/storage/sqlite_storage/_base.py

…(review-loop)

Address /review-loop findings on the B3 Task 7 PR:
- restore SQLite contract coverage for the KEPT delete_all_profile_change_logs /
  delete_profile_change_log_for_user methods. Deleting TestProfileChangeLogs
  wholesale dropped their only asserting test (the add/get tests had to go); the
  delete methods are retained for Task 8, so a kept abstract method must keep its
  guard. Seed the frozen table via direct SQL (add_profile_change_log is gone).
- reword the get_profile_change_logs docstring so it doesn't conflate the Task 6
  (stop write) / Task 7 (stop read + remove field) / Task 8 (drop table) boundaries.
@yilu331
yilu331 merged commit 2653774 into main Jun 23, 2026
1 check passed
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