Skip to content

Persist observed model provenance on learning lineage#357

Open
yilu331 wants to merge 1 commit into
mainfrom
codex/model-provenance-batch1
Open

Persist observed model provenance on learning lineage#357
yilu331 wants to merge 1 commit into
mainfrom
codex/model-provenance-batch1

Conversation

@yilu331

@yilu331 yilu331 commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Persistence-only change. Capture the observed model_name and provider that actually served content-shaping LLM calls, and store them on new lineage events. This batch intentionally does not expand the public API surface.

Developers who need the fields can query storage/lineage_event directly. A public read path can be added later when product need is clear (e.g. claude-smart local DB reader).

Before

Learning lineage recorded what changed and which component changed it, but not which model route actually shaped a persisted profile or playbook.

Changed

  • Capture only actual served model_name and provider from accepted completions
  • Refuse request-side LiteLLM routing metadata as a stand-in for the served model
  • Carry attribution through extraction, consolidation, aggregation, resumable output, parse repair, and transport-failure salvage
  • Preserve ladder-wide first-parsed provenance (including final-rung fail-closed cap saturation)
  • Always emit create lineage when a caller supplies context; model fields may be null
  • Persist on new SQLite lineage_event rows only — no historical backfill
  • CLI ModelResponse.model stays the requested route string; provenance uses only reflexio_served_model for claude-code routes
  • Drop write-only repair-error fields and dead pre-inits from review cleanup

Explicit non-goals (this PR)

  • No model_provenance field on LearningProvenanceViewResponse / POST /api/get_learning_provenance
  • No new endpoint, client method, or ModelProvenanceView public schema
  • No generic entity field, multi-entity lineage query, requested_model, or credential/account label
  • No mismatch alerting, dashboards, or billing-account identification

After

Situation Storage (lineage_event) Public learning-provenance API
Observed MiniMax route model_name=MiniMax-M3, provider=minimax Unchanged (no model fields)
Observed Claude route model_name=…, provider=claude… Unchanged
No served metadata null / null on the create event Unchanged
Historical rows Untouched Unchanged

Data flow

flowchart LR
  R["Accepted completion"] --> C["CompletionResult / ModelProvenance"]
  C --> G["Generation op + LineageContext"]
  G --> E["lineage_event.model_name / provider"]
  E --> D["Developer queries DB/storage if needed"]
  R -->|"no served metadata"| N["null model fields on create event"]
  H["Historical lineage"] --> U["Unchanged; no backfill"]
Loading

Verification

  • Ruff + focused unit/integration suites (claude-code provider, litellm client, playbook consolidator, lineage persistence, learning-provenance route)
  • 383 passed / 1 skipped on the focused suite after Claude review fixes
  • Outside-in: SQLite write carries model fields; POST /api/get_learning_provenance response keys exclude model_provenance
  • Review cleanup: requested-route laundering blocked; dead repair fields removed; aggregator fails loud on provenance list drift

Follow-ups (out of scope)

  • Public read API when product need is proven
  • claude-smart local DB reader for model provenance
  • Paired enterprise storage migration
  • Mismatch alerting / dashboards / backfill

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Model/provider provenance is captured from LiteLLM and Claude Code responses, carried through tool loops, extraction, and generation services, persisted in SQLite lineage events, and returned by the learning provenance API. New lineage context and response schemas support optional provenance metadata.

Changes

Model provenance and lineage

Layer / File(s) Summary
LLM provenance capture
reflexio/server/llm/..., reflexio/server/llm/providers/...
Adds typed completion provenance, routing metadata extraction, Claude Code served-model metadata, repair propagation, and tool-loop result attribution.
Durable extraction propagation
reflexio/server/services/extraction/..., reflexio/server/services/base_generation/...
Stores provenance in versioned committed-output envelopes and carries it through resume and finalization flows.
Generation and persistence wiring
reflexio/server/services/profile/..., reflexio/server/services/playbook/...
Builds lineage contexts from extractor, consolidator, and aggregator provenance and passes them into storage operations.
SQLite lineage storage
reflexio/server/services/storage/...
Adds nullable model_name and provider columns, persists them on lineage events, supports lineage-aware profile/playbook writes, and updates aggregate-event contracts.
Retrieval API and validation
reflexio/models/api_schema/..., reflexio/server/routes/provenance.py, tests/..., reflexio/server/README.md
Adds model provenance response views, filters content-shaping lineage events, documents the response, and adds unit/integration coverage.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: guangyu-reflexio, yyiilluu

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.27% 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
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: persisting observed model provenance in learning lineage.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/model-provenance-batch1

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.

