Admin Portal Trio — Consistency Reconciliation Findings¶
Status: REVIEW 2026-05-12 Owner: SD (CPO/CTO) Scope: Cross-reference reconciliation pass across three Phase-B admin-portal draft specs: - PR #857 —
docs/specs/procedure-onboarding-admin-ui.md(branchdocs/procedure-onboarding-admin-ui-spec) — 484 lines, ~25 agent-days - PR #868 —docs/specs/provider-onboarding-admin-ui.md(branchdocs/provider-onboarding-admin-ui-spec) — 572 lines, ~24.5 agent-days - PR #869 —docs/specs/capabilities-and-readiness-scoring.md(branchdocs/capabilities-readiness-spec) — 738 lines, ~24-30 agent-days Method: read each spec in full, build a cross-reference matrix on data-model deltas / endpoints / events / permissions / PR sequencing / open questions / validation rules / MVP scope, then surface conflicts and overlaps. References: - All three sibling specs above -docs/specs/admin-portal-users-tenants-feature.md— Phase A pattern reference all three siblings extend - ADR-0018 §A, §H, §J, §K, §M, Amendment "Admin Console Operational Screens" - ADR-0026 — parameter registry -.claude/rules/definition-of-done.md— migration head sequencing + parallel-safe partitioning rule
1. Summary¶
Total findings: 22. Split:
| Severity | Count | Description |
|---|---|---|
| Major (blocking) | 4 | Same table / endpoint / event-type claimed by two specs — must resolve before any of the three lands |
| Moderate (rework recommended) | 9 | Cross-reference errors, PR-sequencing dependencies missing, scope-overlap that wastes effort if not deduped |
| Minor (nits / tightening) | 9 | Typos, missing back-references, redundant phrasing, dedupe-able open questions |
Applied inline (in this branch): 6 (cross-reference + typo-level fixes that need no SD judgment). Flagged for SD: 16 (architectural ownership calls, PR-sequencing reshuffles, open-question consolidation).
Consolidated SD question list (deduped): 12 open questions (down from 25 distinct entries across the three specs).
Recommended unified PR roadmap: 17 PRs interleaved in dependency order over 6-7 calendar weeks with parallel dispatch.
Effort estimate (re-estimated with shared infrastructure): ~67-70 agent-days vs naive 80-day sum — savings of ~10-13 agent-days (~13-16%) from dedupe + shared component reuse.
2. Findings¶
2.1 Data model overlap & contracts¶
FINDING #1 — MAJOR: provider_capabilities + procedure_capability_requirements claimed by both #857 and #869.
- #857 §3.2 Delta C defines and creates both tables with full DDL (UNIQUE constraints, ENUMs, columns).
- #869 §3.1 + §3.2 also defines and creates the same two tables — and adds richer columns (
is_stale,staleness_reason). - Resolution: #869 is the canonical owner (it's the dedicated capabilities spec). #857 must drop Delta C entirely and reference #869 §3.1/§3.2 as the source. #857 PR-2's table creation step becomes "wire UI to existing capabilities endpoints from #869 PR-D".
- Impact: prevents a migration-head collision (two specs creating the same
provider_capabilitiestable). Saves ~1-2 agent-days from #857 PR-2.
FINDING #2 — MAJOR: provider_procedures.readiness_score column ownership ambiguous.
- #857 Delta B adds
readiness_score+readiness_score_computed_atcolumns toprovider_procedures. - #869 §5.5 says: "The score is persisted on
provider_procedures.readiness_score(column added by PR #857 Delta B)." - Resolution: ownership is clear (#857 lands the column, #869 lands the algorithm). But this creates a hard sequencing dependency: #869 PR-C cannot land before #857 PR-1. Both specs should explicitly state this. Applied inline to #869 §10 PR-C dependency line and #857 §9.1 MVP scope note.
FINDING #3 — MODERATE: acceptance_criteria JSONB column on provider_procedures is in #857 Delta B but acceptance criteria tab is reused by #868 (procedure offerings axis flipped). Cross-reference missing.
-
857 §5.4 FacilityReadinessSheet tab 3 = Acceptance criteria editor.¶
-
868 §5.4 Tab 3 says "reuses the FacilityReadinessSheet from procedure spec §5.4 rendered with axis flipped" — so the same JSONB editor must work in both contexts. No conflict in data, but the cross-reference back to #857 Delta B should be explicit.¶
- Applied inline: added a clarifying note in #868 §3.1 referencing #857 Delta B's
acceptance_criteriacolumn.
FINDING #4 — MINOR: #869 §3.1 ENUM names use capability_* prefix; #857 §3.2 inline ENUM names (in the DDL block) do not.
-
869 uses
capability_category,capability_status,capability_verification_source,capability_criticality.¶ -
857 Delta C DDL uses bare
ENUM('diagnostic','operational','logistical')inline without naming the type.¶ - Since #857 Delta C is being dropped (finding #1), this resolves naturally. No action.
2.2 Endpoint overlap¶
FINDING #5 — MAJOR: GET / PUT / DELETE /api/v1/admin/providers/{provider_id}/capabilities/{capability_code} claimed by both #857 and #869.
- #857 §4.3 lists all three endpoints under "Provider capability endpoints (new, but ADR-0018 §J also needs them for the provider portal — coordinate)".
- #869 §7.2 lists the same three endpoints. #869 explicitly states: "The endpoints PR #857 §4.3 declares need to actually exist. This spec's PRs deliver [these]."
- Resolution: #869 PR-D ships these endpoints. #857 should mark §4.3 as "endpoints consumed from #869 PR-D, not delivered here." Applied inline as a clarifying note at top of #857 §4.3.
FINDING #6 — MODERATE: POST /api/v1/admin/procedures/{code}/facilities/{provider_id}/recompute-readiness in #857 §4.2 — algorithm lives in #869.
-
857 §4.2 declares the endpoint that triggers recompute.¶
-
869 §5.5 owns the recompute logic + the background task.¶
- Resolution: the endpoint can be defined in either, but it must call into the
readiness_scoring.pymodule that #869 PR-C ships. Recommend moving the endpoint definition to #869 PR-D (alongside the other admin capability endpoints) and have #857's UI call it. Flagged for SD.
FINDING #7 — MINOR: GET /api/v1/admin/procedures/{procedure_code}/facilities (#857 §4.2) vs GET /api/v1/admin/providers/{provider_id}/procedures (#868 §4.2) return the same provider_procedures join with different axes.
- Both endpoints are needed (different UI surfaces). No conflict. Apply inline: add a cross-reference in #868 §4.2 noting axis-flip parity with #857. Applied inline.
FINDING #8 — MODERATE: Bulk-import endpoints are independently spec'd in #857 (procedures) and #868 (providers).
- Paths differ (
/admin/procedures/bulk-importvs/admin/providers/bulk-import). No conflict. - Both follow the same dry-run / transactional pattern. Recommend factoring out a shared
BulkImportService(one inapp/services/admin/bulk_import.py) that both specs' PRs depend on. Saves ~1 agent-day. Flagged for SD.
2.3 Workflow integration¶
FINDING #9 — MODERATE: #868 wizard step 5 (Procedures) writes to provider_procedures — requires #857 PR-1's provider_procedure_admin_service.
-
868 §9.1 says "Procedure-link CRUD (read-only initially — write side is in procedure spec PR-1)". Good — explicit dependency call-out.¶
- But #868 §6.1 step 5 says "N rows in
provider_procedures(cost min/avg/max, currency, success_rate, annual_volume, lead_surgeon)". This is a write. Either: - (a) #868 PR-1 MVP defers procedure-link writes to follow-up (and step 5 is "linking only", with cost/volume edited via #857's UI after-the-fact), or
- (b) #868 PR-1 MVP depends on #857 PR-1 having landed.
- Recommend (a): decouple #868 PR-1 from #857 PR-1. Wizard step 5 becomes "pick procedures from catalog (autocomplete)"; the readiness inputs (cost, volume) are filled in later via the procedure-detail page after provider activation. Applied inline as a clarifying note in #868 §6.1 step 5.
FINDING #10 — MINOR: #868 §5.4 Tab 3 "reuses the FacilityReadinessSheet from procedure spec §5.4" — but #857 owns the React component code.
- Coordination needed at impl time: the component path (
apps/admin-app/src/components/FacilityReadinessSheet.tsxor similar) should be agreed upfront so both specs' implementers don't fork. Flagged for SD (file-naming convention is an impl detail but worth pinning now).
2.4 PR sequencing¶
FINDING #11 — MAJOR: Hidden dependency cycle if naively sequenced.
-
857 PR-1 MVP creates
readiness_scorecolumn → unblocks #869 PR-C.¶ -
869 PR-A creates
provider_capabilities+procedure_capability_requirementstables → unblocks #857 PR-2.¶ -
869 PR-D ships the admin capability endpoints → unblocks #857 PR-2's UI panel.¶
- Resolution: unified roadmap (§4 below). No actual cycle if ordered correctly, but the three specs in isolation each present their PR plan without acknowledging the others' sequencing constraints.
FINDING #12 — MODERATE: #857 §9.2 PR-2 says "create provider_capabilities + procedure_capability_requirements tables + capability UI panel + readiness-score-recompute background task" — but all three of those non-UI items belong to #869.
- Resolution: #857 PR-2 scope shrinks to "wire admin UI to capability endpoints from #869 PR-D" (~2 agent-days instead of 5-6). Applied inline to #857 §9.2 PR-2 row.
2.5 Open SD questions — duplicates¶
FINDING #13 — MODERATE: 25 open questions across three specs reduce to 12 distinct decisions. See §3 below for the deduped list.
2.6 Estimated implementation sizes¶
FINDING #14 — MODERATE: Naive sum is 25+24.5+27 = ~76.5 agent-days; real total with shared infra is ~67-70 agent-days (savings of ~10-13%). See §6 below for breakdown.
2.7 Permission model consistency¶
FINDING #15 — MINOR: Permissions across the trio use consistent resource:verb namespace but have one shared permission (provider_procedure:write) defined in two places.
-
857 §9.1 seeds
provider_procedure:write.¶ -
868 §9.1 also seeds
provider_procedure:write("shared with procedure spec").¶ - Resolution: Whichever PR lands first owns the seed. Recommend the unified roadmap puts #857 PR-1 (or #869 PR-D) as the canonical seeder; #868 PR-1 references but does not re-seed. Applied inline as a clarifying note in #868 §9.1.
FINDING #16 — MINOR: admin:force permission referenced across all three specs but never formally introduced in this trio.
- Existing in the codebase per
admin-portal-users-tenants-feature.mdPhase A. No action needed — pre-existing.
2.8 Event types¶
FINDING #17 — MAJOR: ADMIN_PROVIDER_CAPABILITY_UPDATED defined in both #857 §3.3 and #869 §3.8.
-
857 §3.3 lists it singular.¶
-
869 §3.8 lists
ADMIN_PROVIDER_CAPABILITY_CREATED,_UPDATED,_DELETED,_REVERIFIED(richer set).¶ - Resolution: #869 owns. #857 should remove the line (capability events emitted by the endpoints #869 PR-D ships). Applied inline to #857 §3.3.
FINDING #18 — MINOR: ADMIN_PROVIDER_PROCEDURE_UPDATED defined in #857 §3.3 (cell-level inline edit) and #868 §3.3 (ADMIN_PROVIDER_PROCEDURE_LINKED|UNLINKED).
- These are complementary, not duplicates: #857 owns cell edits (cost, volume changes), #868 owns linking/unlinking a procedure to a provider. No conflict. Cross-reference added inline to #868 §3.3 noting the split. Applied inline.
2.9 Validation rules¶
FINDING #19 — MODERATE: Readiness score computation is described in two places with consistent but not identical wording.
-
857 §8 says "When admin saves a cell,
readiness_scorerecomputed and persisted (input: own row fields + linkedprovider_capabilities+procedure_capability_requirements)" — informal.¶ -
869 §5 is the formal algorithm.¶
- Resolution: #857 §8 should explicitly reference #869 §5 as the normative algorithm. Applied inline.
FINDING #20 — MINOR: Currency / cost validation is duplicated (#857 §7.1, §7.2 and #868 §7.1, §7.2).
- Same rules in both specs — no conflict but redundant. No action — acceptable redundancy for spec readability.
2.10 MVP scope alignment¶
FINDING #21 — MODERATE: All three MVPs can ship in parallel only if the data-model deltas are sequenced.
-
869 PR-A (capabilities tables) is the keystone — should land first.¶
- After PR-A: #857 PR-1 and #868 PR-1 can run in parallel (disjoint schema touches: procedure_requirements/provider_procedures vs providers/contact_persons/accreditations).
-
869 PR-C (scoring) requires #857 PR-1 to have landed (readiness_score column).¶
- Roadmap §4 sequences this explicitly.
FINDING #22 — MINOR: Feature flags are spec'd inconsistently.
-
857 §12 names
procedure_admin_ui_enabled.¶ -
868 §12 names
provider_onboarding_admin_ui_enabled.¶ -
869 §13 names
readiness_scoring_weights_v1,readiness_critical_gap_disqualifies,capability_reverification_email_enabled.¶ - All follow
feedback_flagsmith_dual_envrule (both envs together). No conflict. No action.
3. Consolidated SD Question List (ranked by impact)¶
After dedupe across the three specs, 12 distinct decisions remain. Ranked high → low impact.
| # | Question | Sources | Default in specs | Impact |
|---|---|---|---|---|
| Q1 | Capability vocabulary management — YAML + redeploy, or in-app CRUD page in PR-A? | #857 §11.7, #869 §12.1 | YAML in MVP, in-app deferred to PR-4 | Shapes #869 PR-A scope + #857 follow-up |
| Q2 | Self-service onboarding scope — admin-only for v1? | #857 §11.5, #868 §11.2 | Admin-only confirmed | Sets Phase 2 boundary |
| Q3 | Approve vs activate split — separate or one-click? | #868 §11.1 | Separate (two buttons) | Changes wizard step 6 UX |
| Q4 | Bulk import permission gate — super_admin only, and does it skip review? | #857 §11.4, #868 §11.5 | super_admin only; #868 skips review, #857 doesn't apply | Affects 2 PRs (one each spec) |
| Q5 | Hard-disqualify on critical capability gap — opt-in Flagsmith flag, default off? | #869 §12.6 | Soft penalty default | Matching engine policy |
| Q6 | Readiness weight distribution — 40/35/25 fixed or procedure-category-conditional? | #869 §12.3 | 40/35/25 from ADR-0018 §J | Algorithm parameter |
| Q7 | Multi-facility scoping — capabilities on provider_id or facility_id? |
#869 §12.4 | provider_id (1:1 today) |
Migration design |
| Q8 | Synchronous vs async Neo4j sync on admin writes? | #857 §11.8, #869 §4.2 | Synchronous | Latency vs durability tradeoff |
| Q9 | Document upload (R2-presigned-URL) in PR-1 or PR-2? | #868 §11.3 | PR-2 | +2 agent-days if PR-1 |
| Q10 | Procedure versioning — MVP needs it? | #857 §11.1 | No (mutable in place + audit log) | Schema impact if yes |
| Q11 | Patient-reported capability discrepancy UI — PR-E or separate spec? | #869 §12.7 | PR-E unclear | Patient-facing scope |
| Q12 | Staleness reminder email — opt-in flag, default off? | #869 §12.8 | OFF (ops-driven v1) | Ops workflow |
Removed/merged (no longer distinct):
- "platform_admin vs super_admin" — covered by Q4 (per-permission decision, not global)
- "Currency handling" (#857 §11.6) — covered by CLAUDE.md "All money in USD cents + ISO 4217" rule; no decision needed
- "Admin override on patient_satisfaction" (#868 §11.7) — left as-is (read-only in MVP)
- "Onboarding-status visibility on storefront" (#868 §11.8) — answered (hidden until activated)
- "Capability vocabulary size 45-60" (#869 §12.2) — implementation detail
- "Doctor onboarding inside wizard" (#868 §11.6) — answered (callout-only in MVP)
- "Capability name denormalization" (#869 §12.5) — implementation detail
- "Recovery-flow capability reuse" (#869 §12.9) — deferred, no decision needed
- "Minimum procedure count at submit" (#868 §11.4) — implementation detail, default acceptable
- "Tenant-scoped vs global procedure catalog" (#857 §11.2) — answered (global, matches today's shape)
- "Who can edit readiness scores" (#857 §11.3) — answered by permission spec
- "Provider self-edit pathway" (#857 §11.5) — subsumed by Q2
- "Capabilities scope split MVP vs PR-2" (#857 §11.7) — answered by Finding #1 resolution
4. Recommended Unified PR Roadmap (17 PRs over 6-7 weeks)¶
Dependency-ordered. Calendar at 1.5-2 agent-days per calendar-day with parallel dispatch.
WEEK 1
PR-869-A Capabilities data model + repos + YAML vocabulary (4-5 d) [keystone]
WEEK 2 (3 chains parallel)
PR-857-1 Procedure onboarding MVP — admin UI + procedure_requirements/provider_procedures Deltas A+B (incl readiness_score column) (10 d, BE+FE split)
PR-868-1 Provider onboarding MVP — wizard + lifecycle + provider_accreditations/contact_persons (11 d, BE+FE split)
PR-869-B Neo4j projection helpers + sync endpoint (3 d)
PR-869-F Annual staleness cron (#711) (2-3 d)
WEEK 3
(PR-857-1 and PR-868-1 complete; merge in dependency order)
PR-869-D Admin capability endpoints + perms (4 d)
PR-869-C Readiness scoring + matching wiring (5-6 d) [requires PR-857-1 Delta B]
WEEK 4
PR-857-2 Wire capability UI panel to PR-869-D endpoints (~2 d, reduced from spec estimate)
PR-868-2 Document upload (R2 presigned URLs) (4-5 d)
PR-869-E Patient-facing readiness panel (5-6 d) [requires PR-869-C]
WEEK 5
PR-857-3 Procedure bulk import (3-4 d)
PR-868-3 Recovery-provider variant tab (3-4 d)
PR-857-4 Capability vocabulary management page (2-3 d) [resolves Q1 if SD picks in-app]
WEEK 6
PR-857-5 Procedure history viewer (1-2 d)
PR-857-6 Recompute all readiness button (1-2 d)
PR-868-4 Provider bulk import (3-4 d) [reuses BulkImportService from PR-857-3 — see Finding #8]
PR-868-5 Provider history viewer (1-2 d)
WEEK 7
PR-868-6 Onboarding progress dashboard + Telegram alerts (1-2 d)
Total: 17 PRs over ~6-7 calendar weeks (vs the ~9-11 weeks naive sum if each spec ran serial).
Critical-path PRs (block downstream work): - PR-869-A blocks PR-869-B, PR-869-C, PR-869-D, PR-869-F, PR-857-2 - PR-857-1 blocks PR-869-C, PR-857-2 through PR-857-6 - PR-868-1 blocks PR-868-2 through PR-868-6 - PR-869-C blocks PR-869-E
True-parallel opportunities (zero shared file conflicts): - Week 2 chains (857-1, 868-1, 869-B, 869-F) all touch disjoint files. Run in 4 separate worktrees. - Week 4 (857-2, 868-2, 869-E) — disjoint. - Week 5 (857-3, 868-3, 857-4) — disjoint.
Migration head sequencing (per .claude/rules/definition-of-done.md):
- PR-869-A introduces ENUMs + 2 tables (one migration head).
- PR-857-1 introduces Deltas A + B columns (one migration head, rebases on 869-A).
- PR-868-1 introduces Deltas A + B + C + D + tables (one migration head, rebases on 857-1).
- Subsequent PRs have at most one migration each; rebase on landing-time head.
5. Recommended Edits Per Spec¶
5.1 #857 (docs/specs/procedure-onboarding-admin-ui.md)¶
| Section | Edit | Type |
|---|---|---|
| §3.2 Delta C | Drop the inline DDL for provider_capabilities and procedure_capability_requirements. Replace with a cross-reference: "Tables created by #869 PR-A — see capabilities-and-readiness-scoring.md §3.1 and §3.2." |
Applied inline |
| §3.3 | Remove ADMIN_PROVIDER_CAPABILITY_UPDATED (owned by #869) |
Applied inline |
| §4.3 | Add note: "Endpoints consumed from #869 PR-D, not delivered in this spec." | Applied inline |
| §8 | Reference #869 §5 as normative for readiness algorithm | Applied inline |
| §9.2 PR-2 row | Scope shrinks from "create tables + UI panel + recompute task" to "wire admin UI to capability endpoints from #869 PR-D". Reduce estimate from 5-6 to ~2 agent-days. | Applied inline |
| §11 (open questions) | Q11.2 (tenant-scoped catalog), Q11.3 (who edits readiness), Q11.7 (capabilities scope split), Q11.5 (provider self-edit) — note they're resolved by the consolidation pass | Flagged for SD |
5.2 #868 (docs/specs/provider-onboarding-admin-ui.md)¶
| Section | Edit | Type |
|---|---|---|
| §3.1 | Add cross-reference: "provider_procedures.acceptance_criteria column defined by #857 Delta B." |
Applied inline |
| §3.3 | Add note clarifying split with #857: "#857 owns ADMIN_PROVIDER_PROCEDURE_UPDATED (cell-level), this spec owns _LINKED/_UNLINKED (relation-level)." |
Applied inline |
| §4.2 | Add cross-reference to #857 §4.2: "Axis-flipped twin of GET /api/v1/admin/procedures/{procedure_code}/facilities — same join, different lead axis." |
Applied inline |
| §6.1 step 5 | Clarify: "Procedure linking only in PR-1 MVP — cost/volume readiness data edited via #857's FacilityReadinessSheet after provider activation." |
Applied inline |
| §9.1 | Note: provider_procedure:write permission seeded by #857 PR-1, not re-seeded here. |
Applied inline |
| §11.2 | Subsumed by consolidated Q2 — note resolution | Flagged for SD |
| §11.5 | Bulk import skip-review default — confirm with consolidated Q4 | Flagged for SD |
5.3 #869 (docs/specs/capabilities-and-readiness-scoring.md)¶
| Section | Edit | Type |
|---|---|---|
| §5.5 | Reaffirm hard dependency: "Requires provider_procedures.readiness_score column landed by #857 PR-1 Delta B; PR-C cannot land before #857 PR-1." |
Applied inline |
| §7.2 | Strengthen ownership claim: "These endpoints replace #857 §4.3's placeholders — PR-D delivers them; PR #857's UI consumes them." | Applied inline |
| §10 PR-C row | Add explicit dependency on #857 PR-1 (already noted but tighten) | Applied inline |
| §12.1 | Subsumed by consolidated Q1 — note | Flagged for SD |
| §12.6 | Subsumed by consolidated Q5 — note | Flagged for SD |
6. Effort Re-estimate¶
| Spec | Standalone (per its §10) | Adjusted with dedupe | Δ |
|---|---|---|---|
| #857 | 25 agent-days | 21-22 (PR-2 shrinks from 5-6 to ~2; Delta C migration dropped) | -3 to -4 d |
| #868 | 24.5 agent-days | 22 (procedure-link write deferred; shared BulkImportService) | -2 to -3 d |
| #869 | 24-30 agent-days | 24-30 (no change — already keystone) | 0 |
| Cross-cutting savings | — | -3 to -4 (shared FacilityReadinessSheet component + shared BulkImportService + shared audit pattern + shared permission seeding) |
-3 to -4 d |
| Total | ~73.5 - 79.5 (naive sum: ~76.5) | ~67-70 | -7 to -10 d (~10-13% savings) |
Calendar: at 1.5-2 agent-days/calendar-day with the 17-PR parallel dispatch plan in §4, total elapsed time is ~6-7 weeks end-to-end, vs ~9-11 weeks naive serial.
Confidence: ±2 agent-days per spec. The savings depend on: 1. SD approving Finding #1 resolution (drop #857 Delta C) — high confidence 2. Finding #8 shared BulkImportService — medium confidence (impl team must agree) 3. Finding #10 shared FacilityReadinessSheet component — medium confidence (component contract needs upfront pinning)
7. Recommended Review Order for SD¶
- This findings doc first — it provides context for the three sibling PRs.
- Then #869 (the keystone capabilities spec) — it owns the data model the other two consume.
- Then #857 (procedure onboarding) — it adds the
readiness_scorecolumn #869 PR-C needs. - Then #868 (provider onboarding) — it consumes both.
Approve Findings #1, #2, #5, #11, #17 (the 5 majors) before greenlighting any sibling PR to merge.
Last updated: 2026-05-12 — REVIEW awaiting SD approval.