Skip to content

feat: add explicit playbook provenance contracts#302

Merged
guangyu-reflexio merged 4 commits into
mainfrom
feature/tau-leaderboard-investor-report
Jul 7, 2026
Merged

feat: add explicit playbook provenance contracts#302
guangyu-reflexio merged 4 commits into
mainfrom
feature/tau-leaderboard-investor-report

Conversation

@guangyu-reflexio

@guangyu-reflexio guangyu-reflexio commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add explicit playbook citation provenance so citations can distinguish user and agent playbook targets.
  • Extend retrieval-log item contracts and storage persistence with explicit target metadata and source-window snapshot fields.
  • Keep legacy citation and retrieval-log compatibility while making new provenance fields available to enterprise offline tuner flows.

Changes

  • API/schema: explicit citation kind/real_id handling and retrieval-log item target fields.
  • Reflection/storage: canonical citation key handling plus SQLite storage support for explicit retrieval-log targets.
  • Tests: coverage for citation canonicalization, retrieval-log persistence, and explicit target compatibility.

Test Plan

  • uv run pytest --no-cov tests/server/services/reflection/test_post_horizon_filter.py tests/server/services/reflection/test_reflection_service.py tests/server/services/storage/test_sqlite_storage_bc_extras.py tests/server/services/storage/test_storage_contract_extras.py -q
  • Enterprise integration gates were run from the parent PR with REFLEXIO_GOVERNANCE_REF_SECRET=test-governance-ref-secret.

Summary by CodeRabbit

  • New Features

    • Expanded citation support to recognize more specific playbook citation types.
    • Improved handling of playbook references so explicit playbook sources are preserved in outputs and reports.
  • Bug Fixes

    • Fixed citation normalization so mixed legacy and explicit playbook references are handled consistently.
    • Improved filtering and deduplication so unsupported playbook-like citations are ignored where appropriate.
  • Documentation

    • Updated schema and storage guidance to reflect backward-compatible playbook reference handling.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR expands the CitationKind literal type to include user_playbook and agent_playbook alongside legacy playbook/profile values, propagating this type across domain models, API schemas, SQLite storage filtering, the reflection service's citation deduplication logic, and the openclaw plugin's wire citation mapping, with corresponding test coverage.

Changes

CitationKind Expansion and Propagation

