Skip to content

Commit e83df7c

Browse files
authored
Merge pull request #2 from fbraza/score2
feat: Implement SCORE2 cardiovascular risk assessment algorithm
2 parents f0d38f2 + d8a9eb4 commit e83df7c

File tree

88 files changed

+1604
-57
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+1604
-57
lines changed

.github/workflows/claude-code-review.yml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ jobs:
1717
# github.event.pull_request.user.login == 'external-contributor' ||
1818
# github.event.pull_request.user.login == 'new-developer' ||
1919
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
20-
20+
2121
runs-on: ubuntu-latest
2222
permissions:
2323
contents: read
2424
pull-requests: read
2525
issues: read
2626
id-token: write
27-
27+
2828
steps:
2929
- name: Checkout repository
3030
uses: actions/checkout@v4
@@ -39,7 +39,7 @@ jobs:
3939

4040
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
4141
# model: "claude-opus-4-20250514"
42-
42+
4343
# Direct prompt for automated review (no @claude mention needed)
4444
direct_prompt: |
4545
Please review this pull request and provide feedback on:
@@ -48,31 +48,30 @@ jobs:
4848
- Performance considerations
4949
- Security concerns
5050
- Test coverage
51-
51+
5252
Be constructive and helpful in your feedback.
5353
5454
# Optional: Use sticky comments to make Claude reuse the same comment on subsequent pushes to the same PR
5555
# use_sticky_comment: true
56-
56+
5757
# Optional: Customize review based on file types
5858
# direct_prompt: |
5959
# Review this PR focusing on:
6060
# - For TypeScript files: Type safety and proper interface usage
6161
# - For API endpoints: Security, input validation, and error handling
6262
# - For React components: Performance, accessibility, and best practices
6363
# - For tests: Coverage, edge cases, and test quality
64-
64+
6565
# Optional: Different prompts for different authors
6666
# direct_prompt: |
67-
# ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' &&
67+
# ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' &&
6868
# 'Welcome! Please review this PR from a first-time contributor. Be encouraging and provide detailed explanations for any suggestions.' ||
6969
# 'Please provide a thorough code review focusing on our coding standards and best practices.' }}
70-
70+
7171
# Optional: Add specific tools for running tests or linting
7272
# allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)"
73-
73+
7474
# Optional: Skip review for certain conditions
7575
# if: |
7676
# !contains(github.event.pull_request.title, '[skip-review]') &&
7777
# !contains(github.event.pull_request.title, '[WIP]')
78-

.github/workflows/claude.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,26 +39,25 @@ jobs:
3939
# This is an optional setting that allows Claude to read CI results on PRs
4040
additional_permissions: |
4141
actions: read
42-
42+
4343
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
4444
# model: "claude-opus-4-20250514"
45-
45+
4646
# Optional: Customize the trigger phrase (default: @claude)
4747
# trigger_phrase: "/claude"
48-
48+
4949
# Optional: Trigger when specific user is assigned to an issue
5050
# assignee_trigger: "claude-bot"
51-
51+
5252
# Optional: Allow Claude to run specific commands
5353
# allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
54-
54+
5555
# Optional: Add custom instructions for Claude to customize its behavior for your project
5656
# custom_instructions: |
5757
# Follow our coding standards
5858
# Ensure all new code has tests
5959
# Use TypeScript for new files
60-
60+
6161
# Optional: Custom environment variables for Claude
6262
# claude_env: |
6363
# NODE_ENV: test
64-

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,3 @@ __marimo__/
211211
CLAUDE.md
212212
AGENTS.md
213213
.aider*
214-
specs