Actionable comments posted: 5

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

Inline comments:
In `@reflexio/server/llm/_litellm_text_generation.py`:
- Around line 792-827: Update _configured_credential_label so the
custom_endpoint label is selected only when confirmed served-route metadata
identifies the custom endpoint, not merely when params["api_base"] matches it.
Preserve fallback attribution using the resolved provider/model route and ensure
network fallbacks do not inherit the primary custom endpoint credential label.
- Around line 1015-1016: Preserve the provenance computed by _call_and_parse
when parsing raises StructuredOutputParseError by attaching it to the exception
or converting the failure into a provenance-bearing _StructuredAttempt. Update
the first_error and exhausted-repair flows at the referenced call sites so
initial_provenance and final-attempt provenance remain populated even when every
parse attempt fails.

In `@reflexio/server/services/extraction/resumable_agent.py`:
- Around line 94-107: Update decode_committed_output so recognized version 1
envelopes never return committed_output as the payload when output is invalid or
model_provenance is missing. Extract and return the envelope’s output when
available, or use the appropriate existing error/fallback behavior when it is
missing or invalid, while preserving the legacy raw-payload path for
non-version-1 inputs.

In `@reflexio/server/services/playbook/components/consolidator.py`:
- Around line 751-755: Update the StructuredOutputRepairError handling around
first_parsed_output so the fallback is returned whenever that output exists,
even when provenance is absent. Track and assign the provenance belonging to the
attempt that produced first_parsed_output, rather than unconditionally using
initial_provenance; preserve the existing re-raise behavior when no parsed
output is available.

In `@reflexio/server/services/profile/components/consolidator.py`:
- Around line 612-617: Update the duplicate-group consolidation flow around
group_existing_indices and the merged_profile lineage mapping to track existing
indices already claimed by earlier groups. Before creating a merged profile and
recording lineage, skip or reject any group whose valid existing indices overlap
previously claimed indices; otherwise preserve the existing source filtering and
mapping behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 19b82651-5c00-4af6-ba6c-9dbad52405ec

📥 Commits

Reviewing files that changed from the base of the PR and between c986eac and fbda9e9.

