Sweep follow-up to 113bd55a — same defensive pattern (reject unknown enum strings at the entry boundary) applied to every other builder that indexed a Record<EnumLiteral, T> with a value sourced from raw JSON args. Builders + enums covered: - buildTag — TagTone (default | accent | success | warning | error) - buildCallout — CalloutTone (info | success | warning | danger | note) - buildActivityLog — tone (info | success | warning | danger | neutral) - buildInviteRow — InviteStatus (pending | expired | accepted) - buildMemberRow — trailing.tone for status_dot (online | busy | away | offline). role_badge / menu variants skip the check (no tone field) Same failure mode each one fixed: when a model invents an out-of-enum string (gpt-5.4 did this with `level: "caption"` in ab-v4), the lookup `TONES[bad]` / `STATUS_TONE[bad]` returned undefined, the next property access crashed mid-batch with a cryptic `undefined is not an object`, and the surrounding dispatch loop dropped every remaining tag (until df33e937 + 07639f6d landed the per-shape continuation + partial-doc scoring earlier today). With validation in place, a bad enum becomes a clean per-shape error message + the rest of the batch still applies. 13 new edge-case tests cover throw on bad input + valid path on every enum value + omitted-default for each builder. 3785 vitest pass, format clean, tsc silent. Builders not touched: heading.ts (already done in 113bd55a). Builders that don't fit this pattern (no enum→Record lookup of a user-controlled string): everything else surveyed via grep on `Record<.*Tone|Status|Level|Mode|Kind`. |
||
|---|---|---|
| .. | ||
| agent-native@e1f90cab96 | ||
| pen-acp | ||
| pen-ai-skills | ||
| pen-core | ||
| pen-engine | ||
| pen-figma | ||
| pen-mcp | ||
| pen-react | ||
| pen-renderer | ||
| pen-sdk | ||
| pen-types | ||
| CLAUDE.md | ||