Skip to content

Store explicit side-effect severity - #144

Open
Airwhale wants to merge 2 commits into
codex/match-dose-administration-routefrom
codex/side-effect-severity
Open

Store explicit side-effect severity#144
Airwhale wants to merge 2 commits into
codex/match-dose-administration-routefrom
codex/side-effect-severity

Conversation

@Airwhale

@Airwhale Airwhale commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Stack from main: #121 -> #119 -> #122 -> #118 -> #120 -> #142 -> #141 -> #144

The first five PRs are merged. The remaining open stack is #142 -> #141 -> #144.

Why

The classifier currently stores side effects as symptom strings. That preserves which effect was reported but loses whether the author described it as mild, moderate, severe, or life-threatening. As a result, analyses can compare side-effect reporting rates but cannot test whether dose or route is associated with reported severity.

The extraction must remain conservative. A symptom that sounds clinically serious is not evidence that the author experienced it severely, so severity should remain missing unless the author explicitly states it.

Approach taken

  • Add a small Pydantic SideEffectReport model with side_effect and nullable severity fields.
  • Restrict severity to mild, moderate, severe, and life_threatening.
  • Update batch and fallback prompts to return side-effect objects and explicitly prohibit inferring severity from the symptom name.
  • Store the objects as JSON in the existing treatment_reports.side_effects text column. No schema migration or rewrite of existing rows is required.
  • Add focused tests for valid severity, invalid severity, unspecified severity, and the exact JSON written to SQLite.

User-facing changes

New classification rows store side effects as objects such as:

{"side_effect": "headache", "severity": "mild"}

When the author reports a side effect without describing its intensity, severity is null. Existing database rows are unchanged and retain their original string-array JSON.

Detailed test plan

  1. Run the complete test suite:
uv run pytest -q

Expected result: 379 passed.

  1. Run the focused contract and persistence tests:
uv run pytest tests/test_side_effect_severity.py -q

Expected result: 3 passed.

  1. Run lint checks on the new model, prompt, persistence code, and tests:
uvx ruff check src/models.py src/prompts/intervention_config.py src/utilities/db.py tests/test_side_effect_severity.py

Expected result: All checks passed!

  1. Verify the stacked diff contains only the intended code, schema comment, documentation, and tests:
git diff --name-only origin/codex/match-dose-administration-route...HEAD

Expected files:

README.md
schema.sql
src/models.py
src/pipeline/classify.py
src/prompts/intervention_config.py
src/utilities/db.py
tests/test_side_effect_severity.py

Represent each classified side effect as a validated object containing the symptom name and an optional ordinal severity. Persist the objects in the existing JSON column without migrating prior rows, and document the new shape.

Severity remains null unless the author explicitly states it. Add focused validation and SQLite persistence tests.
Combine successful nested classification validation with the SQLite round trip so one test verifies parsing, serialization, and persistence. Preserve mild and severe values, explicit null, and omitted severity in the stored JSON assertions.

Keep a focused invalid-severity check on SideEffectReport and remove the duplicate standalone success assertion. Validation: uv run --locked pytest -q (378 passed); uvx ruff check tests/test_side_effect_severity.py; git diff --check.
@Airwhale
Airwhale marked this pull request as ready for review September 11, 2026 22:01
@Airwhale
Airwhale requested review from Ely-S and polya-b September 11, 2026 22:01
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.

1 participant