Audited live on what is actually deployed. The task named
86b9bd1; staging.ownermind.co reports
sourceSha 7cd604b, built 06:12Z. 86b9bd1 is an ancestor —
staging is three commits ahead, and those commits touch
CoachExperience.tsx, ReviewLanePanel.tsx,
app.screener.tsx and app.css: all three of the areas asked about.
Auditing the named commit would have reported problems that were already fixed.
The premise needs one correction, and it makes the fix easier
It is not a June bug, and it is not a code bug. No coach has a portrait. All four coaches are the same silhouette glyph in four tints. The nine specialists do have real photographs — which is why the gap only becomes obvious once a coach is selected and sits in the drawer header directly above them.
Everything in the rendering path checks out, which is why this looks like a bug and is not one. Verified end to end on the deployed build:
coach-avatar coach-ava coach-face-lg c2 —
correct class for June.background-position: 0px 100% and background-size: 200% 200% —
correct cell of a 2×2 sheet.sana-coach-sprite.webp contain image data (sampled to
canvas: mean luma 121–136, std-dev 22–25, 0% transparent). June's cell is not empty.This one is mine. The deployed asset is byte-identical to
mocks/ownermind-coaches/sana-coach-sprite.webp — same SHA. I shipped that sheet
as a placeholder alongside the avatar CSS on 31 Jul so the frame could be built against
something, and it was consumed literally. The real portraits were never commissioned. My own
comment in that stylesheet says the frame is sized so "a Tavus still and a talking-head loop
are interchangeable without reflow" — the slot was always meant to hold a real face.
| Action | What | Where |
|---|---|---|
| Change | Produce four coach portraits at 418×418 into the same 2×2 sheet, same byte layout. No code, no CSS, no class changes — the mapping is already correct and will pick them up. Precedent for the treatment is the CourseVenture companion roster. | apps/web-start/public/ sana-coach-sprite.webp |
| Change | Adjacent defect, found while checking the sprites. Specialist av9
(Lena Ortiz) renders from the base sheet at 0% 0% — the same cell as
av0. My extension rule is scoped
.sana-source .drawer .roster .ava.av9, but the live element is
.coach-specialist-face.av9, so it never matches and the ext sprite is never
loaded. Rescope the selector to the class actually rendered. |
sana-avatars.css (the .roster .ava block) |
Walked Screener plus all ten assessment stages · 213 distinct strings collected
All three lines named in the brief are already removed on the deployed build. They
exist at 86b9bd1 and are gone by 7cd604b. Nothing to do — recorded
here so the same items are not re-reported.
| Action | Line | Was at | Status on staging |
|---|---|---|---|
| Done | "Ask the selected agent" | ReviewLanePanel.tsx:463<span class="sr-only"> |
This was screen-reader-only text, not visible copy. Correctly replaced with
aria-label="Message your coach or specialist" — migrated, not dropped. |
| Done | "Drafts arrive as cards you accept, edit or ignore…" | ReviewLanePanel.tsx:507 | Removed. |
| Done | "Research time protected: evaluated…" | app.screener.tsx:387 | Removed. |
What is left. The work area is clean — only three instructional strings repeat across stages at all, and each belongs to the stage it is on. The remaining redundancy is in the drawer:
| Action | Line | Repeats | Why |
|---|---|---|---|
| Change | "I'll stay with what is on this page, question the gaps, and keep every draft separate until you decide what enters your assessment." 12.5px | 11 of 11 surfaces |
The one genuinely redundant line. It is a promise about how the coach behaves, which is true once and does not change per stage. Show it on first session or until dismissed, not on every navigation. |
| Keep | "Your coach: <name>" 14px | 11 of 11 | Identity, not instruction. It should persist. |
| Keep | The nine specialist descriptors — "Source coverage, citations, and evidence gaps", "Independent counter-work and falsifiers", … 9.5px, visible | 11 of 11 | These are the only thing distinguishing nine faces, and they double as the
buttons' accessible names. Keep the text. If the roster is ever collapsed to faces alone,
move them to title/aria-label — do not delete. |
| Keep | "Why does it matter?" 13px | 11 of 11 | A control, not a caption. |
The item named is real, and the reason is not size alone. "Include delisted companies"
is label.check at 12.5px, sentence case. Every other field label in the same
Screener form is a .flab span at 9.5px, uppercase, letterspaced. It is ~32%
larger and in a different case treatment than its immediate siblings — that mismatch is
what reads as oversized. .check is declared only in app.css, away from
the rest of the form's typography.
The larger finding underneath it: the field-label tier is defined on only 5 of 11
stages. .flab gets the 9.5px uppercase treatment on screener,
first-pass, decision, allocation, monitoring. On risk, memo, compound, quality and
valuation no font-size rule applies, so labels fall back to the 16px root default —
bigger than the 13px panel headings that contain them, and second only to the page title.
Measured on Risk: 12 of 12 labels at 16px.
A grep for the selector is misleading here, which is worth flagging to whoever fixes it:
.sana-source.sana-page-risk .flab does exist, at
sana-pages.css:822 — but it only sets overflow-wrap:anywhere. The
element matches the rule and still has no size.
| Action | What | Where |
|---|---|---|
| Change | Give .flab one declaration that is not page-scoped — 9.5px, uppercase,
.13em tracking, var(--cream-3) — and delete the five per-page
copies. Field labels are not a per-stage decision. |
sana-pages.css:82, 225, 894 + allocation, monitoring |
| Change | Fold .check into the same tier so a checkbox label matches the labels beside
it, and move it out of app.css into the page stylesheet with the rest of the
form. |
app.css |
| Change | Page titles render 32px. The hierarchy verified in July was 27 for page titles and 20 for section headings. Risk currently carries 8 distinct font sizes, Screener 6. | stage stylesheets |
No regression from the copy pass — I checked before assuming one. All seven Screener
form controls have a real accessible name; none relies on a placeholder; no orphaned
.sr-only nodes are left behind. The items below are the accessible name itself, so
they will look like removable instructional copy and are not:
aria-label="Message your coach or specialist" — the ask textarea. This is what
replaced the removed sr-only span; deleting it leaves the input unnamed.<label> on all six Screener inputs — including
"Include delisted companies". Restyle it; do not unwrap it.aria-label on each of the nine specialist "bring in" buttons — they carry the
only role description those faces have.aria-label="Hide the coach panel" and
"Show <name>'s coach panel" — the only names on those two controls.role="status" on the saved indicator./app/progress still carries the light cards from the earlier contract;
app.css is untouched on that point and the page renders empty on a new account,
so it cannot be judged from here.staging.ownermind.co, sourceSha 7cd604b
(builtAt 2026-08-03T06:12:35Z), signed in on an isolated QA account.
Named ref 86b9bd1 is an ancestor, three commits behind.
Review only — no code, no deploy, no routing.