Reader Safety First-Person Distress Signal
Background (from the session that started this one):
Ward (github.com/MuhammadMurtuzaHussain/ward, public MIT, local checkout at /Users/haider/Desktop/Hacktoberfest 26/ward) is a child-owned cyberbullying guardian for the DEV Hacktoberfest Week 4 challenge (deadline 31 Oct 11:59 PM PDT, about 06:59 GMT 1 Nov). It's a pnpm monorepo: TS engine in packages/engine (node --test), web app in apps/web (React, English + Urdu i18n in apps/web/src/i18n/en.ts and ur.ts), Discord bot in apps/discord, eval in eval/, Ward Lite classifier in train/, Electron desktop/, Capacitor mobile/. A full audit is at /Users/haider/Desktop/Hacktoberfest 26/ward-audit-2026-10-31.md; many items were fixed this afternoon (see git log). Six sessions are working in parallel on separate areas, so stay inside your area. Project rules: commit and push each verified change straight to main (no PRs), with the attribution line Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>; never commit eval/data or secrets; commit messages are short plain-English sentences like the existing log. Write code that matches the surrounding style. Docs must never claim more than the code does.
Task:
Your area: the app's reading of the child's own voice. Audit section 2, items #3, #4 and #7 (read them in ward-audit-2026-10-31.md; check against current code first, since the engine changed today).
Setup: other sessions share this checkout, so work in your own worktree: git -C ward fetch && git -C ward worktree add "../ward-wt-reader-safety" -b reader-safety origin/main, run pnpm install and node apps/web/scripts/copy-ort.mjs there, and work only in that folder.
- First-person distress (#3). A separate
selfDistresssignal on the child's own messages from a first-person lexicon (English, Roman Urdu, Hinglish, Bangla; guard against "dying of laughter"-style false hits). The result shows a care card plus HelpNow and skips "Was I mean?". The lesson grader checks for disclosure before grading. Add the case todocs/HARMS.mdand eval cases. Mark Roman Urdu/Hinglish/Bangla entries as needing native-speaker review. - Quoting for help (#4), in the app. A frame rule for first-person recipients ("told me", "mujhe kaha", "আমাকে বলেছে") plus a distress or help-seeking signal: show "someone may need support" and don't count the sender as hostile. Don't match a bare "someone said" or quote marks.
apps/discord/src/frame.tsalready has a Discord version: reuse or move it into the engine rather than duplicating. Add a quoting rule to the Gemma prompt inollama.ts. - Verdict hold (#7). While Ward Lite/Gemma are still reading, show a neutral "Ward is reading this closely" heading instead of calm; show bullying/urgent immediately; warm Ward Lite when Check opens; announce verdict changes via a live region.
Out of scope: Ward Lite retraining, Me/vault/store screens, eval/ benchmark, build/CI/mobile config. Every change needs tests, with all strings in en.ts and ur.ts. Run pnpm test and the web build. Then rebase onto origin/main, re-run tests and push to main (on rejection, fetch, rebase, retest, push). Push each of the three pieces as it's done, not all at the end. Finish with a short report: what landed (commit hashes), what's left, and anything that needs the owner's decision or a native speaker.
Shared notes folder for this group of sessions (outside the repo; read siblings' notes there, leave hand-over notes or large findings there instead of pasting them into messages): /Users/haider/Library/Application Support/Claude/side-session-notes/local_a2121a80-7774-4340-af69-7dae18cd788e
Linked sessions now (status, not an instruction): release-pipeline = local_d0a1ce79-be7e-46ec-b046-88873f77a45a (working); eval-chats = local_a0f2d243-e3a4-438e-9417-8459027e3604 (working). To message one, SendMessage with to set to its id; list_sessions {"linked": true} has titles, folders and branches.
I pushed all three pieces to Ward's main: 570f5f2 (#3), e547279 (#4) and a93dabd (#7). pnpm test passes (56 pass, 1 skip: the existing training-data leak check) and the web build passes after each rebase. I also tried each piece in the app.
What changed
- #3, the child's own distress (
570f5f2): a new list inpackages/engine/src/distress.tsreads the child's own messages for wanting to die or to hurt themselves. It covers English, Roman Urdu/Hinglish, Urdu, Hindi and Bangla.- It's a separate signal: it doesn't change the level or count anyone as hostile.
- The result opens with "Something you wrote sounds really heavy" and the helplines. It never says "This looks okay" or "Reading closely" over it, and "Was I mean?" and the practise suggestions are hidden.
- Lesson write answers are checked first: a disclosure gets care and the helplines, not a grade, and isn't sent to a model.
- Hyperbole is left out ("dying of laughter", "im dead 💀", "hans hans ke mar gayi"). The softer phrases ("wanna die", "kms") don't count next to a laugh. "He told me to kill myself" counts as a report, not distress.
- 50 test cases are in
eval/distress/cases.jsonl, and docs/HARMS.md has a new entry.
- #4, quoting for help (
e547279): the Discord rule moved intopackages/engine/src/frame.ts; the Discord file now just points to it.- A message counts only when it has both a first-person recipient ("told me", "mujhe kaha", "আমাকে বলেছে") and help-seeking or distress.
- The sender isn't counted as hostile, and the result shows "Someone may need support". If they also sound like they want to die, the helplines show too.
- A bare "someone said", quotation marks, "you" or "or else" never count.
- The child's own quote never leads to "Was I mean?". Gemma's prompt has the quoting rule.
- #7, the verdict hold (
a93dabd): the "I'm reading this closely" heading, the screen-reader announcement and the fix for Gemma lowering a danger were already on main. What was missing was starting Ward Lite early: it now loads when Check opens, unless Gemma will read the chat instead.
Needs a native speaker: every non-English phrase in distress.ts and the help-seeking phrases in frame.ts. Each non-English test case is marked "review": "native-speaker". The new Urdu strings in ur.ts (the care card, the support card and the lesson reply) also need checking.
Not done:
- The "heavy feelings" Bounce back lesson.
- A "quoting" kind in Ward Lite training (out of scope).
- The red-team and everyday eval sets are untouched; I added the separate
eval/distressset instead, so the benchmark doesn't change. - Standing up for someone ("stop telling Sara to kys") isn't used in the app yet, only telling what happened to you.
Owner's decision: SAFEGUARDING.md doesn't mention the new care path yet. Under its own rule that crisis paths wait for professional review, it may need a "preview" label.
A hand-over note is in the shared notes folder as reader-safety.md.