Skip to content

Add /cpa:product-review command - #78

Open
kristenoneill wants to merge 5 commits into
mainfrom
kon/cpa-product-review-command
Open

Add /cpa:product-review command#78
kristenoneill wants to merge 5 commits into
mainfrom
kon/cpa-product-review-command

Conversation

@kristenoneill

Copy link
Copy Markdown

Summary

Adds /cpa:product-review — a new command under canvas-plugin-assistant/commands/ that evaluates a plugin from a product perspective. Complementary to /cpa:security-review (engineering concerns); this one surfaces product judgments a human needs to make.

The command checks nine tenets:

  1. Clinical data model / USCDI V3 — flags CustomModels that restate data Canvas already has in its USCDI-backed native models.
  2. Placement — manifest scope must match intent (provider_menu_item / global / patient_specific / portal_menu_item).
  3. Coded data capture — flags string-based matching on clinical concepts; recommends SNOMED/LOINC/RxNorm/ICD-10/CVX/NUCC.
  4. Native Canvas primitives — CustomModels that should be Questionnaires, Tasks, Notes, Goals, Commands, CareTeamMembership, Organization/Location, etc.
  5. Alert fatigue — trigger scope, dismissibility, and blocking-vs-passive assessment for each interruption.
  6. Configurability — flags hardcoded clinical thresholds and code lists that should live in settings or content.
  7. Audit trail / attribution — flags writes that don't capture the actor and shadow-override patterns.
  8. Terminology consistency — Canvas vocabulary (Patient/Staff/Note/Command) and clinical code-system field naming.
  9. ONC certified-criteria overlap — cross-references plugin behavior against every §170.315 criterion Canvas is certified for; classifies overlaps as augment vs. replace, and flags replace-class overlaps HIGH for compliance risk.

The command writes a timestamped report to .cpa-workflow-artifacts/product-review-*.md and uses AskUserQuestion to route next steps. It explicitly does not auto-fix USCDI or ONC findings — always confirms first, because they touch the designated record set and compliance posture.

Also updates the workflow reference tables in wrap-up.md and security-review.md so the new command appears in the standard chain.

Test plan

  • Run /cpa:product-review against a plugin with a clean bill of health → verify ✅ PASS verdict
  • Run against a plugin with CustomModel fields that duplicate USCDI concepts → verify Tenet 1 flags with file:line references
  • Run against a plugin that sends referrals / transmits PHI externally → verify Tenet 9 flags ONC overlap as HIGH
  • Verify report is written to .cpa-workflow-artifacts/product-review-<timestamp>.md
  • Verify AskUserQuestion next-steps prompt appears after findings
  • Confirm the command does not silently mutate code for USCDI or ONC findings without confirmation

🤖 Generated with Claude Code

kristenoneill and others added 3 commits April 20, 2026 14:02
Evaluates plugins from a product perspective across nine tenets: USCDI V3
clinical data model alignment, placement conventions, coded data capture
(SNOMED/LOINC/RxNorm/ICD-10), use of native Canvas primitives over parallel
systems, alert fatigue, configurability of clinical logic, audit/attribution,
terminology consistency, and overlap with the §170.315 criteria Canvas is
ONC-certified for.

Writes a timestamped report to .cpa-workflow-artifacts/ and routes next
steps via AskUserQuestion. Does not auto-fix USCDI or ONC findings —
always confirms first, because they touch the designated record set and
compliance posture.

Wires the new command into the /cpa:security-review and /cpa:wrap-up
workflow references so it appears in the standard chain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Clarify that the §170.315(b)(11) CDS concern under Tenet 9 is about
plugin-authored clinical guidance (hardcoded titration schedules, default
thresholds, shipped code lists representing clinical opinions) — not
about plugins that surface fields users populate with their own clinical
content.

Adds a "plugin-authored vs. plugin-surfaced" classification with flag /
do-not-flag examples and a simple test: "if the plugin's shipped
content/defaults were removed, does any clinical opinion remain?" Notes
that moving defaults out of code (Tenet 6) often resolves the Tenet 9
concern as a side effect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expands the placement tenet to make two distinctions explicit:

1. provider_menu_item vs global — both live outside a patient chart, but
   provider_menu_item is for settings-ish work (configuration, catalog
   management, user preferences, admin actions) while global is for
   panel-level clinical activities (worklists, rollups, population
   dashboards). Quick test: does opening this UI show patient clinical
   data as its primary content? yes → global; no → provider_menu_item.

2. Mixed-scope applications (one app doing two jobs):
   - Patient-scoped apps with handlers that mutate non-patient state
     (catalog/template/preference CRUD behind a chart button) — split
     into a patient_specific action app and a provider_menu_item manager
     app.
   - Global-scoped apps whose every handler takes a patient_id and
     operates on one patient — move to patient_specific, or surface the
     one-patient drill-down as a distinct app linked from the panel.

