docs(sharing): name the screener's score row where the section is consented

`POST /api/mental-health/assessments` is fenced on `mind` and writes one row
into `measurements`: the instrument's total, minted `COMPUTED` and keyed on the
administration it came from, so the trend reads through the chart and rollup
tier without the encrypted item answers going anywhere. A grant scoped to mood
and mind therefore adds a point to the owner's measurement series, and nothing
said so.

Left in place rather than fenced. Withholding the projection the way the
booster mint is now fenced would file a screener whose own total is missing
from the record — an inconsistency inside the section the grant does open, to
avoid a derived point in one it does not. So it is documented instead, in the
three places it is decided or agreed to: the declaration, the section's own
definition, and the consent copy in all seven locales, which is where a
widening belongs. The published operation says it too.
This commit is contained in:
Marc-André Bombeck committed 2026-09-10 11:15:50 +02:00
1 parent 1b74bf8b54
commit c809971a23
11 files changed
+41 -13

No files matched your search

+11 -4
View File
@@ -14734,10 +14734,17 @@ paths:
tags:
- Mental health
summary: Record a completed screener
description: Stores one administration (item answers encrypted) and writes the derived total as a server-owned
PHQ9_SCORE / GAD7_SCORE / WHO5_SCORE / SCI_SCORE measurement (source COMPUTED — never client-writable). WHO-5
and SCI totals run HIGHER = better; their follow-up thresholds point downwards (≤ 50 / ≤ 16). On a positive
PHQ-9 item-9 the response carries the locale-aware crisis-resource set.
description: >-
Stores one administration (item answers encrypted) and writes the derived total as a server-owned PHQ9_SCORE /
GAD7_SCORE / WHO5_SCORE / SCI_SCORE measurement (source COMPUTED — never client-writable). WHO-5 and SCI totals
run HIGHER = better; their follow-up thresholds point downwards (≤ 50 / ≤ 16). On a positive PHQ-9 item-9 the
response carries the locale-aware crisis-resource set.
The projection row is the one write this operation makes outside its declared section: the operation is fenced
on `mind`, and the measurement it derives lands in `measurements`. It is deliberate and unconditional — a
screener whose own total is missing from the record would be an inconsistency inside the section the grant does
open. The consent copy for the mood-and-mind section names it.
parameters:
- *a6
requestBody:
+1 -1
View File
@@ -10484,7 +10484,7 @@
},
"mind": {
"label": "Stimmung und Psyche",
"detail": "Stimmungseinträge und der Verlauf der psychologischen Fragebögen."
"detail": "Stimmungseinträge und der Verlauf der psychologischen Fragebögen. Ein ausgefüllter Fragebogen legt seinen Summenwert zusätzlich als Messwert ab."
},
"cycle": {
"label": "Zyklus",
+1 -1
View File
@@ -10484,7 +10484,7 @@
},
"mind": {
"label": "Mood and mind",
"detail": "Mood entries and the history of the mental-health questionnaires."
"detail": "Mood entries and the history of the mental-health questionnaires. A completed questionnaire also files its total score as a reading."
},
"cycle": {
"label": "Cycle",
+1 -1
View File
@@ -10484,7 +10484,7 @@
},
"mind": {
"label": "Ánimo y bienestar mental",
"detail": "Las entradas de ánimo y el historial de los cuestionarios de salud mental."
"detail": "Las entradas de ánimo y el historial de los cuestionarios de salud mental. Un cuestionario completado también registra su puntuación total como una medición."
},
"cycle": {
"label": "Ciclo",
+1 -1
View File
@@ -10484,7 +10484,7 @@
},
"mind": {
"label": "Humeur et santé mentale",
"detail": "Les entrées d'humeur et l'historique des questionnaires de santé mentale."
"detail": "Les entrées d'humeur et l'historique des questionnaires de santé mentale. Un questionnaire rempli enregistre aussi son score total comme une mesure."
},
"cycle": {
"label": "Cycle",
+1 -1
View File
@@ -10484,7 +10484,7 @@
},
"mind": {
"label": "Umore e benessere mentale",
"detail": "Le voci sull'umore e lo storico dei questionari sulla salute mentale."
"detail": "Le voci sull'umore e lo storico dei questionari sulla salute mentale. Un questionario compilato registra anche il suo punteggio totale come una misurazione."
},
"cycle": {
"label": "Ciclo",
+1 -1
View File
@@ -10484,7 +10484,7 @@
},
"mind": {
"label": "기분과 마음",
"detail": "기분 기록과 정신건강 설문 이력이에요."
"detail": "기분 기록과 정신건강 설문 이력이에요. 작성한 설문은 총점도 측정값으로 함께 저장돼요."
},
"cycle": {
"label": "생리 주기",
+1 -1
View File
@@ -10484,7 +10484,7 @@
},
"mind": {
"label": "Nastrój i zdrowie psychiczne",
"detail": "Wpisy o nastroju i historia kwestionariuszy zdrowia psychicznego."
"detail": "Wpisy o nastroju i historia kwestionariuszy zdrowia psychicznego. Wypełniony kwestionariusz zapisuje też swój wynik łączny jako pomiar."
},
"cycle": {
"label": "Cykl",
@@ -159,6 +159,17 @@ async function postAssessment(request: NextRequest): Promise<Response> {
// into the record: the ordinary way this instrument is used when the person
// it is about cannot run their own record. The row records what the person
// in the room reported; the audit row says who typed it.
//
// It writes ONE row outside its declared section, and the crossing is
// deliberate rather than an oversight: the `*_SCORE` Measurement below is a
// projection of this administration, minted `COMPUTED`, keyed on
// `assessment:<id>`, and it exists only so the trend reads through the chart
// and rollup tier without ever touching the encrypted item content. Fencing
// it on `measurements` the way the booster mint is fenced would file a
// screener whose own total is missing from the record — an inconsistency
// inside the section the grant DOES open, to avoid a derived point in one it
// does not. The consent copy for this section says so, which is where a
// widening belongs.
const { user, actor } = await requireRecordAuth("manage", "mind");
// Opt-in module (default OFF) — same gate as GET.
+2 -1
View File
@@ -135,7 +135,8 @@ export const mentalHealthPaths: NonNullable<ZodOpenApiObject["paths"]> = {
tags: ["Mental health"],
summary: "Record a completed screener",
description:
"Stores one administration (item answers encrypted) and writes the derived total as a server-owned PHQ9_SCORE / GAD7_SCORE / WHO5_SCORE / SCI_SCORE measurement (source COMPUTED — never client-writable). WHO-5 and SCI totals run HIGHER = better; their follow-up thresholds point downwards (≤ 50 / ≤ 16). On a positive PHQ-9 item-9 the response carries the locale-aware crisis-resource set.",
"Stores one administration (item answers encrypted) and writes the derived total as a server-owned PHQ9_SCORE / GAD7_SCORE / WHO5_SCORE / SCI_SCORE measurement (source COMPUTED — never client-writable). WHO-5 and SCI totals run HIGHER = better; their follow-up thresholds point downwards (≤ 50 / ≤ 16). On a positive PHQ-9 item-9 the response carries the locale-aware crisis-resource set.\n\n" +
"The projection row is the one write this operation makes outside its declared section: the operation is fenced on `mind`, and the measurement it derives lands in `measurements`. It is deliberate and unconditional — a screener whose own total is missing from the record would be an inconsistency inside the section the grant does open. The consent copy for the mood-and-mind section names it.",
parameters: [idempotencyKeyParameter],
requestBody: {
content: {
+10 -1
View File
@@ -68,7 +68,16 @@ export const SHARE_DOMAINS = [
"profile",
/** Illness episodes and the day logs under them. */
"illness",
/** Mood entries and mental-health screener history. */
/**
* Mood entries and mental-health screener history.
*
* One write in this section lands outside it, and the consent copy names it:
* completing a screener also files the instrument's total as a `COMPUTED`
* measurement, so the trend reads through the chart and rollup tier without
* the encrypted item content going anywhere. It is a projection of the
* administration rather than a second reading, and withholding it would file
* a screener whose own total is missing from the record.
*/
"mind",
/** Cycle tracking. */
"cycle",