📒 Files selected for processing (67)
  • reflexio/models/api_schema/domain/entities.py
  • reflexio/models/api_schema/retriever_schema.py
  • reflexio/models/api_schema/ui/converters.py
  • reflexio/models/api_schema/ui/entities.py
  • reflexio/models/config_schema.py
  • reflexio/server/README.md
  • reflexio/server/llm/__init__.py
  • reflexio/server/llm/_litellm_text_generation.py
  • reflexio/server/llm/_litellm_types.py
  • reflexio/server/llm/litellm_client.py
  • reflexio/server/llm/providers/claude_code_provider.py
  • reflexio/server/llm/providers/claude_code_stream_parser.py
  • reflexio/server/llm/tools.py
  • reflexio/server/routes/playbooks.py
  • reflexio/server/routes/profiles.py
  • reflexio/server/routes/provenance.py
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/base_generation_service.py
  • reflexio/server/services/deferred_learning_plan.py
  • reflexio/server/services/extraction/outcome.py
  • reflexio/server/services/extraction/resumable_agent.py
  • reflexio/server/services/extraction/resume_worker.py
  • reflexio/server/services/model_provenance.py
  • reflexio/server/services/playbook/components/aggregator.py
  • reflexio/server/services/playbook/components/consolidator.py
  • reflexio/server/services/playbook/components/extractor.py
  • reflexio/server/services/playbook/playbook_edit_apply.py
  • reflexio/server/services/playbook/service.py
  • reflexio/server/services/profile/components/consolidator.py
  • reflexio/server/services/profile/components/extractor.py
  • reflexio/server/services/profile/service.py
  • reflexio/server/services/reflection/components/extractor.py
  • reflexio/server/services/reflection/service.py
  • reflexio/server/services/storage/sqlite_storage/_base.py
  • reflexio/server/services/storage/sqlite_storage/_lineage.py
  • reflexio/server/services/storage/sqlite_storage/playbook/_agent.py
  • reflexio/server/services/storage/sqlite_storage/playbook/_user.py
  • reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py
  • reflexio/server/services/storage/storage_base/_lineage.py
  • reflexio/server/services/storage/storage_base/playbook/_agent.py
  • reflexio/server/services/storage/storage_base/playbook/_user.py
  • reflexio/server/services/storage/storage_base/profiles/_profile_store.py
  • tests/models/test_lineage_models.py
  • tests/models/test_llm_credential_labels.py
  • tests/models/test_view_models.py
  • tests/server/llm/test_claude_code_provider.py
  • tests/server/llm/test_claude_code_stream_parser.py
  • tests/server/llm/test_litellm_client_surface.py
  • tests/server/llm/test_litellm_client_tool_calls.py
  • tests/server/llm/test_litellm_client_unit.py
  • tests/server/llm/test_tools.py
  • tests/server/services/extraction/test_model_provenance_envelope.py
  • tests/server/services/extraction/test_resumable_agent.py
  • tests/server/services/playbook/test_cluster_change_detection.py
  • tests/server/services/playbook/test_playbook_aggregator.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • tests/server/services/playbook/test_playbook_generation_service.py
  • tests/server/services/profile/test_profile_generation_service.py
  • tests/server/services/reflection/test_reflection_service.py
  • tests/server/services/storage/sqlite_storage/test_create_lineage_provenance_integration.py
  • tests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.py
  • tests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.py
  • tests/server/services/storage/test_lineage_contract.py
  • tests/server/services/storage/test_playbook_base_aggregate_emit.py
  • tests/server/services/storage/test_sqlite_lineage_event_integration.py
  • tests/server/test_app_route_inventory.py
  • tests/server/test_lineage_events_api.py

Comment thread reflexio/server/llm/_litellm_text_generation.py Outdated
Comment thread reflexio/server/llm/_litellm_text_generation.py Outdated
Comment thread reflexio/server/services/extraction/resumable_agent.py Outdated
Comment thread reflexio/server/services/playbook/components/consolidator.py Outdated
Comment thread reflexio/server/services/profile/components/consolidator.py

@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 (1)
reflexio/server/services/storage/storage_base/_lineage.py (1)

84-88: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use direct dictionary access instead of setdefault.

Since result is already pre-populated with all requested entity_ids as keys on line 84, and the get_lineage_events query guarantees that returned events belong to these IDs, you can use direct dictionary access. This is cleaner and provides a fail-fast mechanism (a KeyError will be raised) if a faulty storage backend implementation ever returns unrequested entity IDs.

♻️ Proposed refactor
-        result = {entity_id: [] for entity_id in entity_ids}
-        for event in events:
-            if event.op not in CONTENT_SHAPING_LINEAGE_OPS:
-                continue
-            result.setdefault(event.entity_id, []).append(event)
+        result = {entity_id: [] for entity_id in entity_ids}
+        for event in events:
+            if event.op in CONTENT_SHAPING_LINEAGE_OPS:
+                result[event.entity_id].append(event)
🤖 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/storage_base/_lineage.py` around lines 84 -
88, In the event aggregation loop, replace setdefault usage in the lineage
result construction with direct access to the pre-populated result mapping,
preserving the existing append behavior and allowing unexpected entity IDs to
fail with KeyError.
🤖 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/server/services/storage/storage_base/_lineage.py`:
- Around line 84-88: In the event aggregation loop, replace setdefault usage in
the lineage result construction with direct access to the pre-populated result
mapping, preserving the existing append behavior and allowing unexpected entity
IDs to fail with KeyError.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f3357d0-fa35-465b-bb05-9741a3b6c483

📥 Commits

Reviewing files that changed from the base of the PR and between fbda9e9 and b40d650.

📒 Files selected for processing (7)
  • reflexio/server/routes/provenance.py
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/base_generation_service.py
  • reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py
  • reflexio/server/services/storage/storage_base/_lineage.py
  • tests/server/services/storage/test_lineage_contract.py
  • tests/server/test_lineage_events_api.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • reflexio/server/services/base_generation_service.py
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py

