Conversation
The term page drew its breadcrumb twice — once in `SozlukTermHeader`, once inline in `NewTermComposer` — and the two copies drifted. #9355 and #9331 each landed on the header alone, leaving the composer's letter crumb pointing at `/sozluk` (where the root crumb beside it already goes) and naming the letter with `slug.charAt(0).toLowerCase()`, which reads `IŞIK` as `i` when that headword is `ı`'s everywhere else. `SozlukTermCrumbs` now owns the markup for both branches and takes the letter as a prop: the stored `first_letter` column from the header, `sozlukLetterOf(slug)` from the composer, which is the same Turkish-aware fold every producer of that column shares. A slug the alphabet does not index yields `null` and renders no letter crumb, matching the header. Both crumbs are router `Link`s, so a click no longer reloads a route the SPA owns. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
🚀 Preview deployed
|
|
review-code: PASS @ d767a0a content:9667aae9291e — merge-ready Round 1, code class. Namespaces this head derives: Per-criterion verification
Standing checks
Non-blocking notes (no criterion turns on either; neither routed to the contract)
Deviations
Nothing undisclosed that this gate could see; the section is present and none of it is falsified.
Verdict-written: 2026-09-21T04:49:38Z |
review-ui: CANT-SEE at d767a0aNo verdict posted. The one state this PR changes for a reader never painted, so a PASS here would What I could renderPreview
What I could not render, and why
The
The refusal is post-signing, so the failure is on the preview side of the cookie, not an unset The half that did paint, and what it shows
Deterministic tierNot recomputed. Not this PR'sCrumb link styling is #9608's. |
|
The rendered-visual gate could not see this PR's surface at The surface this PR fixes is Exact refusal, exit
What I ruled out this round, so the next operator does not re-seed for nothing:
That leaves one unverified piece: the No verdict posted, and none is inferable: the composer's crumb never painted, so this ticket's |
The sözlük term page drew its breadcrumb twice:
SozlukTermHeaderfor a term that exists, and asecond copy inlined in
NewTermComposerfor a slug nobody has defined yet. The two drifted —PR #9600 (#9355) and the fold fix (#9331) each landed on the header alone, so the composer was
still pointing its letter crumb at
/sozlukand folding the letter withslug.charAt(0).toLowerCase().Which file owns the crumb markup now
apps/web/src/components/sozluk/SozlukTermCrumbs.tsx— new, and the only renderer of.kp-sozluk-term__crumbson this page. Both branches render it:apps/web/src/components/sozluk/SozlukTermHeader.tsxpasses the storedfirst_lettercolumn.apps/web/src/pages/SozlukTermPage.tsx(NewTermComposer) passessozlukLetterOf(slug)fromapps/web/worker/features/sozluk/turkish-alphabet.ts— the term does not exist yet, so there isno column to read, and that leaf module is the fold every producer of the column shares.
The component builds the target through
sozlukLetterHref(letter, false)and renders no lettercrumb when the letter is empty or
null. So there is one derivation site per branch feeding onemarkup, and a fourth crumb fix cannot land on only one view.
Both crumbs are router
Links now; the composer's were raw<a href>, a full page load on aroute the SPA already owns.
Tests
apps/web/src/pages/SozlukTermPage.test.tsxgains aNewTermComposerbreadcrumb block coveringthe Turkish pairs —
IŞIKandışıkboth resolve to/sozluk/harf/%C4%B1,İMECEandimeceboth to
/sozluk/harf/i— plus the unindexed slug (3-adimrenders one crumb link, the root) andthe two-
Linkrouting assertion.SozlukTermHeader.test.tsxis unchanged and still passes throughthe shared component. 17/17 green in
apps/webprojectclientfor the two touched files.fabrika build check --surface codeis green.Deviations
Said: attach before/after captures of the rendered surface.
Did: shipped with no captures; the DOM assertions in the tests stand in.
Why:
fabrika ui render --surface /sozluk/<slug>exits 11 in this worktree —app "web" did not answer 200 on /api/health within the readiness bound — every surface is UNKNOWN, the worker backend never binding (ECONNREFUSEDon the vite proxy). Reproduced twice. That is the known worktree render gap tracked in A fresh worktree cannot render the web surface: .env.example has no Cloudflare credentials #9497, so the before state was never capturable either.Disposition: the PR preview is the rendering surface for this change; the render gap is on the record for the design gate to judge.
Said: the ticket offers a shared breadcrumb component or a narrower in-place fix.
Did: took the shared-component route.
Why: acceptance criterion 6 asks that the two views stop carrying independent letter derivations, and the in-place fix would leave two copies of the markup that already drifted twice.
Disposition: intended;
SozlukTermCrumbs.tsxis the one owner, named above.Said: keep the diff to this ticket's surface.
Did: exported
NewTermComposerfromSozlukTermPage.tsx.Why: the crumb is asserted against the real component rather than a re-implementation of its derivation.
Disposition: intended; no other call site changes.
Said: build to the repo's design law.
Did:
LAW-SOURCE: manifest-prose.Why:
fabrika ui manifestreports no typed prohibition registry ("registry": null).Disposition: no new tokens, values or styles in this diff; markup, class names and CSS are unchanged, so no visual change is intended. Crumb link styling belongs to Sozluk term crumbs read as plain text, letter-page crumbs as links #9608, and
SozlukTermPage.cssand the subnav chrome are left alone so this does not collide with fix: /pano overflows the mobile viewport: 500px of document in a 390px window #9586.Fixes #9602
🤖 Generated with Claude Code