specs/coding_style.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Python Coding Style Specification
2+
3+
## Core Principles
4+
5+
### 1. Favor Simplicity Over Complexity
6+
- **Always choose the simple, straightforward solution** over complex or "sophisticated" alternatives
7+
- **Avoid over-engineering** - resist the urge to build elaborate abstractions unless clearly needed
8+
- **No premature optimization** - especially avoid blind optimization without measurement
9+
- **Use simple building blocks** that can be composed elegantly rather than complex features
10+
- **Principle**: If there are two ways to solve a problem, choose the one that is easier to understand
11+
12+
### 2. Clarity is Key
13+
- **Readable code beats clever code** - optimize for the reader, not the writer
14+
- **Use clear, descriptive names** for variables, functions, and classes
15+
- **Format code for maximal scanning ease** - use whitespace and structure intentionally
16+
- **Document intent and organization** with comments and docstrings where helpful
17+
- **Reduce cognitive load** - code should express intent clearly at a glance
18+
- **Principle**: The easier your code is to understand immediately, the better it is
19+
20+
### 3. Write Pythonic Code
21+
- **Follow Python community standards and idioms** for naming, formatting, and programming paradigms
22+
- **Cooperate with the language** rather than fighting it
23+
- **Leverage Python features** like generators, itertools, collections, and functional programming
24+
- **Write code that looks like Python wrote it** - use established patterns and conventions
25+
- **Examples of Pythonic patterns**:
26+
- List comprehensions over explicit loops when appropriate
27+
- Context managers (`with` statements) for resource management
28+
- Generator expressions for memory efficiency
29+
- `enumerate()` instead of manual indexing
30+
- `zip()` for parallel iteration
31+
32+
### 4. Don't Repeat Yourself (DRY)
33+
- **Avoid code duplication** to make code more maintainable and extendable
34+
- **Use functions and modules** to encapsulate common logic in single authoritative locations
35+
- **Consider inheritance** to avoid duplicate code between related classes
36+
- **Leverage language features** like default arguments, variable argument lists (`*args`, `**kwargs`), and parameter unpacking
37+
- **Eliminate duplication through abstraction** - but don't abstract too early
38+
39+
### 5. Focus on Readability First
40+
- **PEP8 is a guide, not a law** - readability trumps mechanical adherence to style rules
41+
- **Make code as easy to understand as possible** - this is the ultimate goal
42+
- **Deliberately violate guidelines** if it makes specific code more readable
43+
- **Consider the human reader** first when making formatting and style decisions
44+
- **Principle**: Rules serve readability, not the other way around
45+
46+
### 6. Embrace Conventions
47+
- **Follow established conventions** to eliminate trivial decision-making
48+
- **Use PEP8 as a baseline** but prioritize readability when there's conflict
49+
- **Establish consistent patterns** in your codebase for common tasks:
50+
- Variable naming patterns
51+
- Exception handling approaches
52+
- Logging configuration
53+
- Import organization
54+
- **Consistency enables focus** - familiar patterns let readers focus on logic rather than parsing
55+
56+
## Specific Implementation Guidelines
57+
58+
### Naming Conventions
59+
- **Variables and functions**: `snake_case`
60+
- **Classes**: `PascalCase`
61+
- **Constants**: `UPPER_SNAKE_CASE`
62+
- **Private attributes**: `_single_leading_underscore`
63+
- **Choose descriptive names** that clearly indicate purpose and content
64+
65+
### Code Structure
66+
- **Organize imports** in this order: standard library, third-party, local imports
67+
- **Use blank lines** to separate logical sections
68+
- **Keep functions focused** on a single responsibility
69+
- **Prefer composition over inheritance** when appropriate
70+
- **Write functions that do one thing well**
71+
72+
### Documentation
73+
- **Write docstrings** for modules, classes, and functions that aren't immediately obvious
74+
- **Use comments** to explain why, not what
75+
- **Keep comments up to date** with code changes
76+
- **Focus on intent** rather than implementation details
77+
78+
### Error Handling
79+
- **Use specific exception types** rather than generic `Exception`
80+
- **Follow the "easier to ask for forgiveness than permission" (EAFP) principle**
81+
- **Handle errors at the appropriate level** - don't catch exceptions you can't handle meaningfully
82+
83+
### Performance and Optimization
84+
- **Write clear code first** - optimize only when necessary and after measurement
85+
- **Use appropriate data structures** for the task
86+
- **Leverage built-in functions** and library functions when they're clearer
87+
- **Profile before optimizing** - don't guess where bottlenecks are
88+
89+
## Code Review Checklist
90+
91+
When generating or reviewing Python code, ensure:
92+
- [ ] The simplest solution that works is chosen
93+
- [ ] Names clearly communicate purpose
94+
- [ ] Code is easily scannable and readable
95+
- [ ] Pythonic patterns are used appropriately
96+
- [ ] No unnecessary duplication exists
97+
- [ ] Conventions are followed consistently
98+
- [ ] Comments explain intent where needed
99+
- [ ] Error handling is appropriate
100+
- [ ] The code would be easy for another developer to understand and maintain
101+
102+
## Decision Framework
103+
104+
When faced with coding choices, ask:
105+
1. **Is this the simplest solution that works?**
106+
2. **Will this be clear to someone reading it in 6 months?**
107+
3. **Am I using Python idioms appropriately?**
108+
4. **Am I duplicating logic that could be abstracted?**
109+
5. **Does this follow our established conventions?**
110+
6. **Is this optimized for readability?**
111+
112+
The answer to all these questions should be "yes" for beautiful Python code.

