- Per-author identity primitive on the v1 surface — closes the named rev-130 next-sprint candidateRev 130 shipped the dashboard avatar primitive (initials chip + deterministic per-author HSL hue) on the rev-130 task comment thread head + rev-30 mentions inbox row head, but duplicated the helpers across both consumers because they were 12 lines each. Rev 130's running state explicitly named 'per-author identity primitive on the v1 surface' as the rev-131 candidate, citing the cost of every MCP host re-implementing the hash + initials logic. Rev 131 closes that. New shared `@/lib/author-identity` module exports `authorInitials(name)` + `authorHue(userId)` + `getAuthorIdentity(userId, name)` — same hash + initials rules as the rev-130 dashboard helpers so existing avatar colours don't shift. Both dashboard consumers (task-comments.tsx + mentions-inbox.tsx) import from there now. The v1 `GET /api/v1/tasks/{id}/comments` projects `authorInitials` + `authorHue` on every comment row + on the rev-129 distinct-authors sidecar (so MCP hosts rendering an author picker draw the same chip per author with one shape, no follow-up call). The POST handler also returns identity on the new comment so callers chaining create-then-render don't have to re-fetch the listing endpoint. Typed in the OpenAPI 3.1 spec in lockstep with the v1 mirror — the cadence pattern from rev 78 onward (every v1 enhancement gets typed in the spec in the same cycle) holds unbroken into rev 131.
- Match highlight on the rev-111 marked.js HTML render path — closes the rev-130 highlighting symmetryRev 130 shipped match highlighting on the short-comment renderCommentBody path (plain-text comments) — but long markdown comments rendering through `c.textHtml` (server-rendered marked HTML, rev 111) skipped the highlight, so an operator searching a long structured comment for 'concern' saw the filter narrow but had to re-read every rendered paragraph to find WHERE the match was. Rev 131 closes that gap. New `highlightCommentHtml(html, query)` helper splits the HTML on tag boundaries, walks every text-content segment, and wraps matched substrings in the same `<mark className='ld-task-comment-match'>` the rev-130 plain-text path uses — tag content (attributes, element names, class names) is left untouched so existing markup, links, and @-mention pills all stay intact. Pairs with the rev-130 plain-text highlight so the keyword filter highlights matches identically across both render paths.
- Match counter chip + ↑↓ arrow-key navigation through search matchesUntil rev 131 the rev-128 keyword filter narrowed the visible thread but operators with multiple matches across a long thread had no surface for 'how many matches?' or 'jump to the next one' — they scrolled the filtered subset by hand. Rev 131 closes that with two paired primitives. (a) Compact 'N/M' counter chip beside the search input shows the active match index + total match count, with a tooltip explaining the keyboard shortcuts. Brand-color teal palette ties the counter to the rev-130 match-highlight palette so the counter and the highlight read as one feature. Tabular-num typography keeps the index numerals vertically aligned as the operator rotates through. (b) ↑↓ arrow keys + Enter (when the search input has focus) rotate through matched comments. Wraps at the ends so an operator at match #N tapping ↓ lands on #1. Cmd/Ctrl-modified keys are deliberately not handled so browser shortcuts still work outside the input. The active match gets a brighter brand-color outline + glow distinct from the rev-130 default match treatment so the eye lands on the active one first. The matched comment scrolls smoothly into view via `scrollIntoView({ block: 'center' })` 50ms after the highlight commits so the brighter active treatment + the scroll arrive at the same time.
- Cumulative dashboard polish — brand-color active-match outline + tabular-num counter typographyCumulative micro-polish (every rev 22+ has carried at least one). New `.ld-task-comment-active-match` CSS uses a 2px brand-color teal outline + 4px offset + 6px border-radius so the active match reads as the operator's current focus across both render paths (plain-text + marked HTML). New `.ld-task-comment-match-counter` chip wears the same brand-color teal palette + tabular-num typography so the index doesn't shift width as the operator rotates through. The active-match treatment composes cleanly with the existing rev-31 deep-link permalink flash — both can fire on the same comment without competing visually since the active-match class applies to the row outline + brighter inner highlights, while the deep-link class applies to the row background flash. Three orthogonal visual cues for three different reading horizons (active match / deep-link arrival / default match) anchored in the same brand-color palette.