acp-writer mock BFF: canned-data implementation of the #127 UI contract - #136
Draft
khaledsulayman wants to merge 23 commits into
Draft
acp-writer mock BFF: canned-data implementation of the #127 UI contract#136khaledsulayman wants to merge 23 commits into
khaledsulayman wants to merge 23 commits into
Conversation
First-cut, screen-driven contract for the acp-writer BFF's UI-facing surface, to be co-owned by the BFF (backend) and React UI tracks and merged before both split off. Single source of truth: UI generates types via openapi-typescript; BFF validates against it — no hand-synced parallel types. Scope: UI-facing endpoints only (runs lifecycle, review gates, care plans, status). BFF-internal plumbing (artifact notifications, SonataFlow callbacks) is intentionally out of scope. Three open questions flagged inline (# OPEN:) for Jaideep/Sam: SMART token flow, whether planningBrief is gate-only vs always-present, and confirming the StepKey vocabulary matches the SonataFlow workflow states. Refs samschifman#28. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ates Verified the automated StepKey values 1:1 against the acp-writer SonataFlow workflow (acp-writer/deploy/orchestrator/acp-writer-workflow.yaml, v0.2.0) and documented the PascalCase-state → snake_case-key mapping inline. The BFF owns this mapping when deriving currentStep from a live instance. Reframed the remaining open question: the two human review gates the contract depends on (review_brief, review_careplan) do not exist in the workflow yet — it runs straight through with only automated async callbacks. Per spike-b/ spike-c they need to be added as Callback states emitting an awaiting_review marker to drive the awaiting_* statuses. Flagged as a backend/workflow item. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
planningBrief: confirmed available from the brief gate onward (not gate-only) — it is written to the durable MinIO PHI artifact (planning_brief_ref) after composition and survives the whole run, so it's readable after approval. Dropped the OPEN hedge on RunDetail.planningBrief and noted the view-model flattens the richer internal PlanningBrief (provenance fields) if the review UI needs them. SMART launch: split the vague token-handling OPEN into the two coupled decisions it actually is — (1) browser vs BFF token exchange, (2) $summary read location — and surfaced the tension between a BFF-side FHIR read and the AGENTS.md boundary "acp-writer does not query FHIR servers." Left open as a team boundary call. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
acp-writer is a confidential SMART client (holds a secret), so the token exchange
belongs server-side in the BFF. Reshaped POST /runs/smart-launch to take
{iss, launch, code} (+ optional PKCE codeVerifier) and made BFF-side exchange the
recommended default. Documented that the current mock-EHR IPS Viewer uses
client_credentials with the secret in the browser — a dev shortcut, not a real
SMART exchange, not to be promoted to the contract. Kept browser+PKCE (public
client re-registration) as the documented alternative.
Also removed the Person A / Person B framing from the file header and OPEN notes
in favor of "UI track" / "BFF/backend track".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removed the negotiation-draft framing and the inline # OPEN blocks so the spec reads as the intended contract, not a working doc: - Rewrote the header (dropped "FIRST-CUT DRAFT", review-me framing). - Dropped the SMART-launch and StepKey OPEN comment blocks; the shapes now state the decisions plainly (BFF-side token exchange; human gates as first-class steps). - Trimmed draft-y rationale (bug-ticket refs, "verified vX", flattening NOTE). - info.version 0.1.0-draft -> 0.1.0. Open questions and talking points now live in the PR description: SMART exchange/ $summary location, the workflow human-gate work-item, and planning-brief provenance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The contract's human gates don't match the built pipeline; annotate honestly
rather than assert them as settled:
- review_brief maps onto the AUTOMATED brief_reviewer node; no human brief review
is specified in the design docs. Marked UNCONFIRMED.
- review_careplan is a real human step but today happens post-write (PUT
/careplans/{id}/status on the draft), not as an in-run pause.
- The awaiting_* RunStatus states model in-run pauses the SonataFlow workflow
does not implement.
- Care-plan approval is modeled twice (POST /runs/{id}/review/careplan vs PUT
/careplans/{id}/status); only one should survive.
These are design-review decisions, not resolved here — surfaced inline so the
contract stops implying an execution model that isn't built.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Brief review is automated, not a human step:
- Removed review_brief (StepKey), awaiting_brief_review (RunStatus), and brief
from ReviewGate (now [careplan] only).
- /runs/{id}/review/{gate} -> /runs/{id}/review/careplan (single gate).
- planningBrief demoted to informational (composed brief for display/read-back),
no longer a review gate; its shapes are reused by CarePlanView.
SMART token exchange and $summary read happen client-side:
- Removed POST /runs/smart-launch. The browser completes the SMART exchange and
the Patient/$summary read, then submits the IPS via POST /runs (single entry
point for upload and SMART). BFF never touches the SMART token or reads FHIR —
which also resolves the AGENTS.md "acp-writer does not query FHIR servers" tension.
Still open (design review): whether care-plan review is an in-run gate
(awaiting_careplan_review + POST /runs/{id}/review/careplan) or post-write
approval (PUT /careplans/{id}/status) — the two remain redundant for now.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…man#128 Care-plan provenance decision: ship the flattened BriefGoal/BriefActivity/ CarePlanView shape for the first cut. Extending it with structured provenance (targets, dose/route/frequency, source refs, DMN audit) is deferred to samschifman#128. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Meeting decided care-plan review is an in-run gate, not post-write approval:
- Removed the redundant PUT /careplans/{id}/status approval path.
- GET /careplans/{id} is now a read-only view of a persisted (already-approved)
plan; approval happens in-run via POST /runs/{id}/review/careplan.
- RunStatus.awaiting_careplan_review documented as a decided in-run gate needing a
ReviewCarePlan SonataFlow Callback state (backend work-item, samschifman#129), modeled on
the ingester's ReviewManifest/ReviewArtifacts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add reviewIteration + previousFeedback to RunDetail so the UI can show which care-plan review round it's on and the feedback given last round (mirrors the ingester's map_to_run_detail). - currentStep -> currentSteps (array) on RunSummary/RunDetail: the pipeline is not strictly linear (steps can run in parallel), so multiple can be active at once. - Remove the PlanningBrief schema and RunDetail.planningBrief (brief review is not a human step, per discussion). Renamed the shared item shapes BriefGoal/Activity/ Conflict -> PlanGoal/PlanActivity/PlanConflict since only CarePlanView uses them. - (smart-launch removal he flagged was already done when SMART went client-side.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pet/mock BFF that satisfies the PR samschifman#127 UI contract with canned data so the React UI (incl. the care-plan review loop) can be developed and demoed without the heavy pipeline. Mirrors the cpg-ingester BFF's optional-backend/mock pattern. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nine TDD tasks: contract models, in-memory store w/ clock-derived progression, canned data, mock router (8 endpoints), FastAPI app, local run, Containerfile, chart-pods wiring, cluster milestone. Model aliases pinned to the contract by a conformance test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d config, public now()
…, import-hygiene test, careplan ordering, frozen updatedAt
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
samschifman
approved these changes
Aug 20, 2026
khaledsulayman
marked this pull request as draft
August 25, 2026 15:36
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.
Summary
A mock Backend-for-Frontend for acp-writer that implements the finalized UI contract (
acp-writer/api/bff-openapi.yaml, #127) with canned, deterministically-progressing data. It lets the React UI — including the care-plan review loop — be developed, demoed, and deployed without the real pipeline (no SonataFlow / MinIO / LLM / DMN / FHIR). It mirrors the cpg-ingester BFF's optional-backend pattern and plugs into the deployment framework as thebffpod in mock mode.Motivation: the workflow (
acp-writer-workflow.yaml) has no human care-plan gate yet (that's the follow-up for aReviewCarePlanSonataFlow state), soawaiting_careplan_review— the centerpiece of the review UI — cannot be produced by the real backend today. The mock is the only way to exercise that UI now, and it doubles as a contract-conformance harness and a working skeleton for the real (SonataFlow-backed) BFF.What's included
services/bff_models.py— pydantic v2 models mirroring the contract (camelCase aliases); reusable by the real BFF.mocks/{store,data,router}.py— in-memory store with clock-derived step progression (no background threads), the 8 UI-facing endpoints, and canned hypertension data + a small FHIR bundle.services/bff.py— FastAPI app: mock mode whenSONATAFLOW_URLis unset; scoped CORS (not*);/health; a markedNotImplementedErrorstub for the real SonataFlow branch.awaiting_careplan_review(fullCarePlanView) → approve completes + persists a plan / request_changes loops withreviewIteration+previousFeedback; cancel; and a failed run (seed +ipsBundle.mockFailsentinel) so error UI can be exercised.deploy/pods/Containerfile.bff(UBI, slim) +chart-podsbffpod (mock mode) + UI→BFF NetworkPolicy so the two-pod (bff + ui) cluster demo works.dev_docs/.Flags surfaced for the team
ReviewCarePlanhuman gate (tracked as a follow-up); the mock stands in until it lands.StepKey.review_careplancomment still describes the removed post-writePUT /careplans/{id}/statuspath.Test plan
pytest— 28 passing (contract, store, api, boot, architecture)helm lint chart-pods— 0 failed;bff/uiNetworkPolicies renderpodman build+ container smoke —/health,/status, seed runs, create-run all serveacp-writer-bffimage,helm upgrade --installwith onlybff+ui, verify viaoc port-forward(manual milestone)🤖 Generated with Claude Code
Generated by Claude Code under the supervision of Khaled Sulayman