@yilu331

yilu331 commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator Author

Review — model provenance in learning lineage

Read the full diff. The lineage/storage/schema plumbing is sound and well-tested. One correctness regression and a few simplification opportunities that speak to the size of this change.

1. Correctness — consolidator salvage path narrowed (high)

reflexio/server/services/playbook/components/consolidator.py (~L749-756):

except StructuredOutputRepairError as exc:
    if first_parsed_output is not None and exc.initial_provenance is not None:
        self.model_provenance = exc.initial_provenance
        return first_parsed_output
    raise
except LiteLLMClientError:
    raise

This changes error behavior in two ways vs. the previous except (StructuredOutputRepairError, LiteLLMClientError): if first_parsed_output is not None: return first_parsed_output:

  • LiteLLMClientError no longer salvages. Previously, if an early turn produced a usable first_parsed_output and a later turn hit a client error (post-retry network/timeout), consolidation returned the salvaged output. It now always re-raises, failing the whole consolidation.
  • Repair salvage is gated on exc.initial_provenance is not None. initial_provenance is derived only from the first attempt (first_attempt.provenance if first_attempt and first_attempt.parsed_output is not None else None). When the first attempt was unparseable (StructuredOutputParseError → _attempt_repair(exc, None), so first_attempt is None) but a later repair turn produced a valid-but-rejected output, first_parsed_output is set yet initial_provenance is None → the branch raises instead of salvaging.

Net: recoverable consolidations now fail, and the salvage decision is coupled to provenance capture, which is an unrelated concern. Suggest keeping the salvage unconditional on first_parsed_output, setting self.model_provenance = exc.initial_provenance opportunistically (without gating the return on it), and restoring the LiteLLMClientError salvage branch.

2. Simplification — two parallel provenance-carrying mechanisms

Provenance is threaded via both a wrapper type (CompletionResult[T]) and a .provenance attribute on existing response types (ToolCallingChatResponse, _StructuredAttempt, ToolLoopResult). _unwrap_completion_result even reads both (isinstance(...CompletionResult) else getattr(value, "provenance", None)). Picking one representation would remove a chunk of the return-type unions (str | BaseModel | ToolCallingChatResponse | CompletionResult[...]) now propagated through generate_response/generate_chat_response/_make_request and every caller.

Relatedly, the unwrap block

if isinstance(response, CompletionResult):
    self.model_provenance = response.provenance
    response = response.value

is copy-pasted in the profile consolidator, playbook consolidator, reflection extractor, and aggregator. tools.py already has _unwrap_completion_result — exporting/reusing one helper would collapse the four copies.

3. Simplification/robustness — id()-keyed provenance maps

profile/service.py and playbook/service.py build {id(x) for x in ...} sets and branch on id(obj) in extracted_objects; the aggregator stashes self._provenance_by_playbook_identity[id(playbook)] in one method and pops it in another. This works only because the objects stay alive through the flow, and object-identity routing is easy to break in later refactors. Consider attaching provenance (or an actor tag) to the object at construction, or pairing (object, provenance) in a list, rather than keying on id().

4. Minor

  • _emit_fallback_observability computes (provenance or self._build_model_provenance(...)).model_name before the if hidden.get("reflexio_provider") == "claude-code": return early exit — move the early return to the top to skip the wasted build.
  • save_user_playbooks always emits op="create" regardless of the passed context's op_kind; an assert (or documented precondition) that op_kind == "create" would prevent silent misuse.

Nothing else blocking — the SQLite migration, idempotency-keyed create events, and the "no create event on upsert of an existing row" guard all look correct.

@yilu331
yilu331 force-pushed the codex/model-provenance-batch1 branch from 746b366 to 25b61dc Compare July 18, 2026 04:37

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
reflexio/server/services/playbook/components/consolidator.py (1)

751-761: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Combine redundant exception handlers.

StructuredOutputRepairError is a subclass of LiteLLMClientError and both blocks execute identical fallback logic. You can safely remove the StructuredOutputRepairError block to simplify the code.

♻️ Proposed refactor
-        except StructuredOutputRepairError as exc:
-            if first_parsed_output is not None:
-                self.model_provenance = exc.first_parsed_provenance
-                return first_parsed_output
-            raise
         except LiteLLMClientError as exc:
             if first_parsed_output is not None:
                 self.model_provenance = exc.first_parsed_provenance
                 return first_parsed_output
             raise