Adds a "one app, one job" test: list each application's endpoints in
patient-specific vs. non-patient-specific columns; if both have entries,
the app should probably be split.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kristenoneill

Copy link
Copy Markdown
Author

@andhines - would love your eyes on this from a product perspective - anything I missed? I ran it against a handful of plugins to confirm it aligns with my general thinking. It might be overly sensitive in areas - but figure its better to flag/have a conversation.

@andhines

andhines commented Apr 21, 2026 via email

Copy link
Copy Markdown
Member

Two updates based on feedback:

1. Add the product-review skill under canvas-plugin-assistant/skills/.
   Mirrors the existing skill+command pattern (plugin-api-server-security,
   custom-data-patterns, etc.): the skill contains the nine tenets as
   coding-time rules that can be applied inline during plugin development;
   the /cpa:product-review command remains the end-to-end workflow with
   environment validation, report generation, and next-step routing.

   Skill structure:
   - SKILL.md — when to invoke, index of the nine tenets, relationship
     to other skills and the command, do-not-auto-fix boundary
   - product_review_context.txt — full tenet rules with detection
     heuristics, flag criteria, and priority order for inline
     application

2. Broaden Tenet 1 from "Clinical Data Model / USCDI V3" to
   "Designated Record Set / Clinical Data Model". USCDI V3 is the
   required subset; the DRS under HIPAA is broader and includes
   billing/encounter records, care coordination communications,
   authorizations/consents, utilization/case management, imported
   external data once incorporated, and patient-generated health data
   used for care decisions.

   Tenet 1 now includes:
   - The DRS test ("if it's used to make a decision about the patient,
     it belongs in the DRS")
   - The USCDI V3 table (existing, as the required subset)
   - A broader DRS categories table (new — billing, care coordination,
     authorizations, etc.)
   - An explicit excluded table (psychotherapy notes, QA/peer review,
     business planning, de-identified data, personal memory aids,
     litigation holds)
   - HIGH-priority flags for psychotherapy notes (escalate to
     Compliance — not DRS, not a regular Note either) and for
     parallel billing/claims paths

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kristenoneill

Copy link
Copy Markdown
Author

@andhines broadened to evaluate based on what is typically considered a part of the designated record set.

When it asked me skill vs command - the examples of the skills it gave as a reference/to differentiate didn't seem like parallels - but makes sense.

Distinguish between two concepts that were previously conflated:

1. Actor — who actually performed the action. Must be captured in
   Canvas's audit trail. For session-authenticated calls, the logged-in
   Staff; for API-key / service-account / webhook calls, the integration
   bot. Never silently attributed to a clinician who did not actually
   perform the action.

2. Routing / assignment — fields a caller supplies that name a clinician
   for business reasons (provider_id on a note, assignee on a task,
   prescriber_id on a carried-forward prescription). Legitimate for
   integrations to set — they tell Canvas "file this under Dr. X" but do
   not attest that Dr. X authored the content.

The distinction determines severity:

- NOT HIGH: API-key-authenticated endpoints that create or route records
  on behalf of a named clinician (bulk import, scheduling, CCM
  dashboards, task routing, unsigned note creation attributed to a
  provider), as long as the audit trail stamps the integration bot as
  the real actor. The customer is responsible for using such
  integrations only where real attestation is not required.

- HIGH: API-key-authenticated endpoints that trigger attestation events
  as a named clinician — electronic signing, signing-adjacent commits
  (push_charges, commit where Canvas treats it as clinician
  certification), and shadow-override patterns where displayed data is
  edited via side-channel metadata while the underlying record stays
  untouched.

- MEDIUM: CustomModel writes that capture no actor at all, missing
  Canvas-side audit for high-impact operations, API-key on PHI-bearing
  endpoints without a bot-stamped audit entry.

Golden patterns documented for both clinician-driven and
integration-driven flows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@aduane

aduane commented Apr 25, 2026

Copy link
Copy Markdown

Evaluation: ran the new tenets against 10 plugins in msf-canvas

Walked the proposed /cpa:product-review tenets through 10 plugins in msf-canvas by hand, simulating what the command would surface. Sample covered three provider-companion plugins (provider_register_patient_companion, provider_note_vitals_companion, provider_clinical_summary_companion) plus seven varied non-companion plugins (high-risk-medications, hcc_capture, custom-observation-management, chronic-care-management-activity-tracker, bmi_coding_automation, abstractive_health, claim_coding_agent).

Overall: the tenet structure is sound and produces the right calls on the strongest real findings (substring matching on med names, 1000-code inline ICD lists, API-key writes without staff session). Six suggestions below — most are framing/sharpening rather than structural changes.


1. Provider companion scopes are missing from Tenet 2's mapping table

The scope→surface table at commands/product-review.md:140-147 enumerates provider_menu_item / global / patient_specific / portal_menu_item, but the new 3-tier provider companion scopes (provider_companion_global, provider_companion_patient_specific, provider_companion_note_specific) aren't there. All three companion plugins in the sample use one of those scopes, so Tenet 2 produces an inconclusive or false-positive result on every modern companion plugin.

Suggested addition to the table:

Plugin purpose Scope UX surface
Provider mobile launcher (no patient/note context) provider_companion_global Provider companion home
Provider mobile patient view provider_companion_patient_specific Companion patient page
Provider mobile note view provider_companion_note_specific Companion note view

2. Tenet 7 detection has some false-positive risk worth softening

Tenet 7 (commands/product-review.md:299-345) actually has good nuance already — it distinguishes actor from routing, has a "Not a Tenet 7 flag" carve-out for routing-only API-key endpoints, etc. The risk is in the Detect heuristics at :309-317: greps over .save()/.create()/Effect/etc. will surface every native-effect emission, and a reviewer may read the surfaced grep hits as findings even though the rule's logic would clear them.

Rather than tightening the rule, the better posture is to encourage attribution where an actor is reachable:

  • For handlers extending StaffSessionAuthMixin, the staff is right there in the session — capture and pass it through to whatever the handler emits, even if the platform also stamps it.
  • For CronTask and other actor-less contexts, default to a canvas bot fallback until a plugin-specific fallback actor is available.

A line under the Detect block — "if the handler is StaffSessionAuthMixin and emits native Effects, the platform attributes the dispatching staff; do not flag merely because actor capture isn't visible in the source" — would help the reviewer interpret the grep hits correctly.

3. Add a "confirm-and-document" surfacer for cascade / auto-finalize patterns

Three plugins in the sample finalize clinical or billing writes from system-driven event handlers without a provider-driven trigger:

  • bmi_coding_automation/protocols/bmi_diagnosis.py:180,189originate() + commit() of Diagnose/UpdateDiagnosis on VITALS_COMMAND__POST_COMMIT
  • claim_coding_agent/protocols/agent.py:30-40AddBillingLineItem.apply() on PERFORM_COMMAND__POST_ORIGINATE
  • chronic_care_management_activity_tracker/handlers/ccmat_monthly_cron.py:236,272,316 — Note + Diagnose + billing emitted from a monthly cron

These aren't necessarily anti-patterns — sometimes "when action A happens, action B should also happen" is the desired design. But they're worth surfacing so the developer confirms intent and documents the cascade in the README. Suggested behavior: when the command sees a .commit() (or equivalent finalization) emitted from a system-driven event handler, surface as a "confirm-and-document" item rather than a HIGH finding.

4. Tenet 6 needs a clinical-content vs. UI-mechanics rubric

Tenet 6 (commands/product-review.md:277-296) currently says "hardcoded threshold → flag, hardcoded code list → flag." That works for clear-cut cases but produces noise on UI knobs that happen to be numeric.

From the sample:

  • Should flag: hcc_capture/protocols/condition_annotations.py:10-1090 (1000+ ICD-10 codes inline), bmi_coding_automation/protocols/bmi_diagnosis.py:80-131 (22 BMI bands), claim_coding_agent/protocols/agent.py:32-38 (hardcoded CPT 99213 + units + modifiers), chronic_care_management_activity_tracker/handlers/ccmat_monthly_cron.py:36,310-321 (CCM minute thresholds + CPT 99490/99439)
  • Borderline: 1-year DOB fuzzy-match window in register_patient_companion, patterns-via-secret in high-risk-medications
  • Should not flag: _VITALS_MAX_PANELS = 12 in clinical_summary_companion, 4-digit phone narrowing in register_patient_companion

Suggested rubric to add near the top of Tenet 6:

Flag a hardcoded value when it encodes a clinical, regulatory, or billing rule that a non-engineer would expect to be content/settings (CMS thresholds, code lists, medical-society cutoffs, billing rates). Don't flag UI mechanics or implementation knobs (page sizes, retry counts, polling intervals, fuzzy-match windows that are heuristics rather than clinical thresholds). When in doubt: would a clinician or biller want to change this without filing an engineering ticket?

5. Consider a manifest-accuracy tenet (or a Tenet 8 extension)

claim_coding_agent's manifest description reads "Example plugin using LLM inference to manage claim coding in real time" and declares OPENAI_SECRET_KEY as a required secret, but protocols/agent.py:23-24 instantiates LlmOpenai and never calls it — the plugin actually emits a hardcoded CPT 99213 with no LLM in the path. That's a real product issue (misleading description for installers, declared secret that isn't used) but no current tenet covers it.

Suggested addition (either under Tenet 8 or as a new small tenet):

Manifest accuracy. The plugin's manifest description should match its actual behavior. Flag when:

  • declared secrets are imported but never read
  • the description references a capability (LLM, external API, scheduled job) that the code doesn't exercise
  • declared components reference dead classes

6. Reference data duplicated between command and skill

The PR adds both commands/product-review.md (573 lines) and skills/product-review/product_review_context.txt (323 lines). Most of the bulk in the command file is reference data — USCDI/DRS tables (product-review.md:51-133), ONC criteria list (product-review.md:378-440) — and the skill exists specifically to hold the rule set as inline-applicable context. Two copies of the same reference data is a maintenance hazard (two places to update on the next ICD release / criterion change).

Suggested: trim the command file to the workflow steps (validate env, orient, walk tenets, generate report, route next steps) and reference the skill for the rule data — e.g., "See product-review skill context for the USCDI/DRS table." Keeps one source of truth for the rule definitions.


Happy to discuss any of these or open separate issues if it's easier to track. Items 1, 4, and 6 are the ones I'd flag as most likely to bite reviewers immediately; the others are sharpening.

@andhines

Copy link
Copy Markdown
Member

@kristenoneill I recommend updating https://github.com/canvas-medical/coding-agents/blob/main/canvas-plugin-assistant/CLAUDE.md to get the tenets broadly applied

@andhines

Copy link
Copy Markdown
Member

Further guidance, mostly from claude-code-guide, on the topic of integrating the skill into the plugin more broadly / cohesively:

Higher-leverage integration points

  In rough order of impact:                                                                                            
   
  1. The plugin-brainstorm agent's own .md file (highest leverage)                                                     
  Since agents are isolated, the agent definition itself needs to reference the product-review skill. Either embed a
  "before proposing data model or scope, apply Tenets 1, 2, 4, 9" instruction, or have the agent invoke the skill      
  explicitly during the planning dialogue.
                                                                                                                       
  2. The skill's own description: frontmatter                                                                          
  Skills auto-trigger based on description matching. The current description is good but trigger keywords could be
  strengthened — e.g. explicit phrases like "creating CustomModel", "declaring Application scope", "matching clinical  
  concepts" help Claude self-invoke without being told. This is the most "passive" integration: well-written
  descriptions mean the skill activates without anyone reminding Claude.                                               
                           
  3. Cross-references from related skills                                                                              
  plugin-patterns, custom-data-patterns, and canvas-sdk are loaded when their domains come up. A one-line pointer in
  each ("before finalizing custom data model, also apply product-review skill — Tenet 1") is more reliable than        
  CLAUDE.md because it fires in-context, when the relevant work is happening. The product-review SKILL.md already does
  the reverse (lines 44–49 reference these skills); the back-references are missing.                                   
                           
  4. Workflow commands (/new-plugin, /cpa:wrap-up, etc.)                                                               
  Commands have explicit step lists. /cpa:wrap-up is already named as the gating step in the skill. Verify /new-plugin
  and any scaffolding commands include a product-review checkpoint after the data model / manifest is drafted but      
  before code generation begins.
                                                                                                                       
  5. CLAUDE.md (your suggestion — still useful, just narrower)                                                         
  Best used for a short, specific reminder: "When planning new plugins or modifying CustomModels/AttributeHubs/manifest
   scope, invoke the product-review skill." Don't restate the tenets — that's the skill's job. CLAUDE.md should route  
  to the skill, not duplicate it.
                                                                                                                       
  6. Hooks (heavier-handed, optional)
  A PostToolUse hook on Write/Edit to CANVAS_MANIFEST.json or files matching *custom_model* could inject a system
  reminder to apply Tenets 1/2. Useful as a backstop but adds noise — only worth it if drift is a recurring problem.   
   
  The mental model to give the developer                                                                               
                           
  ▎ CLAUDE.md is the passive reminder layer — fine for routing. The real integration happens by (a) writing skill      
  ▎ descriptions that auto-trigger, (b) cross-referencing from neighboring skills so it surfaces in-context, and (c) 
  ▎ embedding the trigger into agents and commands that don't inherit project CLAUDE.md.                               
                           
  Best ROI: fix the plugin-brainstorm agent first (the planning blind spot), then add cross-references in              
  plugin-patterns and custom-data-patterns, then the targeted CLAUDE.md line.

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.

3 participants