Layer / File(s) Summary
Domain CitationKind type and Citation/PlaybookRetrievalLogItem contracts
reflexio/models/api_schema/domain/entities.py, reflexio/server/services/storage/storage_base/_retrieval_log.py
CitationKind literal is expanded and exported; Citation.kind uses it; PlaybookRetrievalLogItem gains target_kind/target_id and snapshot fields with a backfill validator for legacy agent_playbook_id; docs updated for backward compatibility.
API schema updates using CitationKind
reflexio/models/api_schema/eval_overview_schema.py, reflexio/models/api_schema/internal_schema.py, reflexio/models/api_schema/retriever_schema.py, reflexio/server/services/evaluation_overview/components/rule_attribution.py
RuleAttributionRow.kind, SessionCitation.kind, PlaybookApplicationStat.kind, and CitationKey/RuleAttribution.kind are retyped from string/literal to CitationKind.
SQLite storage citation-kind filtering
reflexio/server/services/storage/sqlite_storage/_extras.py, tests/server/services/storage/*
_SUPPORTED_CITATION_KINDS centralizes allowed kinds; get_playbook_application_stats and get_citations_by_session_ids filter by supported kinds; tests validate explicit user_playbook/agent_playbook handling.
Reflection service citation key normalization
reflexio/server/services/reflection/service.py, tests/server/services/reflection/*
New _reflection_target_kind/_reflection_citation_key helpers normalize citation keys used in horizon lookup, cited-row resolution, deduplication, and horizon filtering; tests verify canonicalization of legacy vs explicit playbook kinds.
Openclaw plugin wire citation kind mapping
reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py, reflexio/integrations/openclaw/plugin/tests/test_state.py
_VALID_CITATION_KINDS expanded; _to_wire_citations remaps "playbook" kind to a specific wire kind based on source_kind before validation.

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

Sequence Diagram(s)

sequenceDiagram
    participant ReflectionServiceRun as ReflectionService.run
    participant CollectCitations as _collect_citations
    participant KeyHelper as _reflection_citation_key
    participant FilterByHorizon as _filter_citations_by_horizon

    ReflectionServiceRun->>CollectCitations: gather assistant citations from window
    CollectCitations->>KeyHelper: normalize (kind, real_id)
    KeyHelper-->>CollectCitations: ("playbook"|"profile", real_id)
    CollectCitations-->>ReflectionServiceRun: deduplicated citations
    ReflectionServiceRun->>FilterByHorizon: apply horizon eligibility
    FilterByHorizon->>KeyHelper: build citation_by_key via setdefault
    FilterByHorizon-->>ReflectionServiceRun: eligible citations (earliest per key)
Loading

Possibly related PRs

  • ReflexioAI/reflexio#39: Both PRs modify the Citation model's kind field semantics in reflexio/models/api_schema/domain/entities.py.
  • ReflexioAI/reflexio#64: Both PRs touch get_playbook_application_stats/PlaybookApplicationStat.kind, with this PR extending that logic to support user_playbook and agent_playbook.
  • ReflexioAI/reflexio#168: Both PRs modify SessionCitation.kind in reflexio/models/api_schema/internal_schema.py.
🚥 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 summarizes the main change: adding explicit playbook provenance contracts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/tau-leaderboard-investor-report

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 (3)
reflexio/server/services/reflection/service.py (1)

170-174: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant None-filtering on horizon_by_key.

eligible is already built from _filter_citations_by_horizon, which only includes citations with a non-None _reflection_citation_key. The if (key := ...) is not None guard here is therefore dead code in practice, though harmless.

🤖 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/server/services/reflection/service.py` around lines 170 - 174, The
horizon_by_key comprehension in reflection.service._filter_citations_by_horizon
is redundantly filtering out None keys even though eligible already contains
only citations with a valid _reflection_citation_key. Remove the unnecessary if
(key := ...) is not None guard and keep the key assignment in the dict
comprehension so the existing eligible set is mapped directly by
_reflection_citation_key.
reflexio/models/api_schema/domain/entities.py (1)

410-467: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Complex but internally consistent backfill validator.

Traced all branches of backfill_legacy_target_fields: legacy-only (agent_playbook_id set), explicit target_kind="user_playbook", explicit target_kind="agent_playbook" with/without agent_playbook_id, and mismatch detection all resolve correctly and match the test expectations in test_storage_contract_retrieval_logs.py. No functional issue found, though the six-branch validator is dense — consider extracting the "agent_playbook" reconciliation branch into a helper for readability if this grows further.

🤖 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/models/api_schema/domain/entities.py` around lines 410 - 467, The
backfill logic in backfill_legacy_target_fields is correct but the
agent_playbook reconciliation path is too dense. Refactor the explicit
agent_playbook branch into a small helper on PlaybookRetrievalLogItem (or a
nearby private function) and keep the model_validator focused on dispatching
between legacy, user_playbook, and agent_playbook cases while preserving the
same validation behavior and error messages.
reflexio/server/services/storage/sqlite_storage/_extras.py (1)

28-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider importing the shared CitationKind instead of duplicating it locally.

_CitationKind/_SUPPORTED_CITATION_KINDS re-declare the same literal values as reflexio.models.api_schema.domain.CitationKind (used elsewhere in this same PR). This duplication is a drift risk — this PR itself required manually updating two locations to add user_playbook/agent_playbook; a future expansion could easily miss this file and silently drop valid citations from the stats/filter queries.

♻️ Suggested consolidation
-type _CitationKind = Literal["playbook", "profile", "user_playbook", "agent_playbook"]
-
-_SUPPORTED_CITATION_KINDS: tuple[_CitationKind, ...] = (
-    "playbook",
-    "profile",
-    "user_playbook",
-    "agent_playbook",
-)
+from reflexio.models.api_schema.domain import CitationKind
+
+_SUPPORTED_CITATION_KINDS: tuple[CitationKind, ...] = (
+    "playbook",
+    "profile",
+    "user_playbook",
+    "agent_playbook",
+)

If there's a deliberate reason to keep the storage layer decoupled from reflexio.models.api_schema.domain, please confirm and disregard.

🤖 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/server/services/storage/sqlite_storage/_extras.py` around lines 28 -
35, The storage layer is duplicating the citation kind literals instead of
reusing the shared domain type, which can drift from
`reflexio.models.api_schema.domain.CitationKind`. Update `_extras.py` to import
and use `CitationKind` directly where `_CitationKind` and
`_SUPPORTED_CITATION_KINDS` are defined, and ensure the tuple of supported kinds
stays derived from the shared source used by the rest of the PR. Keep the
relevant storage helpers aligned so future additions only need to be made in one
place.
🤖 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/models/api_schema/domain/entities.py`:
- Around line 410-467: The backfill logic in backfill_legacy_target_fields is
correct but the agent_playbook reconciliation path is too dense. Refactor the
explicit agent_playbook branch into a small helper on PlaybookRetrievalLogItem
(or a nearby private function) and keep the model_validator focused on
dispatching between legacy, user_playbook, and agent_playbook cases while
preserving the same validation behavior and error messages.

In `@reflexio/server/services/reflection/service.py`:
- Around line 170-174: The horizon_by_key comprehension in
reflection.service._filter_citations_by_horizon is redundantly filtering out
None keys even though eligible already contains only citations with a valid
_reflection_citation_key. Remove the unnecessary if (key := ...) is not None
guard and keep the key assignment in the dict comprehension so the existing
eligible set is mapped directly by _reflection_citation_key.

In `@reflexio/server/services/storage/sqlite_storage/_extras.py`:
- Around line 28-35: The storage layer is duplicating the citation kind literals
instead of reusing the shared domain type, which can drift from
`reflexio.models.api_schema.domain.CitationKind`. Update `_extras.py` to import
and use `CitationKind` directly where `_CitationKind` and
`_SUPPORTED_CITATION_KINDS` are defined, and ensure the tuple of supported kinds
stays derived from the shared source used by the rest of the PR. Keep the
relevant storage helpers aligned so future additions only need to be made in one
place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d0859915-0f41-4096-a2a7-8eaa64c878a8

📥 Commits

Reviewing files that changed from the base of the PR and between 3e51bd2 and 8037a07.

📒 Files selected for processing (14)
  • reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py
  • reflexio/integrations/openclaw/plugin/tests/test_state.py
  • reflexio/models/api_schema/domain/entities.py
  • reflexio/models/api_schema/eval_overview_schema.py
  • reflexio/models/api_schema/internal_schema.py
  • reflexio/models/api_schema/retriever_schema.py
  • reflexio/server/services/evaluation_overview/components/rule_attribution.py
  • reflexio/server/services/reflection/service.py
  • reflexio/server/services/storage/sqlite_storage/_extras.py
  • reflexio/server/services/storage/storage_base/_retrieval_log.py
  • tests/server/services/reflection/test_post_horizon_filter.py
  • tests/server/services/reflection/test_reflection_service.py
  • tests/server/services/storage/test_sqlite_storage_bc_extras.py
  • tests/server/services/storage/test_storage_contract_extras.py

@guangyu-reflexio guangyu-reflexio merged commit f245066 into main Jul 7, 2026
1 check passed
@guangyu-reflexio guangyu-reflexio deleted the feature/tau-leaderboard-investor-report branch July 7, 2026 11:14
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