🤖 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/playbook/components/consolidator.py` around lines
751 - 761, Remove the redundant StructuredOutputRepairError handler and retain
the existing fallback logic in the LiteLLMClientError handler. Ensure
StructuredOutputRepairError continues to be caught through its
LiteLLMClientError superclass, preserving model_provenance assignment,
first_parsed_output return, and re-raising when no parsed output exists.
🤖 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.

Inline comments:
In `@reflexio/server/llm/providers/claude_code_provider.py`:
- Line 646: The model response builders must always provide a string model,
falling back to the requested model when served_model is absent. In
reflexio/server/llm/providers/claude_code_provider.py:646-646, update
_build_model_response to use served_model or model; at :811-862, restore the
model: str parameter in _build_model_response_with_tool_call and apply the same
fallback; at :1051-1056, pass model=model to that helper invocation.

---

Nitpick comments:
In `@reflexio/server/services/playbook/components/consolidator.py`:
- Around line 751-761: Remove the redundant StructuredOutputRepairError handler
and retain the existing fallback logic in the LiteLLMClientError handler. Ensure
StructuredOutputRepairError continues to be caught through its
LiteLLMClientError superclass, preserving model_provenance assignment,
first_parsed_output return, and re-raising when no parsed output exists.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6d5cf08b-d184-4f4b-93a1-5af750478b47

📥 Commits

Reviewing files that changed from the base of the PR and between 746b366 and 25b61dc.

📒 Files selected for processing (69)
  • reflexio/models/api_schema/domain/entities.py
  • reflexio/models/api_schema/retriever_schema.py
  • reflexio/models/api_schema/ui/converters.py
  • reflexio/models/api_schema/ui/entities.py
  • reflexio/models/config_schema.py
  • reflexio/server/README.md
  • reflexio/server/llm/__init__.py
  • reflexio/server/llm/_litellm_text_generation.py
  • reflexio/server/llm/_litellm_types.py
  • reflexio/server/llm/litellm_client.py
  • reflexio/server/llm/providers/claude_code_provider.py
  • reflexio/server/llm/providers/claude_code_stream_parser.py
  • reflexio/server/llm/tools.py
  • reflexio/server/routes/playbooks.py
  • reflexio/server/routes/profiles.py
  • reflexio/server/routes/provenance.py
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/base_generation_service.py
  • reflexio/server/services/deferred_learning_plan.py
  • reflexio/server/services/extraction/outcome.py
  • reflexio/server/services/extraction/resumable_agent.py
  • reflexio/server/services/extraction/resume_worker.py
  • reflexio/server/services/model_provenance.py
  • reflexio/server/services/playbook/components/aggregator.py
  • reflexio/server/services/playbook/components/consolidator.py
  • reflexio/server/services/playbook/components/extractor.py
  • reflexio/server/services/playbook/playbook_edit_apply.py
  • reflexio/server/services/playbook/service.py
  • reflexio/server/services/profile/components/consolidator.py
  • reflexio/server/services/profile/components/extractor.py
  • reflexio/server/services/profile/service.py
  • reflexio/server/services/reflection/components/extractor.py
  • reflexio/server/services/reflection/service.py
  • reflexio/server/services/storage/sqlite_storage/_base.py
  • reflexio/server/services/storage/sqlite_storage/_lineage.py
  • reflexio/server/services/storage/sqlite_storage/playbook/_agent.py
  • reflexio/server/services/storage/sqlite_storage/playbook/_user.py
  • reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py
  • reflexio/server/services/storage/storage_base/__init__.py
  • reflexio/server/services/storage/storage_base/_lineage.py
  • reflexio/server/services/storage/storage_base/playbook/_agent.py
  • reflexio/server/services/storage/storage_base/playbook/_user.py
  • reflexio/server/services/storage/storage_base/profiles/_profile_store.py
  • tests/conftest.py
  • tests/models/test_lineage_models.py
  • tests/models/test_llm_credential_labels.py
  • tests/models/test_view_models.py
  • tests/server/llm/test_claude_code_provider.py
  • tests/server/llm/test_claude_code_stream_parser.py
  • tests/server/llm/test_litellm_client_surface.py
  • tests/server/llm/test_litellm_client_tool_calls.py
  • tests/server/llm/test_litellm_client_unit.py
  • tests/server/llm/test_tools.py
  • tests/server/services/extraction/test_model_provenance_envelope.py
  • tests/server/services/extraction/test_resumable_agent.py
  • tests/server/services/playbook/test_cluster_change_detection.py
  • tests/server/services/playbook/test_playbook_aggregator.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • tests/server/services/playbook/test_playbook_generation_service.py
  • tests/server/services/profile/test_profile_generation_service.py
  • tests/server/services/reflection/test_reflection_service.py
  • tests/server/services/storage/sqlite_storage/test_create_lineage_provenance_integration.py
  • tests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.py
  • tests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.py
  • tests/server/services/storage/test_lineage_contract.py
  • tests/server/services/storage/test_playbook_base_aggregate_emit.py
  • tests/server/services/storage/test_sqlite_lineage_event_integration.py
  • tests/server/test_app_route_inventory.py
  • tests/server/test_lineage_events_api.py
🚧 Files skipped from review as they are similar to previous changes (53)
  • tests/models/test_llm_credential_labels.py
  • reflexio/server/llm/init.py
  • reflexio/server/services/model_provenance.py
  • reflexio/server/services/storage/storage_base/playbook/_user.py
  • reflexio/models/api_schema/domain/entities.py
  • reflexio/server/services/storage/storage_base/init.py
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/playbook/playbook_edit_apply.py
  • reflexio/server/services/base_generation_service.py
  • reflexio/server/services/storage/storage_base/profiles/_profile_store.py
  • tests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.py
  • tests/server/services/playbook/test_playbook_generation_service.py
  • tests/server/llm/test_litellm_client_tool_calls.py
  • reflexio/server/services/reflection/components/extractor.py
  • reflexio/server/routes/playbooks.py
  • tests/models/test_lineage_models.py
  • tests/server/llm/test_litellm_client_surface.py
  • reflexio/server/llm/litellm_client.py
  • reflexio/models/config_schema.py
  • reflexio/server/routes/profiles.py
  • reflexio/server/services/playbook/components/aggregator.py
  • tests/server/services/storage/sqlite_storage/test_create_lineage_provenance_integration.py
  • reflexio/server/services/reflection/service.py
  • tests/server/services/reflection/test_reflection_service.py
  • reflexio/server/services/storage/storage_base/playbook/_agent.py
  • tests/server/llm/test_tools.py
  • reflexio/server/services/extraction/outcome.py
  • reflexio/server/README.md
  • reflexio/server/services/storage/storage_base/_lineage.py
  • tests/server/services/playbook/test_playbook_aggregator.py
  • tests/server/services/extraction/test_model_provenance_envelope.py
  • reflexio/server/services/profile/components/consolidator.py
  • reflexio/server/services/playbook/components/extractor.py
  • reflexio/server/services/storage/sqlite_storage/playbook/_user.py
  • tests/server/services/storage/test_playbook_base_aggregate_emit.py
  • reflexio/server/services/profile/components/extractor.py
  • reflexio/server/services/deferred_learning_plan.py
  • tests/server/services/extraction/test_resumable_agent.py
  • reflexio/server/services/storage/sqlite_storage/playbook/_agent.py
  • tests/server/llm/test_claude_code_stream_parser.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • tests/server/services/playbook/test_cluster_change_detection.py
  • reflexio/server/llm/tools.py
  • reflexio/server/services/storage/sqlite_storage/_lineage.py
  • tests/server/services/storage/test_lineage_contract.py
  • tests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.py
  • reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py
  • reflexio/server/llm/providers/claude_code_stream_parser.py
  • reflexio/server/services/playbook/service.py
  • reflexio/server/services/profile/service.py
  • reflexio/server/llm/_litellm_types.py
  • reflexio/server/services/extraction/resume_worker.py
  • reflexio/server/llm/_litellm_text_generation.py

Comment thread reflexio/server/llm/providers/claude_code_provider.py Outdated
@yilu331
yilu331 force-pushed the codex/model-provenance-batch1 branch 4 times, most recently from 6fcbad5 to fbe181e Compare July 18, 2026 19:00
@yyiilluu
yyiilluu force-pushed the codex/model-provenance-batch1 branch 2 times, most recently from e79b3e2 to 119c13e Compare July 21, 2026 00:34
@yyiilluu

Copy link
Copy Markdown
Contributor

Addressed the review findings in the rebased branch (latest: 119c13e):

  • restored unconditional salvage of the first parsed consolidation output, with provenance assigned opportunistically
  • kept CompletionResult[T] as the single opt-in provenance carrier at the LLM completion boundary; removed provenance from ToolCallingChatResponse and the fallback getattr unwrap path
  • removed all id()-keyed provenance routing in profile generation, playbook generation, and aggregation; attribution is now positional/explicit
  • moved the confirmed claude-code early return ahead of fallback provenance construction
  • validate that create-event lineage contexts use op_kind="create"
  • preserved compatibility with enterprise/other storage backends through additive lineage-aware write methods instead of widening their existing method signatures
  • added event_id, actor, and request_id to each API model-provenance item

Verification details are refreshed in the PR body.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

@yyiilluu I’ll review the rebased changes, including the restored salvage behavior, provenance-carrier simplification, positional attribution, and storage-backend compatibility.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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/server/services/storage/storage_base/playbook/_user.py (1)

42-59: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider validating lineage_contexts here too, even though this fallback doesn't persist it.

SQLite's override raises ValueError for length mismatches and non-"create" op_kind; this default silently swallows the same misuse via del lineage_contexts. Backends that haven't overridden this method would mask a caller bug that only surfaces on SQLite.

🤖 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/storage_base/playbook/_user.py` around lines
42 - 59, Validate lineage_contexts in save_user_playbooks_with_lineage before
falling back to save_user_playbooks, matching SQLite’s ValueError behavior for
length mismatches and any op_kind other than "create"; retain the existing
fallback persistence after validation.
reflexio/server/services/profile/components/extractor.py (1)

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

