🛠️ Creating or Updating a Protocol
This guide walks you through the complete process of creating a new protocol or updating an existing one for problem state management.
1. Define or update the Protocol
Create or update a protocol following the Protocol Definition guidelines.
Location: Create your protocol JSON file in the following GitHub location:
🔗 arc-api/modules/care_management/problems/app/models/problems/protocol_definitions/
Example: See the Eye Health Concerns protocol:
📄 eye_health_concerns.json
Ensure all required data fetchers exist, or create any missing ones.
📋 Protocol Workflow Example: Eye Health Concerns
Initial State: "assess"
When a new Eye Health Concerns problem is created:
- Default state:
assess
(marked asinitial: true
) - Automatic intervention creation: Creates a
CoordinateEyeCare
intervention - Assignment: Goes to the ECM Care Manager team (
role: "ecm_cm"
) - Due date: 1 week from creation (
due_date: "1.week"
) - Deduplication: Prevents duplicate interventions with the same key
Transition Rule: assess → completed
The protocol automatically transitions from "assess" to "completed" when:
"rule": {
"type": "condition",
"parameter": {
"key": "most_recent_completed_intervention",
"args": {
"intervention_types": ["Ecm::Interventions::CoordinateEyeCare"],
"since_last_state_transition": true
}
},
"operator": "eq",
"value": "Ecm::Interventions::CoordinateEyeCare"
}
What the Rule Does
This rule checks if:
- Most recent completed intervention is of type
Ecm::Interventions::CoordinateEyeCare
- Since last state transition (
since_last_state_transition: true
) - only looks at interventions completed after the problem entered the current state - Exact match (
operator: "eq"
) - the intervention type must exactly equalEcm::Interventions::CoordinateEyeCare
Fetcher Connection
The most_recent_completed_intervention
parameter connects to a fetcher that:
- Queries the system for completed interventions
- Filters by the specified intervention types
- Returns only interventions completed since the last state transition
- Provides the most recent one for evaluation
Complete Flow
- Problem created → Enters "assess" state
- Intervention assigned → CM team gets CoordinateEyeCare task (due in 1 week)
- CM completes intervention → Marks eye care coordination as complete
- Automatic transition → Problem moves to "completed" state
- Problem closed → Workflow ends
2. Enable the Problem Type
Before your protocol can be used, you need to enable it in two configuration locations:
A. Add to Protocol Rollout Config
Add the problem type to the desired Care Pod in:
APP_CONFIG.ProblemStates.ProtocolRolloutConfig
Configuration Sources:
- Local Development: Configure in your
local_params.yml
file - Remote Environments: This configuration gets overridden using AWS Parameter Store (No Flipper feature flag)
Why this is needed:
The ProtocolRolloutConfig
is a feature flag system that controls which Care Pods have access to specific medical protocols for different health problems.
How Protocol Rollout Configuration Works
Care Pod Control
The groups
array in the config represents different Care Pods that can have customized protocol access.
Problem-Based Protocols
Each health problem in ALLOWED_PROBLEMS
can have its own care protocol with states, transitions, and workflows.
Gradual Rollout
Instead of enabling new protocols for all Care Pods at once, you can roll them out gradually.
⚠️ Disclaimer: The configuration example below might be outdated. Please ask a team member to share their current local configuration to ensure you are using the latest settings.
ProblemStates:
ProtocolRolloutConfig: '{
"all": {
"enabledProblems": [
"housing",
"depression",
"type_one_diabetes",
"type_two_diabetes",
"food_insecurity",
"transportation_insecurity",
"inadequate_housing",
"financial_insecurity",
"high_blood_pressure",
"wellness_visit",
"cervical_cancer_screening"
]
},
"groups": [
{
"carepods": [
{
"id": "7b816b54-e2f4-4908-80fa-fcb20c319539",
"name": "Pod C"
},
{
"id": "c0cbb869-ee45-433f-9d2c-1adf0cd4f2ba",
"name": "Pod D"
}
],
"enabledProblems": [
"social_isolation",
"oral_health_concerns",
"preventative_dental_care",
"eye_health_concerns"
]
}
]
}'
- "all": All Care Pods receive the protocols listed in
enabledProblems
under "all", regardless of whether thegroups
array is empty.
B. Add to Allowed Problems List
Add to:
Problems::ProblemProtocol::ALLOWED_PROBLEMS
File Reference: problem_protocol.rb#L8
Why this is needed
-
Business Logic: This validation ensures that only approved problem types can be created as
ProblemProtocol
records. Any problem value that isn't in theALLOWED_PROBLEMS
list will be rejected. -
Data Integrity: By maintaining this whitelist, the application prevents invalid or unsupported problem types from being stored in the database.
What happens without this?
If new_protocol
is not in the ALLOWED_PROBLEMS
array, any attempt to create a ProblemProtocol
with problem: 'new_protocol'
would fail validation and raise an error in the following step (Step 3: Sync the Protocol to the Database).
3. Sync the Protocol to the Database
Protocol Installation Process
The SyncProblemProtocolsJob
serves as the installation mechanism for protocols. When you run the job, it creates a new database record that "installs" the protocol definition into the active system.
Problems::SyncProblemProtocolsJob.perform_now("depression")
How Protocol Installation Works
When ProblemProtocol.update_protocol("eye_health_concerns")
is called, it:
- Reads the protocol definition from the file system
- Creates a new database record with the protocol configuration
- Assigns a version number (incremented from previous versions)
- Stores the complete definition as structured data
The Installed Protocol Record
The example shows an installed "eye_health_concerns" protocol:
#<Problems::ProblemProtocol:0x000000015abf12c8
id: "168a06dd-5539-488b-8b9d-0b3a781b614a",
problem: "eye_health_concerns",
version: 2, # <- Version tracking for changes
definition: {
# Complete protocol workflow definition
"states" => [...],
"transitions" => [...]
},
definition_hash: "0f8a576c57b0c8359895f249c1f4873c", # <- Content fingerprint
created_at: "2025-08-12 09:06:14.498835000 -0700",
updated_at: "2025-08-12 09:06:14.498835000 -0700"
>
Installation Flow: File Definition → SyncJob → Database Record → Active Protocol
After this, new problem goals of this type will be automatically evaluated and linked to the protocol.
4. Link Existing Problems to the Protocol
Existing problems won't be linked to the new protocol version automatically (we are linking the problem goal with the specific protocol in problem_goal.state.problem_protocol_id
). To link existing problems to the new version of the protocol, run the evaluator job:
protocol = Problems::ProblemProtocol.current_protocol('depression')
Problems::ProblemProtocolEvaluatorJob.perform_now(protocol, skip_interventions:true, dry_run: false)
Note: For local development, it is recommended to use the Rails console to link existing problems to the protocol. For DEV and PROD environments, please use the rake task described in Step 4: Backfill Existing Problems to ensure proper backfilling and auditing.
What this job does
- Finds all existing problem goals of the specified type
- Links them to the current protocol version by setting
problem_goal.state.problem_protocol_id
- Evaluates each problem against the protocol rules and transitions them to the appropriate state
- Creates any required interventions based on the protocol definition
Note: The dry_run: true
parameter is primarily useful for production environments to validate changes before applying them. For local development and testing, run with dry_run: false
to perform the actual linking. See the deployment and release documentation for production deployment procedures.
5. Completion
At this point:
- The protocol is stored in your local database
- Existing problems of that type are linked to the protocol
- All new problems of the same type will be evaluated and linked on creation
📝 Note: This process updates your local environment only. To deploy protocol changes to higher environments (dev and production), refer to the environment switching documentation for proper deployment procedures.
6. Relative/Optional
Some problems have interventions created when the problem is started. In those cases, we want to block those so that automatic intervention creation only happens through the protocol. In order to do that, we can add an early return in the initial_interventions
method in the problem's model class, based on the Guardian. For example, for type_one_diabetes
:
def initial_interventions
return [] if Problems::Guardian.allowed_to_continue?(problem)
Flipper.enabled?(:care_gaps_automations) ? [monitor_vitals, coordinate_pair_team_appointment] : [custom]
end
7. Testing
You can now create a problem goal of that type for a patient in an enabled care pod (look at APP_CONFIG.ProblemStates.ProtocolRolloutConfig
to see the enabled care pods), either manually or by a trigger (e.g. completing a PHQ9 with depression indications will create a depression problem). The new problem should have a state assigned to it on creation. Every problem goal with a state will display the state dropdown on the careplan, while problem goals with no state will display the state chip/dropdown (depending on current status).
8. Rollout to Dev and Production Environments
In order to release this protocol to lower environments, it's important to perform the following steps:
Dev Environment Rollout
Step 1: Update AWS Parameter Store
- Navigate to AWS Systems Manager → Parameter Store
- Locate the parameter:
/Dev/RailsApi/ProblemStates/ProtocolRolloutConfig
- Update the value to include your new protocol in the enabled problems list
Step 2: Force ECS Deployment
After updating the parameter value, force an ECS deployment to apply the configuration changes:
📄 Follow the ECS Deployments documentation for detailed deployment instructions.
Step 3: Sync the Protocol to the Database
- Connect to the bastion host as described in the Bastion documentation for your target environment (dev or prod) and start the Rails console.
- Follow the instructions in Section 3: Sync the Protocol to the Database to sync the protocol to the database in dev environment.
Step 4: Backfill Existing Problems
Run the backfill script to update existing problems with the default state of the protocol:
bundle exec ruby script/run_task.rb dev 'rake problem_states:backfill_care_pod[enabled,eye_health_concerns,false]'
Alternative for Step 3: Connect to the bastion instance following the Bastion documentation, run the Rails console, and perform steps 3 and 4 manually.
Production Environment Rollout
📋 Resource: Use the Protocol Release Checklist Template to track your deployment progress across environments.
Step 1: Update Production Configuration
- Navigate to AWS Systems Manager → Parameter Store
- Locate the parameter:
/Prod/RailsApi/ProblemStates/ProtocolRolloutConfig
- Update the value to include your new protocol in the enabled problems list
- Force ECS deployment in production
- Run the backfill script with production parameters
Step 2: Dry Run Validation
Before applying changes to production, run a dry run to ensure the changes are correct:
bundle exec ruby script/run_task.rb prod 'rake problem_states:backfill_care_pod[enabled,eye_health_concerns,true]'
Step 3: Product Operations Review
After the dry run is performed, a new CSV report will be pushed to S3:
- S3 Location:
prod-arc-bucket/problem_protocol/reports/
- Region:
us-west-2
- File naming: Follow the protocol name pattern
- Action: Share the report with the Product Manager for review of charts and patients impacted by the update
Step 4: Perform the Update
Set the flag for dry_run
to false
for the last argument of the script.
Option 1: Run from Your Local Machine
bundle exec ruby script/run_task.rb prod 'rake problem_states:backfill_care_pod[enabled,eye_health_concerns,false]'
Option 2: Execute via Bastion Server
Connect to the bastion prod server for faster update, especially for a (GA) Global Audience update:
CMD="bundle exec rake problem_states:backfill_care_pod[enabled,eye_health_concerns,false]" ./rails_console.sh
Where eye_health_concerns
is the protocol name.
Related Documentation
- Protocol Definition
- Protocol Data Fetcher
- Problem State Processor
- Running Remote Tasks - For executing rake tasks in remote environments