specs/score2.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# CVD Risk Prediction Formula
2+
3+
## Overview
4+
5+
This formula calculates the 10-year risk of cardiovascular disease (CVD) using a sex-specific Cox proportional hazards model. The model incorporates multiple risk factors with specific transformations and interaction terms to provide personalized risk estimates.
6+
7+
**Target Population**: European patients aged 40-69 years without prior CVD or diabetes.
8+
9+
## Model Coefficients and Baseline Survival
10+
11+
The model coefficients and baseline survival to calculate 10-year risk of CVD are as follows:
12+
13+
| Risk Factor | Transformation | Male | Female |
14+
|-------------|----------------|------|--------|
15+
| Age, years | cage = (age - 60)/5 | 0.3742 | 0.4648 |
16+
| Smoking | current = 1, other = 0 | 0.6012 | 0.7744 |
17+
| SBP, mm Hg | csbp = (sbp - 120)/20 | 0.2777 | 0.3131 |
18+
| Total cholesterol, mmol/L | ctchol = tchol - 6 | 0.1458 | 0.1002 |
19+
| HDL cholesterol, mmol/L | chdl = (hdl - 1.3)/0.5 | -0.2698 | -0.2606 |
20+
| Smoking*age interaction | smoking*cage | -0.0755 | -0.1088 |
21+
| SBP*age interaction | csbp*cage | -0.0255 | -0.0277 |
22+
| Total cholesterol*age interaction | ctchol*cage | -0.0281 | -0.0226 |
23+
| HDL cholesterol*age interaction | chdl*cage | 0.0426 | 0.0613 |
24+
| **Baseline survival** | | **0.9605** | **0.9776** |
25+
26+
## Risk Calculation Formula
27+
28+
The uncalibrated 10-year risk of CVD is calculated by the following:
29+
30+
**10-year risk = 1 - (baseline survival)^exp(x)**
31+
32+
where **x = Σ[β*(transformed variables)]**
33+
34+
## Regional Calibration
35+
36+
The region and sex-specific scales to calculate calibrated 10-year risk are as follows:
37+
38+
| Risk Region | Male Scale 1 | Male Scale 2 | Female Scale 1 | Female Scale 2 |
39+
|-------------|--------------|--------------|----------------|----------------|
40+
| Low | -0.5699 | 0.7476 | -0.7380 | 0.7019 |
41+
| Moderate | -0.1565 | 0.8009 | -0.3143 | 0.7701 |
42+
| High | 0.3207 | 0.9360 | 0.5710 | 0.9369 |
43+
| Very high | 0.5836 | 0.8294 | 0.9412 | 0.8329 |
44+
45+
### Calibrated Risk Calculation Formula
46+
47+
The calibrated 10-year risk of CVD is calculated by the following:
48+
49+
**Calibrated 10-year risk, % = [1 - exp(-exp(scale1 + scale2*ln(-ln(1 - 10-year risk))))] * 100**
50+
51+
### Regional Risk Classification
52+
53+
- **Belgium**: Classified as a **Low Risk** region
54+
- For initial development, use the Low Risk calibration scales:
55+
- Males: Scale 1 = -0.5699, Scale 2 = 0.7476
56+
- Females: Scale 1 = -0.7380, Scale 2 = 0.7019
57+
58+
## Model Components Explained
59+
60+
### Risk Factor Transformations
61+
62+
1. **Age (cage)**: Centered at 60 years and scaled by 5-year intervals
63+
- `cage = (age - 60)/5`
64+
65+
2. **Smoking**: Binary indicator
66+
- `current = 1, other = 0`
67+
68+
3. **Systolic Blood Pressure (csbp)**: Centered at 120 mmHg and scaled by 20 mmHg intervals
69+
- `csbp = (sbp - 120)/20`
70+
71+
4. **Total Cholesterol (ctchol)**: Centered at 6 mmol/L
72+
- `ctchol = tchol - 6`
73+
74+
5. **HDL Cholesterol (chdl)**: Centered at 1.3 mmol/L and scaled by 0.5 mmol/L intervals
75+
- `chdl = (hdl - 1.3)/0.5`
76+
77+
### Interaction Terms
78+
79+
The model includes four age interaction terms that capture how the effect of risk factors changes with age:
80+
81+
1. **Smoking × Age**: `smoking × cage`
82+
2. **SBP × Age**: `csbp × cage`
83+
3. **Total Cholesterol × Age**: `ctchol × cage`
84+
4. **HDL Cholesterol × Age**: `chdl × cage`
85+
86+
### Sex-Specific Differences
87+
88+
- **Females** generally have higher baseline survival (0.9776 vs 0.9605)
89+
- **Smoking** has a stronger effect in females (0.7744 vs 0.6012)
90+
- **Age** has a stronger effect in females (0.4648 vs 0.3742)
91+
- **SBP** has a slightly stronger effect in females (0.3131 vs 0.2777)
92+
- **HDL cholesterol** protective effect is similar between sexes
93+
94+
## Implementation Workflow
95+
96+
1. **Calculate uncalibrated risk** using the base formula with model coefficients
97+
2. **Apply regional calibration** using the appropriate scales for the patient's location and sex
98+
3. **Output calibrated percentage** as the final 10-year CVD risk estimate
99+
100+
## Implementation Notes
101+
102+
1. **Input Units**:
103+
- Age: years
104+
- SBP: mmHg
105+
- Total cholesterol: mmol/L
106+
- HDL cholesterol: mmol/L
107+
- Smoking: binary (1 = current smoker, 0 = other)
108+
109+
2. **Output**: 10-year CVD risk as a percentage (0-100%)
110+
111+
3. **Model Type**: Cox proportional hazards model with sex-specific coefficients and regional calibration
112+
113+
4. **Default Region**: Belgium (Low Risk region) for initial application development
114+
115+
## Risk Stratification
116+
117+
### Age-Specific Risk Categories
118+
119+
#### Patients <50 years old
120+
121+
- Low to moderate risk: <2.5%
122+
- High risk: 2.5% to <7.5%
123+
- Very high risk: ≥7.5%
124+
125+
#### Patients 50-69 years old
126+
127+
- Low to moderate risk: <5%
128+
- High risk: 5% to <10%
129+
- Very high risk: ≥10%
130+
131+
### Treatment Recommendations
132+
133+
- **Low to moderate risk**: Risk factor treatment plan generally not recommended.
134+
- **High risk**: Risk factor treatment plan should be considered (i.e., blood pressure and LDL-C control).
135+
- **Very high risk**: Risk factor treatment plan should be recommended (i.e., blood pressure and LDL-C control).

0 commit comments

Comments
 (0)