Add type annotation for consistency.

Sibling attributes on the same lines are explicitly typed (_last_resumable_run_id: str | None = None, _last_resumable_token_totals: RunTokenTotals | None = None), but _last_model_provenance is left untyped.

♻️ Suggested annotation
-        self._last_model_provenance = None
+        self._last_model_provenance: ModelProvenance | None = None
🤖 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/profile/components/extractor.py` at line 102, Add an
explicit optional type annotation to _last_model_provenance in the extractor
initialization, matching the annotations used by _last_resumable_run_id and
_last_resumable_token_totals; preserve its existing None initialization.
🤖 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/server/services/profile/components/extractor.py`:
- Line 102: Add an explicit optional type annotation to _last_model_provenance
in the extractor initialization, matching the annotations used by
_last_resumable_run_id and _last_resumable_token_totals; preserve its existing
None initialization.

In `@reflexio/server/services/storage/storage_base/playbook/_user.py`:
- Around line 42-59: Validate lineage_contexts in
save_user_playbooks_with_lineage before falling back to save_user_playbooks,
matching SQLite’s ValueError behavior for length mismatches and any op_kind
other than "create"; retain the existing fallback persistence after validation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f6337db0-3789-4b12-928a-b393b9d758a5

📥 Commits

Reviewing files that changed from the base of the PR and between 25b61dc and 119c13e.

