v4.27 — Hallmark Design-Debt Remediation
Every WCAG AA floor Desi's 70-gate audit found broken is fixed, or the rule that would have prevented it is written down where the next author will actually find it.
Summary
Desi's objectuve-hallmark design-debt autopilot scored all 59 ionic_frontend/src/views/** surfaces against 70 gates (source issue OBJ-1964) and surfaced three defect families worth a milestone rather than a one-off fix: hard WCAG AA contrast and tap-target failures on high-traffic surfaces (sign-in, onboarding), a query-state-fabrication bug recurring for the third time (OBJ-1711's "an unresolved query renders as a confident, specific, wrong answer" shape), and unconverged design-system drift (arbitrary pixel type sizes, hand-rolled card recipes, raw text-white/slate-* instead of tokens).
The milestone's real payoff isn't the diffs — it's that three of those four defect families were breakable because the rule that would have caught them was never written down anywhere an author would look. Phase 5 (this page, plus docs/reference/desi-design-context.md and this project's CHANGELOG.md) exists specifically to close that gap: document the contrast rule, the type-ramp rule, the card recipe, and the query-state honesty rule, each with a concrete in-repo wrong-shape and right-shape example, so a fifth recurrence of any of them has no excuse.
teams/** was pulled out of scope entirely on 2026-08-01 (Josh's call, recorded on OBJ-1966) once the branch it needed to build on turned out to be a hard CI blocker (pr-scope-guard) rather than just a scheduling risk — it now ships as a fast-follow gated on the gsd/v4.19-teams-v1-wiring → master promotion, tracked as OBJ-1969 (which has since shipped its own PR, #1970).
Goal
Close the design debt Desi's 70-gate audit found across 59 view surfaces, and — more importantly — leave behind the guards that stop each defect family from recurring. Concretely: clear every WCAG AA floor that a real user hits; kill the third recurrence of the OBJ-1711 "fabricated state rendered as fact" query bug and land a lint rule so there is no fourth; converge the
teams/**type ramp and the app-wide token drift back onto the design system; and write the three broken rules down where the next author will actually find them.
Scope — What Shipped
- Phase 1:
Community.vuetap targets and CTA label grown to spec. - Phase 2:
Coach.vueandEnneagramTypeDetail.vueconverted to honestloading/error/empty/readystate gating via a newQueryStateCardcomponent, plus a mechanical ESLint guard (no-fabricated-query-state) against a fourth recurrence. - Phase 3 (pulled from this milestone, 2026-08-01):
teams/**type ramp + semantic corrections — moved to a fast-follow (OBJ-1969), shipped separately (PR #1970, onmaster). - Phase 4: three independent design-system convergence sweeps — a shared
.selectable-cardrecipe replacing three hand-rolled copies (and fixing a genuine light-mode invisible-border bug), a real blanketprefers-reduced-motionrule, and atext-white/slate-*token-drift sweep that also gated the internal/design-systemtoken gallery behind auth. - Phase 5: the prevention docs — four rules written down with in-repo evidence,
CHANGELOG.mdentries for every user-visible fix, and this narrative. - Not part of this milestone, but its evidence sits on
master: the OBJ-1965 contrast sweep (SignIn.vueand nine other anchors) was dispatched to Codi ahead of milestone kickoff — highest-severity finding, smallest diff, no design decisions — and shipped directly tomastervia PRs #1932 and #1934 rather than through this milestone's integration branch.
Promoted to master 2026-08-02 via PR #1987 (merge commit df03a252543a31bdcd4d19208d93850c3f5cd627), per the stranded-branch lesson CLAUDE.md's Common Gotchas documents from v4.15/v4.19/v4.13/v4.14/v4.3 — a milestone is not shipped when its phases merge, only when master contains its code. Master containment verified by content presence (scripts/check-branch-promotion.mjs) and, since the promotion itself was a real merge commit rather than a squash, by true ancestry (git merge-base --is-ancestor) as well. The promotion's full Vitest run caught a fresh alpha-modifier regression this milestone's own Phase 4b had introduced (SlideWizardLayout.vue), fixed before shipping. The Phase 2 hard gate — Coach.vue/EnneagramTypeDetail.vue's live loading/error/empty states, never visually verified through two review rounds — was cleared before promotion via Storybook + Playwright captures (10 screenshots, 5 states × light/dark).
Phases
| Phase | Name | Status | Plans | Highlights |
|---|---|---|---|---|
| 1 | Accessibility floor completion | Shipped | 1 | Community.vue tap targets 32px → 44px, sentence-case CTA (OBJ-1967, PR #1937) |
| 2 | Query-state honesty + the guard that stops recurrence #4 | Shipped | 3 | Coach.vue/EnneagramTypeDetail.vue honest state gating, QueryStateCard, no-fabricated-query-state ESLint rule (OBJ-1968, PR #1946) |
| 3 | teams/** type ramp + semantic corrections | Pulled from milestone (2026-08-01) | — | Rescoped to a fast-follow gated on the gsd/v4.19-teams-v1-wiring → master promotion; shipped separately as OBJ-1969, PR #1970 |
| 4 | Token & system convergence | Shipped | 3 | .selectable-card recipe + light-mode border fix (OBJ-2002, PR #1957); blanket reduced-motion rule (PR #1973); text-white/slate-* sweep + /design-system auth gate (PR #1964) |
| 5 | Prevention & docs | Shipped | 1 | This page, docs/reference/desi-design-context.md rule documentation, CHANGELOG.md |
| 6 | Master promotion | Shipped | 1 | PR #1987, merge df03a252 — 56-commit rebase, alpha-modifier regression caught and fixed, Phase 2 visual-evidence hard gate cleared |
Key Decisions
teams/**(Phase 3) pulled from the milestone, 2026-08-01 — the intended baseline branch,gsd/v4.19-teams-v1-wiring, turned out to be blocked outright by thepr-scope-guardCI check rather than merely at scheduling risk. Escalated to Josh rather than guessed at; decision recorded on OBJ-1966.teams/**slices were struck from Phase 4's MOTION-1 and TOKEN-1 tasks too, so v4.27 ships everything non-teams/**with zero special-casing.- The OBJ-1965 contrast sweep shipped ahead of and outside this milestone, directly to
master(PRs #1932, #1934), because it was the audit's highest-severity finding with the smallest diff and zero design decisions — making it wait on milestone numbering would have been the wrong trade. Consequence: the integration branch andmasterdiverged, so Phase 5's docs had to verify each of the four rules against the correct ref per rule (contrast and type-ramp againstmaster; card recipe and query-state honesty against the integration branch) rather than one uniform baseline. - Coverage bar revised after Phase 1: "≥80% on the lines this milestone changes, with no file-wide regression" replaces the original "≥80% on every changed file" wording, after
Community.vue(52% file-wide before and after, all of it pre-existing untouched surface) showed the literal reading would mean back-filling unrelated coverage into a design-debt PR — scope creep wearing a quality costume. - CARD-1 used
--shadow-card/--shadow-card-hoverinstead of the originally-specced--shadow-md/--shadow-lg— verified againstdesign_system/css/tokens.cssthat only the-cardshadow tokens carry a dark-mode override; following the literal task spec would have fixed an invisible-border bug in light mode by introducing an invisible-shadow bug in dark mode. - Every phase after Phase 1 branches from the tip of the integration branch, never
master— Phase 1's branch was accidentally cut from a pre-milestonemastercommit and had to be rebuilt after Riley caught it at PR time.
Requirements Coverage
This milestone is driven by Desi's 70-gate objectuve-hallmark audit (OBJ-1964), not a formal PRD or REQUIREMENTS.md — there is no requirements file to quote coverage from. Progress is tracked per audit finding in the ROADMAP's phase checklist instead.
Outcomes
- Every input placeholder and secondary-text anchor the audit flagged for stacked-opacity contrast failure now clears the 4.5:1 WCAG AA floor in both themes (on
master, via OBJ-1965). Community.vue's icon buttons and error-recovery CTA meet the 44px tap-target floor, with test coverage that asserts computed pixels rather than class-name presence.Coach.vueandEnneagramTypeDetail.vuecan no longer render an unresolved query as a confirmed, specific, wrong answer — and a mechanical ESLint guard exists so a fourth occurrence of this bug family gets caught before review.- The three onboarding/Coach-setup option-card surfaces share one token-only recipe with a real, visible border in light mode.
prefers-reduced-motion: reduceis a real blanket rule across the app, not two hand-picked animations.- The internal
/design-systemtoken gallery is no longer reachable unauthenticated in production. - The four rules this milestone exists to prevent recurrence of are now documented with in-repo wrong-shape/right-shape evidence in
docs/reference/desi-design-context.md(§5 type-ramp, §7 card recipes, §13 contrast, §14 query-state honesty), plus a query-state honesty checklist entry inCONTRIBUTING.md.
Tech Debt
- (Phase 2) The computed-dimensions tap-target rule has no mechanical enforcement. It was broken twice in this milestone alone — caught by review both times, not by CI.
ionic_frontend/tests/unit/helpers/tapTarget.tsexists to make the correct assertion easy, but nothing requires a new component's tests to use it. Open need: a lint rule or CI assertion, not a reviewer's memory. Recorded indocs/reference/desi-design-context.md§15. - (Phase 2, resolved before promotion) Live
loading/error/emptystates forCoach.vue/EnneagramTypeDetail.vuehad never been visually verified against Desi's mockups through two review rounds — CI's "Capture UI Evidence" job only screenshots the default/ready state on six unrelated routes. Cleared by Vicki before master promotion via Storybook + Playwright captures (10 screenshots, 5 states × light/dark). Recorded indocs/reference/desi-design-context.md§15. - (Milestone-level, OBJ-2039)
branch-promotion-guard's declared-branch parser flagged this milestone's own promotion against the wrong branch. The parser takes the first backtick-quotedgsd/...token in the ROADMAP file, which happened to begsd/v4.19-teams-v1-wiring(quoted in the decision-log explaining the Phase 3 rescope) rather than this milestone's own branch, named un-backticked on theDelivery model:line. Vicki verified the flag was a false positive (v4.19 is independently onmastervia PR #1956) and overrode it correctly. Filed as OBJ-2039 (backlog, not urgent); durable fix is to derive the branch from the ROADMAP filename rather than scanning prose. - (Milestone-level) Integration branch not yet deleted.
gsd/v4.27-hallmark-design-debt-remediationis confirmed promoted (content-presence verified,master...branch ahead:0) but remains onorigin. Per this repo's planning canon, deleting it removes a livepr-scope-guardcross-branch-overlap risk for other branches — flagged as a follow-up, not a docs task.
Related Artifacts
- Roadmap: v4.27-hallmark-design-debt-remediation-ROADMAP.md
- Milestone Audit: v4.27-hallmark-design-debt-remediation-MILESTONE-AUDIT.md
- Source audit: OBJ-1964 (Desi's 70-gate
objectuve-hallmarkaudit) - Related fast-follow: OBJ-1969 / PR #1970 —
teams/**type ramp + semantic corrections, rescoped out of this milestone, shipped separately tomaster - Merge PR: #1987 —
gsd/v4.27-hallmark-design-debt-remediation→master
Related Commits
917baba0a— fix(a11y): grow Community.vue tap targets to 44px, sentence-case CTA (OBJ-1967, PR #1937)dd476f245— fix(coach): delete the|| 'spark'persona fallback the UI-SPEC named for removal (OBJ-1968, PR #1946)03e9418fd— feat(coach,enneagram): add QueryStateCard for honest loading/error/empty states (OBJ-1968, PR #1946)6d7818f57— fix(welcome,coach): converge selectable-card recipe, fix light-mode border bug (OBJ-2002, PR #1957)2729c8201— fix(theme): replace narrow reduced-motion guard with a real blanket rule (OBJ-1970, PR #1973)6177398f5— fix(tokens): sweep raw text-white/slate-* drift, gate /design-system behind auth (OBJ-1970, PR #1964)fc021535a— fix(a11y): remove alpha modifiers from muted-foreground/foreground text tokens (OBJ-1965, PR #1932, onmaster)c34312bf1— fix(a11y): drop alpha modifier on text-foreground contrast anchors (OBJ-1976, PR #1934, onmaster)002e2fdbe— docs: extend OBJ-1711 gotcha for Coach.vue/EnneagramTypeDetail.vue recurrence + no-fabricated-query-state guard (OBJ-1999, PR #1950)6cae23f55— fix(tokens): drop alpha-modified foreground token on SlideWizardLayout back button (OBJ-2025)df03a252— Merge pull request #1987 fromgsd/v4.27-hallmark-design-debt-remediation(OBJ-2025, milestone promotion tomaster)
Last updated: 2026-08-02