From 3b9cd36f925fec73cd7ae4e1fbc790fc4c801df6 Mon Sep 17 00:00:00 2001 From: Lacky1234union Date: Sat, 3 Oct 2026 14:50:30 +0300 Subject: [PATCH 1/2] =?UTF-8?q?chore(core):=20freeze=20shared=20core=20con?= =?UTF-8?q?tracts=20=E2=80=94=20ScrubbedText,=20RiskLevel,=20AlertLevel,?= =?UTF-8?q?=20privacy=20signatures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lets #2-#7 proceed in parallel against stable interfaces. Refs #2 Co-Authored-By: Claude Opus 5.5 --- app/core/privacy.py | 13 +++++++++++++ app/core/types.py | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 app/core/privacy.py create mode 100644 app/core/types.py diff --git a/app/core/privacy.py b/app/core/privacy.py new file mode 100644 index 0000000..c81c6c3 --- /dev/null +++ b/app/core/privacy.py @@ -0,0 +1,13 @@ +"""PII scrubbing and pseudonymisation (issue #2). Contract stub — implementation lands in #2.""" + +from app.core.types import ScrubbedText + + +def scrub(text: str) -> ScrubbedText: + """Replace personal data (phones, emails, SNILS, names, addresses...) with placeholders.""" + raise NotImplementedError + + +def pseudo_id(snils: str, key: str | None = None) -> str: + """HMAC-SHA256(PSEUDO_KEY, normalised SNILS) as 32 hex chars — the token linking identity and clinical DBs.""" + raise NotImplementedError diff --git a/app/core/types.py b/app/core/types.py new file mode 100644 index 0000000..cc85392 --- /dev/null +++ b/app/core/types.py @@ -0,0 +1,24 @@ +"""Shared core types. Frozen contract between zones: change only via a separate small PR.""" + +from enum import IntEnum +from typing import NewType + +# Text that has passed `app.core.privacy.scrub()`. The LLM gateway accepts only this type (guardrail #1). +ScrubbedText = NewType("ScrubbedText", str) + + +class RiskLevel(IntEnum): + """Safety risk level. Ordered, so the combined signal is `max(lexicon, llm)`.""" + + NONE = 0 + POSSIBLE = 1 + ACUTE = 2 + + +class AlertLevel(IntEnum): + """Alert level stored in DB. UI colour is derived (ADR-006): ACUTE=red, HIGH/MODERATE=yellow, INFO=grey.""" + + INFO = 0 + MODERATE = 1 + HIGH = 2 + ACUTE = 3 From f8b1fa561b0a65fc8935ab9b96f919b86ef35fe8 Mon Sep 17 00:00:00 2001 From: Lacky1234union Date: Sat, 3 Oct 2026 14:50:47 +0300 Subject: [PATCH 2/2] style(core): wrap long docstrings Refs #2 Co-Authored-By: Claude Opus 5.5 --- app/core/privacy.py | 5 ++++- app/core/types.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/core/privacy.py b/app/core/privacy.py index c81c6c3..4f0087a 100644 --- a/app/core/privacy.py +++ b/app/core/privacy.py @@ -9,5 +9,8 @@ def scrub(text: str) -> ScrubbedText: def pseudo_id(snils: str, key: str | None = None) -> str: - """HMAC-SHA256(PSEUDO_KEY, normalised SNILS) as 32 hex chars — the token linking identity and clinical DBs.""" + """HMAC-SHA256(PSEUDO_KEY, normalised SNILS) as 32 hex chars. + + The token is the only link between the identity and clinical databases. + """ raise NotImplementedError diff --git a/app/core/types.py b/app/core/types.py index cc85392..98d43a4 100644 --- a/app/core/types.py +++ b/app/core/types.py @@ -16,7 +16,10 @@ class RiskLevel(IntEnum): class AlertLevel(IntEnum): - """Alert level stored in DB. UI colour is derived (ADR-006): ACUTE=red, HIGH/MODERATE=yellow, INFO=grey.""" + """Alert level stored in DB. + + UI colour is derived (ADR-006): ACUTE=red, HIGH/MODERATE=yellow, INFO=grey. + """ INFO = 0 MODERATE = 1