# 2026-07-17 — P1-11 vocab sweep + P1-UX-5b terminology hook

Branch: `feat/p1-11-and-ux5b-shapeshift`
Worktree: `.worktrees/feat-p1-11-and-ux5b-shapeshift`

## Why

The UI/UX feedback PDF (§5 Global terminology, §6 Teacher Dashboard, §7
Notice Board, §8 Curriculum Portfolio, §9 Course Scheme/Plan) requires
many user-facing labels to change. Hunting these down through 100+
components every time is unsustainable, so the work is in two halves:

1. A small `terminology.ts` dictionary + `useTerminology()` hook that
   every UI label can route through going forward.
2. Surgical text edits to the highest-traffic teacher/notice-board
   dashboards so the new language ships immediately on the Pilot UAT
   deploy.

## Changes

### `client/src/lib/terminology.ts` (new)

Single source of truth for all replaced terms. Exports:

- `T` — frozen flat dictionary (`STUDENT: 'Learner'`, `MATERIAL_ASSETS:
  'Learning Material'`, `VIEW_ROSTER: 'View Learners'`, `ARCHIVE_COURSE:
  'Delete'`, `GRADING: 'Marking'`, `THRESHOLD: 'Average'`, `MARKED:
  'Excused'`, `OUTLIERS: 'Below Average'`, `STUDENT_DRILLDOWN: 'Learner
  Remedial Record'`, `BROADCAST: 'Notification'`, plus PDF §9 entries).
- `T_TIERED` — dictionary keyed by `primary` / `secondary` / `tertiary`
  for entries that genuinely differ per tier.
- `TIER` / `ACTIVE_TIER` — constants. `ACTIVE_TIER` is hard-coded
  `tertiary` for now; will read from `school_settings.school_tier` once
  that column lands.
- `useTerminology()` — hook returning `{ tier, T, T_TIERED, term,
  label }`. `label('Course')` resolves to the current tier's mapping.

### `client/src/test/terminology.test.ts` (new, 15 specs)

Vitest. Asserts every PDF § value is present and that `termFor` /
`label` resolve tiered entries correctly.

### User-facing label edits (text-only, 6 files)

| File | PDF § | Edits |
|---|---|---|
| `pages/teacher/TeacherDashboard.tsx` | §6 | `Students → Learners`, `Pending Grading → Pending Marking`, `Below Threshold → Below Average`, `Outliers (avg < 50%) → Below Average (avg < 50%)`, `Marked → Excused` (attendance callout), `Student Drill-down → Learner Remedial Record` |
| `pages/teacher/MyCourses.tsx` | §8 | `Material Assets → Learning Material`, `View Roster → View Learners`, `Archive Course → Delete` |
| `pages/Classes.tsx` | §9 | `Export Intel → Export Scheme` |
| `pages/teacher/Extracurriculars.tsx` | §7 | `Broadcast update to members → Notification update to members`, `Broadcast Update → Notification Update` button |
| `pages/teacher/Students.tsx` | §7 | `Broadcast Notice → Notification` button |

No code identifiers, SQL columns, route paths, or variable names were
touched. Identifier substitutions happen at the schema layer (separate
follow-up, not user-blocking).

## Tier switching — a note

`ACTIVE_TIER` is currently hard-coded `tertiary`. Wiring it to
`school_settings.school_tier` (or a school-wide setting) is the next
sprint. Until that lands, every tier-aware label uses the tertiary
mappings. This matches the demo state and keeps the
default-pilot-deployable promise.

## Verification

- `npx vitest run` (client) → **45 / 45 passed** (5 spec files; 15 new
  from this PR).
- Manual diff review: every edit is a literal string change; no logic
  changes, no API surface changes.

## Out of scope

- Tier wiring (school_settings.school_tier). Tracked separately.
- §8/§9 substitutions in pages that don't exist yet (Course Scheme/Plan,
  Curriculum Portfolio). Those land in P1-UX-7.
- Identifier-level renames (variable names like `student_id` keep the
  schema's choice; no PR will rename `users.id`).
