Skip to content

feat: ground and review generated playbooks - #386

Merged
yyiilluu merged 5 commits into
mainfrom
codex/review-org48-user-playbooks
Jul 28, 2026
Merged

feat: ground and review generated playbooks#386
yyiilluu merged 5 commits into
mainfrom
codex/review-org48-user-playbooks

Conversation

@yyiilluu

@yyiilluu yyiilluu commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Improve normal user-playbook generation with a surgical procedural prompt update, deterministic provenance checks, same-model candidate review, and fail-closed consolidation.
  • Replace model-copied evidence quotations with call-local turn references (evidence_refs: ["T2"]); code resolves cited turns to bounded source-backed text and persisted request/interaction IDs.
  • Keep the current primary model and expert extraction unchanged. The proposed normal prompt versions remain context 4.6.0, extraction 1.5.0, reviewer 1.0.0, and consolidation 2.6.0.
  • Keep the candidate out of production activation: the final org_48 replay recovered all locked observable lessons but strict useful-as-emitted precision was 8/9 (88.9%), below the 95% gate.

Changes

First-pass extraction and evidence

  • Preserve the production Correction SOP, Success Path Recipe, tool-sequence, trigger, and ask-once procedures.
  • Label strict normal windows with request boundaries and whole-turn references ([R#], [T#]) without exposing database IDs.
  • Require complete candidates with evidence_kind, rationale, trigger, content, and one or more cited turn IDs.
  • Validate that every reference was visible in that exact call, maps to persistable provenance, is non-duplicated, and comes from a user turn for direct preferences.
  • Resolve cited turns outside the model to bounded prompt-visible tool/content/action text; never persist the synthetic truncation marker.
  • Retain valid siblings when another candidate is invalid and fail after bounded structured-output repair exhaustion.

Candidate review and consolidation

  • Add exact-accounting accept / revise / reject review in a fresh same-model conversation.
  • Compress the active reviewer from roughly 1,600 static words to 966 rendered words while preserving its decision, evidence-accounting, and structured-output contract; a 1,000-word regression ceiling prevents instruction creep.
  • Prevent revisions from introducing unavailable artifacts, new evidence, or call-local labels in persisted prose.
  • Preserve reviewer revisions, notes, source unions, and provenance through deterministic merge behavior.
  • Repair reject-all, existing-row overlap, duplicate-survivor, application-failure, and malformed-output behavior.

Durable resume and reliability

  • Give turn-referenced extraction its own durable schema name, while preserving the earlier copied-span schema and provider normalization for existing/inactive paths.
  • Snapshot the schema selected at run creation so prompt activation changes cannot reinterpret committed output on resume.
  • Keep the per-rung hard timeout and configured fallback walk; a hard-timeout regression proves MiniMax advances to zai/glm-5.2.
  • Log structured-output salvage instead of recovering partial output silently.

Evaluation

Final ten-case normal-path replay with the production model and public API:

  • locked observable supported-lesson recall: 7/7
  • hard-negative rejection: 2/2
  • useful-as-emitted precision: 8/9 (88.9%)
  • terminal runs: 10/10
  • valid turn references and persisted provenance: 100%
  • overlapping duplicate survivors: 0

The remaining precision failure retained an unsupported claim that narrowing a broad topic produced better content even though no downstream artifact or user outcome was visible. Turn references improve provenance reliability; they do not replace semantic review.

Test Plan

  • Ruff: passed
  • Pyright on changed implementation paths: 0 errors, 0 warnings
  • Compressed reviewer/prompt/service regression suite: 128 passed, 2 skipped
  • Changed playbook/extraction/prompt/LLM suite: 1,227 passed, 65 skipped
  • Complete OSS unit/integration marker suite: 1,082 passed, 64 skipped
  • Hard-timeout to GLM fallback regression: passed
  • Local public-API org_48 replay and persisted provenance inspection: passed mechanically; semantic activation gate remains failed as described above

Summary by CodeRabbit

  • New Features
    • Added evidence-grounded playbook extraction with strict provenance/evidence validation, schema-aware resume, and evidence-aware truncation handling.
    • Introduced a candidate review stage (accept/revise/reject) before consolidation.
    • Enhanced playbook consolidation with evidence-aware reconciliation, stricter duplicate/overlap policies, and fail-closed behavior.
    • Added structured-response validator support for tool loops and resumable extraction flows.
  • Bug Fixes
    • Improved structured-output parsing/repair: safer truncated list salvage and provider-output shape normalization.
    • Enhanced validation error capture with safer logging and warning observability.
  • Documentation
    • Updated playbook pipeline docs and added/disabled prompt templates and prompt versions.
  • Tests
    • Expanded structured-output, evidence-grounding, reviewer, and consolidation coverage (including new regression cases).

@coderabbitai

coderabbitai Bot commented Jul 28, 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: 6 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: 6ea2c2ee-93fc-451b-8164-a6239bd9dbba

📥 Commits

Reviewing files that changed from the base of the PR and between ea2a8aa and 696aa2c.

📒 Files selected for processing (50)
  • reflexio/models/structured_output.py
  • reflexio/server/llm/_litellm_structured_output.py
  • reflexio/server/llm/_litellm_text_generation.py
  • reflexio/server/llm/_litellm_types.py
  • reflexio/server/llm/tools.py
  • reflexio/server/prompt/prompt_bank/playbook_candidate_review/v1.0.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.5.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.6.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.5.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.6.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.4.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.5.0.prompt.md
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/base_generation_service.py
  • reflexio/server/services/extraction/agent_run_records.py
  • reflexio/server/services/extraction/resumable_agent.py
  • reflexio/server/services/extraction/resume_worker.py
  • reflexio/server/services/playbook/README.md
  • reflexio/server/services/playbook/components/consolidator.py
  • reflexio/server/services/playbook/components/extractor.py
  • reflexio/server/services/playbook/components/reviewer.py
  • reflexio/server/services/playbook/playbook_evidence.py
  • reflexio/server/services/playbook/playbook_service_constants.py
  • reflexio/server/services/playbook/playbook_service_utils.py
  • reflexio/server/services/playbook/service.py
  • reflexio/server/services/service_utils.py
  • reflexio/test_support/llm_model_registry.py
  • tests/e2e_tests/test_contradiction_resolution_e2e.py
  • tests/eval/extraction/test_extraction_eval.py
  • tests/fixtures/llm/playbook_extraction.json
  • tests/server/llm/test_litellm_client_unit.py
  • tests/server/llm/test_tools.py
  • tests/server/services/__snapshots__/test_llm_mock_schema_compliance/TestMockResponseSnapshots.test_recorded_fixture_content[playbook_extraction].json
  • tests/server/services/extraction/test_resume_worker.py
  • tests/server/services/playbook/test_consolidation_lineage_integration.py
  • tests/server/services/playbook/test_extractor_polarity_integration.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • tests/server/services/playbook/test_playbook_consolidator_integration.py
  • tests/server/services/playbook/test_playbook_extractor.py
  • tests/server/services/playbook/test_playbook_generalization_manifest.py
  • tests/server/services/playbook/test_playbook_generation_service.py
  • tests/server/services/playbook/test_playbook_generation_service_integration.py
  • tests/server/services/playbook/test_playbook_reviewer.py
  • tests/server/services/playbook/test_playbook_service_utils.py
  • tests/server/services/playbook/test_structured_playbook_content.py
  • tests/server/services/prompt/test_prompt_manager.py
  • tests/server/services/test_base_generation_service.py
  • tests/server/services/test_prompt_model_mapping.py
  • tests/server/services/test_service_utils.py
  • tests/test_data/playbook_generalization_manifest.json
📝 Walkthrough

Walkthrough

The pull request adds evidence-grounded playbook extraction, candidate review, stricter consolidation, provider-tolerant structured parsing, resumable schema selection, fallback timeout handling, prompt versioning, and expanded validation coverage.

Changes

Playbook pipeline

Layer / File(s) Summary
Evidence contracts and prompt context
reflexio/server/services/playbook/playbook_service_utils.py, reflexio/server/services/playbook/playbook_evidence.py, reflexio/server/prompt/prompt_bank/*
Adds structured evidence models, provenance resolution, strict extraction contracts, local turn references, and versioned prompts.
Extraction and resume wiring
reflexio/server/services/playbook/components/extractor.py, reflexio/server/services/extraction/*, reflexio/server/services/base_generation/*
Propagates schemas and validators through fresh and resumed extraction runs, persists schema identity, and selects extended fallback timeouts.
Candidate review
reflexio/server/services/playbook/components/reviewer.py, reflexio/server/services/playbook/service.py
Adds evidence-aware accept/revise/reject review with provider-shape normalization, revision narrowing, and fail-closed validation.
Consolidation
reflexio/server/services/playbook/components/consolidator.py
Adds evidence groups, deterministic replay merging, overlap checks, metadata merging, and strict partition enforcement.
Structured-output resilience
reflexio/models/structured_output.py, reflexio/server/llm/*, reflexio/server/llm/tools.py
Adds provider normalization, list-wrapper coercion, truncated-list salvage, content-safe validation errors, and validator-driven repair turns.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: yilu331, guangyu-reflexio

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.31% 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 summarizes the main change: grounding and reviewing generated playbooks.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/review-org48-user-playbooks

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
reflexio/server/services/playbook/components/consolidator.py (1)

622-630: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

LLM Security (CWE-1427)

Reachability: External

Serialize playbook rows before prompting In _format_playbooks_with_prefix, Content, Trigger, Rationale, and Evidence Span are injected as raw prose, so a malicious span can still smuggle instructions or row-shaped text into the LLM context. The current checks enforce NEW coverage and overlap, but they do not prove the chosen unify/reject_new action is grounded in the cited evidence.

🤖 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
622 - 630, Update _format_playbooks_with_prefix to serialize each playbook row
before adding it to the prompt, treating Content, Trigger, Rationale, and
Evidence Span as data rather than raw prose. Use a structured, unambiguous
representation with proper escaping so embedded instructions or row-shaped text
cannot alter the row boundaries or surrounding prompt semantics, while
preserving the existing prefix, evidence-group, name, source, and timestamp
fields.
reflexio/server/services/extraction/resume_worker.py (1)

571-621: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Persist and label resolved tool answers as strict evidence.

prompt_context.evidence_sources contains only original interactions, while the resumed run can rely on a resolved ask_human answer. The strict validator and persistence path therefore cannot cite that answer: a required positive procedure is either dropped or saved with provenance pointing only to the earlier “missing procedure” conversation.

  • reflexio/server/services/extraction/resume_worker.py#L571-L621: materialize resolved tool answers into the resumed evidence snapshot/map and render a stable local reference before strict validation.
  • reflexio/server/services/extraction/resume_worker.py#L785-L830: rebuild the same persisted evidence snapshot during finalization retry, rather than reconstructing only original interaction evidence.
🤖 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/extraction/resume_worker.py` around lines 571 - 621,
Update the resumed extraction flow around _resume_agent to materialize resolved
tool answers into the evidence snapshot/map, render stable local references, and
pass that augmented evidence to strict validation and persistence. Apply the
same evidence reconstruction in
reflexio/server/services/extraction/resume_worker.py lines 571-621 and 785-830,
with the finalization retry reusing resolved answers rather than only original
interaction evidence.
tests/server/services/playbook/test_playbook_extractor.py (1)

891-925: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Class docstring now contradicts this test.

TestStructuredPlaybookExtraction's docstring still states that a degenerate loop "leaves result.output is None and the extractor returns []", which this test just inverted to a terminal RuntimeError. Update the class docstring so the contract statement matches.

🤖 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/services/playbook/test_playbook_extractor.py` around lines 891 -
925, Update the TestStructuredPlaybookExtraction class docstring to state that a
degenerate loop with no structured output terminates with a RuntimeError, rather
than leaving result.output as None and returning an empty list. Keep the rest of
the documented extraction contract unchanged.
🧹 Nitpick comments (8)
tests/server/services/playbook/test_playbook_generation_service.py (2)

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

This assertion depends on the on-disk active extraction prompt version.

The fail-closed branch only runs when uses_evidence_grounded_extraction sees playbook_extraction_context >= 4.6.0. Since activating an older version is an explicitly supported rollback (per that helper's docstring), a rollback would silently turn this into a "review skipped" path and fail here with an unrelated message. Stubbing get_active_version for playbook_extraction_context would keep the test asserting the behavior it names.

🤖 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/services/playbook/test_playbook_generation_service.py` around
lines 918 - 932, Update the test around service._resolve_write_plan to stub
get_active_version for playbook_extraction_context to return a version at or
above 4.6.0. Keep the existing RuntimeError assertion for “missing validated
evidence metadata: C1” unchanged, ensuring the test consistently exercises the
fail-closed evidence-validation branch regardless of the active on-disk prompt
version.

810-825: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No coverage for the retrieval-cache invalidation branch.

This test's reviewer only changes content, so the survivors' search keys are unchanged and existing_playbooks is reused. The new invalidation path in service.py lines 471-474 (a revised trigger must drop the cached retrieval so consolidation searches again) is never exercised, and the assertions don't check deduplicate(..., existing_playbooks=...) either. A sibling case returning a survivor with a new trigger and asserting call_args.kwargs["existing_playbooks"] is None would pin it. Want me to draft it?

🤖 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/services/playbook/test_playbook_generation_service.py` around
lines 810 - 825, The test around _resolve_write_plan only covers reviewer
content changes and does not exercise retrieval-cache invalidation. Add a
sibling case where reviewer.review returns a survivor with a revised trigger,
then assert consolidator.deduplicate receives existing_playbooks=None via
call_args.kwargs while preserving the existing consolidation assertions.
tests/server/services/playbook/test_playbook_reviewer.py (1)

324-362: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Parametrize the prompt-phrase assertions so a failure names the guarantee.

Forty bare assert <phrase> in normalized lines fail one-at-a-time with no indication of which reviewer behavior regressed, and generic phrases like "This is mandatory" carry almost no signal. A @pytest.mark.parametrize(("guarantee", "phrase"), [...]) over the same list reports every drifted phrase in one run and documents intent.

🤖 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/services/playbook/test_playbook_reviewer.py` around lines 324 -
362, Replace the individual prompt-phrase assertions in the relevant playbook
reviewer test with a pytest.mark.parametrize fixture using (“guarantee”,
“phrase”) entries. Keep the existing phrase list and assertion behavior, but
include descriptive guarantee names—especially for generic phrases such as “This
is mandatory”—so failures identify the regressed reviewer behavior and report
all mismatches in one run.
reflexio/server/services/playbook/service.py (2)

396-474: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Consider extracting the review gate into its own method.

_resolve_write_plan now carries ~90 lines of five-level-deep gating (mock mode → window reload → expert → strict-prompt → evidence validation → review → cache invalidation) on top of its consolidation duties. A _maybe_review_candidates(all_playbooks, playbook_config, consolidator) -> tuple[list[UserPlaybook], list[UserPlaybook] | None] helper would flatten the nesting and make the early-skip branches readable, with no behavior change.

🤖 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/service.py` around lines 396 - 474, Extract
the nested candidate-review gate from _resolve_write_plan into a helper such as
_maybe_review_candidates, returning the reviewed playbooks and the optionally
reusable existing_playbooks cache. Preserve every existing skip condition,
validation/error behavior, reviewer inputs, and consolidation-search-key cache
invalidation, while leaving _resolve_write_plan responsible only for invoking
the helper and continuing consolidation.

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

The "honest empty window" contract is unreachable in production.

[] is deliberately cached and returned here (and pinned by test_review_interaction_window_returns_honest_empty_window), but the sole production caller at line 404 raises RuntimeError on a falsy window, so an empty reload aborts the whole write plan rather than being tolerated. Either the empty case should skip review with a log (like the expert/legacy branches below it) or the docstring should state that empty is also fatal.

🤖 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/service.py` around lines 206 - 217, The
production caller of the cached review window must honor an empty list as a
valid window: update the review flow around the caller near the write-plan logic
to skip review and log appropriately when the window is empty, while preserving
the existing fatal handling for a missing window (None). Keep _get_interactions
and its honest-empty caching behavior unchanged.
reflexio/server/services/playbook/components/reviewer.py (1)

198-208: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The note prefix is an implicit cross-component contract.

consolidator._has_reviewer_revision detects reviewer revisions by matching this free-text note prefix (see tests/server/services/playbook/test_playbook_consolidator.py line 2472, which pins "First-pass reviewer: revised (late_trigger) — …"). A reword here silently disables reviewer-revision precedence in _merge_replayed_evidence_duplicates. Consider hoisting the prefix into a shared constant. Also note the wording says "First-pass reviewer" while this module is documented as the second-pass review.

♻️ Shared constant sketch
+REVIEW_NOTE_PREFIX = "First-pass reviewer"
+
 def _append_review_note(
     existing: str | None,
     decision: str,
     reason_code: str,
     reason: str | None,
 ) -> str:
     normalized_reason = " ".join((reason or reason_code).split())[:500]
     review_note = (
-        f"First-pass reviewer: {decision} ({reason_code}) — {normalized_reason}"
+        f"{REVIEW_NOTE_PREFIX}: {decision} ({reason_code}) — {normalized_reason}"
     )
🤖 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/reviewer.py` around lines 198 -
208, Hoist the exact “First-pass reviewer:” note prefix used by
_append_review_note into a shared constant accessible to
consolidator._has_reviewer_revision, and update both producer and detector to
reuse it. Preserve the existing note format and wording so reviewer-revision
precedence and the pinned test behavior remain unchanged.
reflexio/server/services/playbook/components/consolidator.py (1)

1005-1018: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Overlap guard is not applied on the evidence-validated short-circuit.

The LLM path runs _find_overlapping_survivors over the produced rows (Line 1084) before returning, but this branch returns candidates directly. Two grounded siblings that state the same lesson with disjoint provenance will both persist here and only be caught on a later batch. If that is intended (the comment argues for keeping independent siblings), consider saying so explicitly; otherwise run the same guard over new_playbooks before returning.

🤖 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
1005 - 1018, Apply the same overlap guard used by the LLM path to the
evidence-validated short-circuit before returning new_playbooks. Invoke
_find_overlapping_survivors with the appropriate context, return only the
surviving playbooks, and preserve the existing request_id updates and empty
auxiliary lists.
reflexio/server/services/playbook/playbook_service_utils.py (1)

505-524: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

ref_by_object_id keyed on id() silently collapses shared interaction objects.

If the same Interaction instance is reachable from two request_model.interactions lists (same object, not just equal), the second registration overwrites the first and the earlier turn resolves to the later T#. A (request_id, interaction_id) key would be identity-independent and still O(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 `@reflexio/server/services/playbook/playbook_service_utils.py` around lines 505
- 524, Replace the id(interaction)-based keys in the turn registration logic
with a (request_id, interaction_id) key, and update all corresponding lookups to
use that same tuple. Preserve O(1) resolution while ensuring shared Interaction
instances retain independent turn mappings for each request.
🤖 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/prompt/prompt_bank/playbook_extraction_context/v4.6.0.prompt.md`:
- Around line 316-319: Wrap the {agent_context_prompt} insertion in an explicit
untrusted-data boundary within the prompt, instructing the extractor to treat
all transcript content as evidence only and not follow embedded instructions.
Preserve the existing guidance about exploring available tools and negative
outcomes.

In `@reflexio/server/services/playbook/components/consolidator.py`:
- Around line 1772-1781: The docstrings for _apply_reject_new and _apply_one
still describe the removed safety fallback behavior. Update their descriptions
and Returns documentation to state the current unresolved EXISTING-id
behavior—raising an error—and remove references to logging warnings, returning
empty collections for fallback, or suppressing the safety fallback via
handled_new_ids.

In `@reflexio/server/services/playbook/components/reviewer.py`:
- Around line 404-414: Normalize decision candidate IDs consistently in
_apply_decisions by stripping surrounding whitespace before building the
decisions mapping, matching the normalization used during validation. Ensure
lookups by the generated C{index} identifiers cannot fail for padded provider
IDs, while preserving existing decision handling.

In `@reflexio/server/services/playbook/playbook_evidence.py`:
- Around line 50-56: Update _is_direct_user_preference_source to require both a
normalized user role and a trusted user-origin value in request_source; do not
accept role alone. Reuse the existing request_source enum or constant for the
trusted user source, preserving rejection of generated, memory, and
recommender-originated turns.

In `@reflexio/server/services/playbook/README.md`:
- Around line 93-98: Update the decision-kind bullet list immediately above the
rewritten contract to match the four variants in PlaybookConsolidationOutput:
replace duplicate with unify, prefer_new with reject_new, and prefer_existing
with the current corresponding contract terminology; retain differentiate and
independent unchanged.

In `@reflexio/server/services/playbook/service.py`:
- Line 154: Update _review_window_cache handling in PlaybookGenerationService so
cached review-window data cannot be reused across users or requests. Either key
the cache by (user_id, request_id) and retrieve entries using both identifiers,
or clear it in _prepare_generation_run() whenever a new request is loaded;
preserve reuse only within the same user/request.

In `@tests/server/services/playbook/test_playbook_consolidator.py`:
- Around line 1173-1180: Update the pytest.raises(ValueError) assertion around
_build_deduplicated_results to include a match= pattern that specifically
identifies the unresolved superseding-reference error expected by this test.
Preserve the existing arguments and ensure the pattern is precise enough to
reject unrelated partition, ID, or survivor-overlap validation failures.

In `@tests/server/services/playbook/test_playbook_extractor.py`:
- Around line 1942-1962: Suppress RUF001 locally on the intentional
curly-apostrophe test cases in
test_typographic_quotes_resolve_to_the_original_text and
test_ambiguous_normalized_match_is_rejected, preserving the typographic
characters and test behavior without broadening the lint suppression.

---

Outside diff comments:
In `@reflexio/server/services/extraction/resume_worker.py`:
- Around line 571-621: Update the resumed extraction flow around _resume_agent
to materialize resolved tool answers into the evidence snapshot/map, render
stable local references, and pass that augmented evidence to strict validation
and persistence. Apply the same evidence reconstruction in
reflexio/server/services/extraction/resume_worker.py lines 571-621 and 785-830,
with the finalization retry reusing resolved answers rather than only original
interaction evidence.

In `@reflexio/server/services/playbook/components/consolidator.py`:
- Around line 622-630: Update _format_playbooks_with_prefix to serialize each
playbook row before adding it to the prompt, treating Content, Trigger,
Rationale, and Evidence Span as data rather than raw prose. Use a structured,
unambiguous representation with proper escaping so embedded instructions or
row-shaped text cannot alter the row boundaries or surrounding prompt semantics,
while preserving the existing prefix, evidence-group, name, source, and
timestamp fields.

In `@tests/server/services/playbook/test_playbook_extractor.py`:
- Around line 891-925: Update the TestStructuredPlaybookExtraction class
docstring to state that a degenerate loop with no structured output terminates
with a RuntimeError, rather than leaving result.output as None and returning an
empty list. Keep the rest of the documented extraction contract unchanged.

---

Nitpick comments:
In `@reflexio/server/services/playbook/components/consolidator.py`:
- Around line 1005-1018: Apply the same overlap guard used by the LLM path to
the evidence-validated short-circuit before returning new_playbooks. Invoke
_find_overlapping_survivors with the appropriate context, return only the
surviving playbooks, and preserve the existing request_id updates and empty
auxiliary lists.

In `@reflexio/server/services/playbook/components/reviewer.py`:
- Around line 198-208: Hoist the exact “First-pass reviewer:” note prefix used
by _append_review_note into a shared constant accessible to
consolidator._has_reviewer_revision, and update both producer and detector to
reuse it. Preserve the existing note format and wording so reviewer-revision
precedence and the pinned test behavior remain unchanged.

In `@reflexio/server/services/playbook/playbook_service_utils.py`:
- Around line 505-524: Replace the id(interaction)-based keys in the turn
registration logic with a (request_id, interaction_id) key, and update all
corresponding lookups to use that same tuple. Preserve O(1) resolution while
ensuring shared Interaction instances retain independent turn mappings for each
request.

In `@reflexio/server/services/playbook/service.py`:
- Around line 396-474: Extract the nested candidate-review gate from
_resolve_write_plan into a helper such as _maybe_review_candidates, returning
the reviewed playbooks and the optionally reusable existing_playbooks cache.
Preserve every existing skip condition, validation/error behavior, reviewer
inputs, and consolidation-search-key cache invalidation, while leaving
_resolve_write_plan responsible only for invoking the helper and continuing
consolidation.
- Around line 206-217: The production caller of the cached review window must
honor an empty list as a valid window: update the review flow around the caller
near the write-plan logic to skip review and log appropriately when the window
is empty, while preserving the existing fatal handling for a missing window
(None). Keep _get_interactions and its honest-empty caching behavior unchanged.

In `@tests/server/services/playbook/test_playbook_generation_service.py`:
- Around line 918-932: Update the test around service._resolve_write_plan to
stub get_active_version for playbook_extraction_context to return a version at
or above 4.6.0. Keep the existing RuntimeError assertion for “missing validated
evidence metadata: C1” unchanged, ensuring the test consistently exercises the
fail-closed evidence-validation branch regardless of the active on-disk prompt
version.
- Around line 810-825: The test around _resolve_write_plan only covers reviewer
content changes and does not exercise retrieval-cache invalidation. Add a
sibling case where reviewer.review returns a survivor with a revised trigger,
then assert consolidator.deduplicate receives existing_playbooks=None via
call_args.kwargs while preserving the existing consolidation assertions.

In `@tests/server/services/playbook/test_playbook_reviewer.py`:
- Around line 324-362: Replace the individual prompt-phrase assertions in the
relevant playbook reviewer test with a pytest.mark.parametrize fixture using
(“guarantee”, “phrase”) entries. Keep the existing phrase list and assertion
behavior, but include descriptive guarantee names—especially for generic phrases
such as “This is mandatory”—so failures identify the regressed reviewer behavior
and report all mismatches in one run.
🪄 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

Run ID: dbf35f89-9bc7-47d4-bd8b-655984812389

📥 Commits

Reviewing files that changed from the base of the PR and between 51c9d5c and 7e42768.

📒 Files selected for processing (48)
  • reflexio/models/structured_output.py
  • reflexio/server/llm/_litellm_structured_output.py
  • reflexio/server/llm/_litellm_text_generation.py
  • reflexio/server/llm/_litellm_types.py
  • reflexio/server/llm/tools.py
  • reflexio/server/prompt/prompt_bank/playbook_candidate_review/v1.0.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.5.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.6.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.5.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.6.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.4.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.5.0.prompt.md
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/base_generation_service.py
  • reflexio/server/services/extraction/agent_run_records.py
  • reflexio/server/services/extraction/resumable_agent.py
  • reflexio/server/services/extraction/resume_worker.py
  • reflexio/server/services/playbook/README.md
  • reflexio/server/services/playbook/components/consolidator.py
  • reflexio/server/services/playbook/components/extractor.py
  • reflexio/server/services/playbook/components/reviewer.py
  • reflexio/server/services/playbook/playbook_evidence.py
  • reflexio/server/services/playbook/playbook_service_constants.py
  • reflexio/server/services/playbook/playbook_service_utils.py
  • reflexio/server/services/playbook/service.py
  • reflexio/test_support/llm_model_registry.py
  • tests/e2e_tests/test_contradiction_resolution_e2e.py
  • tests/eval/extraction/test_extraction_eval.py
  • tests/fixtures/llm/playbook_extraction.json
  • tests/server/llm/test_litellm_client_unit.py
  • tests/server/llm/test_tools.py
  • tests/server/services/__snapshots__/test_llm_mock_schema_compliance/TestMockResponseSnapshots.test_recorded_fixture_content[playbook_extraction].json
  • tests/server/services/extraction/test_resume_worker.py
  • tests/server/services/playbook/test_consolidation_lineage_integration.py
  • tests/server/services/playbook/test_extractor_polarity_integration.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • tests/server/services/playbook/test_playbook_consolidator_integration.py
  • tests/server/services/playbook/test_playbook_extractor.py
  • tests/server/services/playbook/test_playbook_generalization_manifest.py
  • tests/server/services/playbook/test_playbook_generation_service.py
  • tests/server/services/playbook/test_playbook_generation_service_integration.py
  • tests/server/services/playbook/test_playbook_reviewer.py
  • tests/server/services/playbook/test_playbook_service_utils.py
  • tests/server/services/playbook/test_structured_playbook_content.py
  • tests/server/services/prompt/test_prompt_manager.py
  • tests/server/services/test_base_generation_service.py
  • tests/server/services/test_prompt_model_mapping.py
  • tests/test_data/playbook_generalization_manifest.json

Comment thread reflexio/server/services/playbook/components/consolidator.py
Comment thread reflexio/server/services/playbook/components/reviewer.py
Comment on lines +50 to +56
def _is_direct_user_preference_source(source: PlaybookEvidenceSource) -> bool:
"""Return whether a turn can independently establish a durable preference.

A durable preference must come from the user's own words: an agent turn
restating what it believes the user wants is not independent evidence.
"""
return source.role.strip().casefold() == "user"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reject internally generated “User” turns as preference evidence.

Checking role alone accepts generation, memory, or recommender content stored as User, despite the prompt requiring request-source metadata to distinguish agent-authored context. Require a trusted user-origin check on request_source too, or internal text can become a persisted user preference.

🤖 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/playbook_evidence.py` around lines 50 - 56,
Update _is_direct_user_preference_source to require both a normalized user role
and a trusted user-origin value in request_source; do not accept role alone.
Reuse the existing request_source enum or constant for the trusted user source,
preserving rejection of generated, memory, and recommender-originated turns.

Comment thread reflexio/server/services/playbook/README.md
Comment thread reflexio/server/services/playbook/service.py
Comment thread tests/server/services/playbook/test_playbook_consolidator.py Outdated
Comment thread tests/server/services/playbook/test_playbook_extractor.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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/server/services/playbook/test_playbook_extractor.py (2)

742-866: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep _make_extractor aligned with the prompt-version contract.

Its conditional get_active_version setup repeats the same broad 1.2.0 fallback. Return the correct version for each prompt ID, including extraction 1.5.0, so these tests cannot silently use stale prompt fixtures.


666-670: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Map extraction prompt versions explicitly.

The fallback returns 1.2.0 for every prompt other than playbook_extraction_context, so a playbook_extraction_main request will not exercise the declared 1.5.0 extraction prompt. Use an explicit per-prompt mapping and fail on unknown IDs.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 19f92a76-80ec-4e46-9120-baf4f3378757

📥 Commits

Reviewing files that changed from the base of the PR and between 1553d7c and 817b78f.

📒 Files selected for processing (10)
  • reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.6.0.prompt.md
  • reflexio/server/services/playbook/README.md
  • reflexio/server/services/playbook/components/consolidator.py
  • reflexio/server/services/playbook/components/reviewer.py
  • reflexio/server/services/playbook/service.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • tests/server/services/playbook/test_playbook_extractor.py
  • tests/server/services/playbook/test_playbook_generation_service.py
  • tests/server/services/playbook/test_playbook_reviewer.py
  • tests/server/services/prompt/test_prompt_manager.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • tests/server/services/prompt/test_prompt_manager.py
  • tests/server/services/playbook/test_playbook_reviewer.py
  • reflexio/server/services/playbook/README.md
  • reflexio/server/services/playbook/components/reviewer.py
  • reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.6.0.prompt.md
  • reflexio/server/services/playbook/service.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • reflexio/server/services/playbook/components/consolidator.py

@yyiilluu
yyiilluu force-pushed the codex/review-org48-user-playbooks branch from 817b78f to ea2a8aa Compare July 28, 2026 05:04

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

♻️ Duplicate comments (1)
reflexio/server/services/playbook/playbook_evidence.py (1)

53-59: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preference-source check still ignores request_source; unresolved from a prior review round.

_is_direct_user_preference_source only checks role, so an internally generated "User"-role turn (memory/store tool, recommender, generation workflow) can still independently establish a durable preference playbook — exactly the case the sibling prompt (v4.6.0.prompt.md lines 112-117) tells the model to distinguish via request_source, but the deterministic backstop here doesn't enforce it. _referenced_evidence_rejection_reason (line 145-148) has the identical gap, duplicated inline instead of calling this helper — fixing only the helper won't close that second path.

🔒 Proposed direction (pending confirmation of the trusted-source constant)
 def _is_direct_user_preference_source(source: PlaybookEvidenceSource) -> bool:
-    return source.role.strip().casefold() == "user"
+    return (
+        source.role.strip().casefold() == "user"
+        and _is_trusted_user_request_source(source.request_source)
+    )

Apply the equivalent check at the _referenced_evidence_rejection_reason call site (line 145-148), ideally by routing it through _is_direct_user_preference_source on a PlaybookEvidenceUnit-compatible shape instead of re-inlining the role check.

Run to locate the trusted-source constant/enum this should compare against:

#!/bin/bash
rg -n --type=py -C3 '\brequest_source\b' reflexio/server/services/playbook
rg -n --type=py -C3 'class .*Source' reflexio/models reflexio/server/services

Also applies to: 145-148

🤖 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/playbook_evidence.py` around lines 53 - 59,
Update _is_direct_user_preference_source to require both a normalized user role
and the trusted request_source constant or enum identified from the existing
model definitions. Replace the duplicated role-only check in
_referenced_evidence_rejection_reason with this same helper or equivalent shared
predicate, ensuring internally generated User-role evidence cannot establish or
validate durable preferences.
🤖 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.

Duplicate comments:
In `@reflexio/server/services/playbook/playbook_evidence.py`:
- Around line 53-59: Update _is_direct_user_preference_source to require both a
normalized user role and the trusted request_source constant or enum identified
from the existing model definitions. Replace the duplicated role-only check in
_referenced_evidence_rejection_reason with this same helper or equivalent shared
predicate, ensuring internally generated User-role evidence cannot establish or
validate durable preferences.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7005cf10-7b1d-462e-87c7-2c01d9eb642b

📥 Commits

Reviewing files that changed from the base of the PR and between 817b78f and ea2a8aa.

📒 Files selected for processing (50)
  • reflexio/models/structured_output.py
  • reflexio/server/llm/_litellm_structured_output.py
  • reflexio/server/llm/_litellm_text_generation.py
  • reflexio/server/llm/_litellm_types.py
  • reflexio/server/llm/tools.py
  • reflexio/server/prompt/prompt_bank/playbook_candidate_review/v1.0.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.5.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.6.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.5.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.6.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.4.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.5.0.prompt.md
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/services/base_generation_service.py
  • reflexio/server/services/extraction/agent_run_records.py
  • reflexio/server/services/extraction/resumable_agent.py
  • reflexio/server/services/extraction/resume_worker.py
  • reflexio/server/services/playbook/README.md
  • reflexio/server/services/playbook/components/consolidator.py
  • reflexio/server/services/playbook/components/extractor.py
  • reflexio/server/services/playbook/components/reviewer.py
  • reflexio/server/services/playbook/playbook_evidence.py
  • reflexio/server/services/playbook/playbook_service_constants.py
  • reflexio/server/services/playbook/playbook_service_utils.py
  • reflexio/server/services/playbook/service.py
  • reflexio/server/services/service_utils.py
  • reflexio/test_support/llm_model_registry.py
  • tests/e2e_tests/test_contradiction_resolution_e2e.py
  • tests/eval/extraction/test_extraction_eval.py
  • tests/fixtures/llm/playbook_extraction.json
  • tests/server/llm/test_litellm_client_unit.py
  • tests/server/llm/test_tools.py
  • tests/server/services/__snapshots__/test_llm_mock_schema_compliance/TestMockResponseSnapshots.test_recorded_fixture_content[playbook_extraction].json
  • tests/server/services/extraction/test_resume_worker.py
  • tests/server/services/playbook/test_consolidation_lineage_integration.py
  • tests/server/services/playbook/test_extractor_polarity_integration.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • tests/server/services/playbook/test_playbook_consolidator_integration.py
  • tests/server/services/playbook/test_playbook_extractor.py
  • tests/server/services/playbook/test_playbook_generalization_manifest.py
  • tests/server/services/playbook/test_playbook_generation_service.py
  • tests/server/services/playbook/test_playbook_generation_service_integration.py
  • tests/server/services/playbook/test_playbook_reviewer.py
  • tests/server/services/playbook/test_playbook_service_utils.py
  • tests/server/services/playbook/test_structured_playbook_content.py
  • tests/server/services/prompt/test_prompt_manager.py
  • tests/server/services/test_base_generation_service.py
  • tests/server/services/test_prompt_model_mapping.py
  • tests/server/services/test_service_utils.py
  • tests/test_data/playbook_generalization_manifest.json
🚧 Files skipped from review as they are similar to previous changes (42)
  • reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.4.0.prompt.md
  • reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.5.0.prompt.md
  • tests/fixtures/llm/playbook_extraction.json
  • reflexio/server/services/playbook/playbook_service_constants.py
  • tests/server/services/snapshots/test_llm_mock_schema_compliance/TestMockResponseSnapshots.test_recorded_fixture_content[playbook_extraction].json
  • reflexio/server/services/extraction/agent_run_records.py
  • tests/server/services/extraction/test_resume_worker.py
  • tests/e2e_tests/test_contradiction_resolution_e2e.py
  • tests/server/services/playbook/test_playbook_generalization_manifest.py
  • reflexio/test_support/llm_model_registry.py
  • reflexio/server/llm/_litellm_text_generation.py
  • reflexio/models/structured_output.py
  • tests/server/llm/test_tools.py
  • reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.5.0.prompt.md
  • tests/server/services/test_service_utils.py
  • tests/test_data/playbook_generalization_manifest.json
  • reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.5.0.prompt.md
  • reflexio/server/services/base_generation_service.py
  • tests/server/services/playbook/test_consolidation_lineage_integration.py
  • tests/server/services/prompt/test_prompt_manager.py
  • reflexio/server/llm/tools.py
  • tests/eval/extraction/test_extraction_eval.py
  • tests/server/services/playbook/test_structured_playbook_content.py
  • reflexio/server/llm/_litellm_types.py
  • reflexio/server/services/extraction/resumable_agent.py
  • tests/server/services/playbook/test_playbook_generation_service_integration.py
  • tests/server/services/test_prompt_model_mapping.py
  • tests/server/services/playbook/test_playbook_reviewer.py
  • reflexio/server/services/base_generation/_extraction_lifecycle.py
  • reflexio/server/prompt/prompt_bank/playbook_candidate_review/v1.0.0.prompt.md
  • reflexio/server/services/playbook/service.py
  • tests/server/services/playbook/test_extractor_polarity_integration.py
  • reflexio/server/services/playbook/components/extractor.py
  • tests/server/services/playbook/test_playbook_generation_service.py
  • tests/server/services/test_base_generation_service.py
  • tests/server/services/playbook/test_playbook_consolidator_integration.py
  • reflexio/server/services/playbook/components/reviewer.py
  • tests/server/services/playbook/test_playbook_consolidator.py
  • tests/server/services/playbook/test_playbook_extractor.py
  • reflexio/server/services/extraction/resume_worker.py
  • reflexio/server/services/playbook/playbook_service_utils.py
  • reflexio/server/services/playbook/components/consolidator.py

yyiilluu added 5 commits July 27, 2026 22:22
Require verbatim evidence and persisted provenance for normal extraction, add a same-model candidate reviewer, make consolidation evidence-aware and fail closed, and advance configured fallbacks after hard LLM timeouts.
@yyiilluu
yyiilluu force-pushed the codex/review-org48-user-playbooks branch from ea2a8aa to 696aa2c Compare July 28, 2026 05:26
@yyiilluu
yyiilluu merged commit cec5adf into main Jul 28, 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