📒 Files selected for processing (57)
  • reflexio/models/api_schema/domain/entities.py
  • reflexio/models/api_schema/retriever_schema.py
  • reflexio/server/README.md
  • reflexio/server/llm/_litellm_text_generation.py
  • reflexio/server/llm/_litellm_types.py
  • reflexio/server/llm/providers/claude_code_provider.py
  • reflexio/server/llm/providers/claude_code_stream_parser.py
  • reflexio/server/llm/tools.py
  • reflexio/server/routes/provenance.py
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/base_generation_service.py
  • reflexio/server/services/deferred_learning_plan.py
  • reflexio/server/services/extraction/outcome.py
  • reflexio/server/services/extraction/resumable_agent.py
  • reflexio/server/services/extraction/resume_worker.py
  • reflexio/server/services/model_provenance.py
  • reflexio/server/services/playbook/components/aggregator.py
  • reflexio/server/services/playbook/components/consolidator.py
  • reflexio/server/services/playbook/components/extractor.py
  • reflexio/server/services/playbook/playbook_edit_apply.py
  • reflexio/server/services/playbook/service.py
  • reflexio/server/services/profile/components/consolidator.py
  • reflexio/server/services/profile/components/extractor.py
  • reflexio/server/services/profile/service.py
  • reflexio/server/services/storage/sqlite_storage/_base.py
  • reflexio/server/services/storage/sqlite_storage/_lineage.py
  • reflexio/server/services/storage/sqlite_storage/playbook/_agent.py
  • reflexio/server/services/storage/sqlite_storage/playbook/_user.py
  • reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py
  • reflexio/server/services/storage/storage_base/__init__.py
  • reflexio/server/services/storage/storage_base/playbook/_agent.py
  • reflexio/server/services/storage/storage_base/playbook/_user.py
  • reflexio/server/services/storage/storage_base/profiles/_profile_store.py
  • tests/conftest.py
  • tests/models/test_lineage_models.py
  • tests/server/llm/test_claude_code_provider.py
  • tests/server/llm/test_claude_code_stream_parser.py
  • tests/server/llm/test_litellm_client_surface.py
  • tests/server/llm/test_litellm_client_tool_calls.py
  • tests/server/llm/test_litellm_client_unit.py
  • tests/server/llm/test_tools.py
  • tests/server/services/extraction/test_model_provenance_envelope.py
  • tests/server/services/extraction/test_resumable_agent.py
  • tests/server/services/playbook/test_cluster_change_detection.py
  • tests/server/services/playbook/test_playbook_aggregator.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • tests/server/services/playbook/test_playbook_generation_service.py
  • tests/server/services/playbook/test_playbook_generation_service_integration.py
  • tests/server/services/profile/test_profile_generation_service.py
  • tests/server/services/storage/sqlite_storage/test_create_lineage_provenance_integration.py
  • tests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.py
  • tests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.py
  • tests/server/services/storage/test_lineage_write_capability.py
  • tests/server/services/storage/test_playbook_base_aggregate_emit.py
  • tests/server/services/storage/test_sqlite_lineage_event_integration.py
  • tests/server/services/test_model_provenance.py
  • tests/server/test_learning_provenance_api.py
