Fix care-plan request_changes loop to actually revise the plan - #164
Merged
khaledsulayman merged 2 commits intoAug 26, 2026
Merged
Conversation
The care-plan review request_changes loop routed back to GenerateBundle and never passed the clinician's feedback anywhere, so round-2 plans came back byte-for-byte identical. Goals and activities are decided in the planning brief (ComposePlan), and GenerateBundle only serializes an existing brief — it cannot change clinical content. - Workflow: request_changes now loops to ComposePlan, and ComposePlan receives careplan_feedback from .careplanReview.comment. - Compose service: seed the composer's brief_review_feedback from careplan_feedback so plan_composer addresses it on the first pass. - BFF mapper: infer_current_state now distinguishes the ComposePlan re-run from the subsequent GenerateBundle during a request_changes loop. Builds on the routing/fail-closed fix (route on .decision). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collaborator
Author
✅ Verified end-to-end on-cluster (Playwright)Deployed The fix works. After Feedback submitted: "Add a numeric BP target <130/80; patient already on amlodipine 5mg — don't start Lisinopril, optimize existing therapy; add a follow-up recheck."
Incidental (not this PR):
Generated by Claude Code under the supervision of Khaled Sulayman |
…e plan The LLM routinely emits source_cpg: null for lifestyle/general goals and activities. source_cpg is a required string on PlanGoal/PlanActivity, so a single null made the whole PlanningBrief fail validation and plan_composer fell back to an empty plan (0 goals / 0 activities). This surfaced as a blank care plan on a request_changes regeneration. Add _sanitize_provenance() (mirrors _sanitize_conflicts) to default null/ missing source_cpg to the run's applicable CPG before validation, so the item survives instead of dropping the entire brief. Pre-existing brittleness — can hit any compose, not just the review loop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
samschifman
approved these changes
Aug 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #163. Follow-up to #147.
Problem
After #147, requesting changes on a care plan correctly loops instead of writing — but the regenerated plan comes back byte-for-byte identical. The clinician's feedback has no effect.
Root cause
request_changesrouted toGenerateBundle, but goals/activities live in the planning brief produced byComposePlan.GenerateBundleonly serializes an existing brief; it can't change clinical content.GenerateBundleonly receives the automatedfhir_review_feedback, never the clinician's.careplanReview.comment.Changes
acp-writer-workflow.yaml):request_changes→ComposePlan(notGenerateBundle);ComposePlannow receivescareplan_feedbackfrom.careplanReview.comment.llm_reasoning.py): seed the composer'sbrief_review_feedbackfromcareplan_feedbackvia_seed_feedback(), soplan_composeraddresses it on the first pass (it already renders feedback under "Reviewer Feedback (address these issues)").sonataflow_client.py):infer_current_statedistinguishes theComposePlanre-run from the subsequentGenerateBundleduring the loop, usingcompleted_attimestamps.InitCarePlanReviewalready preservescareplanReviewCountacross loops, so iteration count +previousFeedbackkeep working.Testing
test_bff_review_mapping.pyfor the loop-detection (request_changes → ComposePlan → GenerateBundle → gate). All pass.Generated by Claude Code under the supervision of Khaled Sulayman