# Labeling guide — Timmy corpus review This is the guide a human reviewer follows when labelling a contributed photo in [`scripts/review_corpus.py`](../scripts/review_corpus.py). It exists so a label in the corpus means the same thing to every reviewer, and so a model trained on those labels cannot quietly inherit a clinical claim nobody made. The corpus it describes is summarised, from the manifest and never by hand, in [DATASET_CARD.md](DATASET_CARD.md). A label is an observation. It is **not** a diagnosis, not a severity assessment, and not a statement about the person's health. ## What a reviewer may record Three fields, all of them visible in the photo: | Field | Vocabulary | Rule | |---|---|---| | `bristolType` | 1–7 | The Bristol form the sample most resembles, by shape and surface — not by how the person says they feel. | | `color` | `brown`, `green`, `yellow`, `pale`, `red`, `black` | The **broad visible color** of the sample in the photo. | | `quality` | `good`, `fair`, `poor` | Whether the photo supports a confident form and color call at all. | `quality` is about the photo, not the person: glare, blur, framing, and distance. A `poor` photo belongs in the corpus as a `poor` photo; it is not a reason to guess a higher-quality label, and `review_corpus.py` excludes an unclear sample from training instead of filling the gap. ## Color is not blood The single most damaging mistake available here. Visible color describes what the photo looks like; it does not establish that blood is present: - `red` means **the sample looks reddish in this photo**. It is **not blood**, and it is not "bleeding". A reviewer never writes "blood" into a label, a comment, or an exclusion reason. - `black` means **the sample looks black or very dark in this photo**. It is not "melena", not "GI bleed", and not evidence of anything. - Neither field may be used to reassure. A `brown` label is **not** a statement that there is no bleeding; a photo cannot rule that out and the app does not claim it can. - Blood, black or tarry stool, pain, urgency, fever, or vomiting are **user-reported** facts, asked in words and routed to the deterministic red-flag path. They are never inferred from an image and never stored as a label by this tool. If the photo genuinely shows something a reviewer believes needs urgent attention, the correct action is to stop labelling and escalate to the maintainers — not to encode a clinical judgement in a class. ## Never diagnose - Do not diagnose, rule out, or name a disease, condition, or cause in any label, comment, or exclusion reason. - Do not infer symptoms, pain, urgency, frequency, hydration, diet, medication, or pregnancy. - Do not grade severity ("mild", "concerning", "abnormal"). The vocabulary is form, color, and photo quality only. - A model suggestion is **provisional input**, never the label. The reviewer's own committed decision is the label; `review_corpus.py` refuses to reveal the model's answer until the reviewer has committed theirs, and records any disagreement beside the proposal rather than averaging it away. ## Exclusions Exclude a sample when it cannot be labelled honestly: | Situation | Action | |---|---| | No stool visible, or the photo is of something else | Exclude: `not-stool`. | | Photo too blurred, glared, or distant to judge form | Exclude: `unreadable-photo`. | | Two samples in one frame, or ambiguous framing | Exclude: `ambiguous-frame`. | | Reviewer believes the image needs urgent clinical attention | **Stop.** Escalate to maintainers; do not label, do not exclude quietly. | | Contributor withdrew consent | Not a review decision: the manifest tombstones the contribution and the queue drops it. | An exclusion is recorded with a reason from the list above. An excluded sample is never training data, and re-including it requires a new review, not an edit. ## Splits: one contributor, one split All of a contributor's photos stay in **one split**, decided by their salted pseudonymous subject key (`< 205` train, `< 230` validation, otherwise test — the ingestion rule in `scripts/ingest_training_photo.py`). A reviewer never chooses a split, and a reviewer never moves a sample between splits to balance a class. If a class is thin, the honest answer is more consented contributors, not a leaked one. `scripts/dataset_card.py` refuses to publish a card for a corpus where one subject key appears in two splits. ## Reporting a problem with this guide If a label feels impossible to assign without a clinical judgement, that is a gap in this guide, not a licence to improvise. Open an issue against [stackchain/timmy-talking-turd](https://forge.alexanderwhitestone.com/git/stackchain/timmy-talking-turd) describing the case, without attaching a real medical image.