🚧 Files skipped from review as they are similar to previous changes (29)
  • tests/server/services/storage/test_sqlite_lineage_event_integration.py
  • reflexio/models/api_schema/domain/entities.py
  • reflexio/server/services/storage/storage_base/init.py
  • reflexio/server/services/playbook/playbook_edit_apply.py
  • reflexio/server/services/model_provenance.py
  • reflexio/server/services/base_generation_service.py
  • tests/server/llm/test_claude_code_stream_parser.py
  • tests/models/test_lineage_models.py
  • tests/server/services/storage/test_playbook_base_aggregate_emit.py
  • tests/server/services/extraction/test_resumable_agent.py
  • reflexio/server/services/extraction/outcome.py
  • reflexio/server/services/playbook/components/extractor.py
  • tests/conftest.py
  • reflexio/server/services/storage/sqlite_storage/playbook/_agent.py
  • tests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.py
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/extraction/resumable_agent.py
  • reflexio/server/services/storage/sqlite_storage/_base.py
  • tests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.py
  • reflexio/server/llm/_litellm_types.py
  • reflexio/server/services/profile/components/consolidator.py
  • reflexio/server/llm/tools.py
  • tests/server/services/playbook/test_cluster_change_detection.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • reflexio/server/services/profile/service.py
  • reflexio/server/services/playbook/service.py
  • reflexio/server/services/storage/storage_base/playbook/_agent.py
  • reflexio/server/services/extraction/resume_worker.py
  • reflexio/server/llm/_litellm_text_generation.py

@yilu331 yilu331 changed the title Record model provenance in learning lineage Persist observed model provenance on learning lineage Jul 25, 2026
Persist actual model_name and provider on new lineage_event rows for
content-shaping writes. Capture only observed served metadata (not
request-side LiteLLM routes). No public API expansion in this batch.
@yilu331
yilu331 force-pushed the codex/model-provenance-batch1 branch from eaba95e to dd25c1f Compare July 26, 2026 21:06
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.

2 participants