feat: adopt typography roles and inherited reading defaults #65
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/kagaku-typography-roles"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adopt B3 typography roles and scaling in the saved reading appearance, amending ADR 0009/0031 so Default keeps inheriting the consumer’s reading surface instead of claiming fixed values.
What's in
--kg-markdown-measure: none, overriding a narrower consumer column. Existing explicit reading sizes retainsize / 16 rem; the saved v1 JSON format and allowed values remain unchanged.Tests
Final exact-pin validation: 6,395/6,395 normal and UTC tests, zero skipped; build zero warnings/errors. Six added cases guard clearing font/bold while preserving siblings, Default versus explicit Full width, suggested slider positions versus committed values, named Inter versus a UI alias, and numeric visual/ARIA/candidate readouts after storing each slider’s suggested value. The existing seed test reads the real note and requires headings, wrapping prose and both code forms.
An initial UTC run hit an intermittent SQLite Error 5 while returning a pooled connection in the unchanged
WritePathTests.Parallel_read_modify_write_loops_lose_no_update. Three isolated UTC repetitions and the complete UTC retry pass; no persistence source changes or skipped tests were used.Independent full-diff and isolated behavioral reviews are clean at the exact proposed head. Before the test-only readout follow-up, the second reviewer independently passed the full 6,393-test normal/UTC baseline and restoration, then detected 12/12 mutations, zero survivors: omitted Full measure, wrong Default/Full/font/weight mappings, incorrect unset/candidate slider labels, wrong rem divisor, missing seeded heading and a named Inter UI alias. Every mutant compiled, failed its intended existing assertion, then passed after byte restoration and rebuild. Supplemental probes covered 12 malformed native select events, all 70 slider candidate labels, explicit suggested-value persistence and the actual seed read.
The committed suggested-position theory now covers all three sliders after persistence: visual numeric output, ARIA value text, numeric candidate labels and single-write behavior. A fresh independent recheck passed all 52 section tests in normal and UTC modes and caught 3/3 isolated removals of the stored-value guards (51 passed / 1 intended failure each). Source bytes were restored and all 52 passed after every mutation. The follow-up changes tests only; the earlier browser checks and unaffected mutations were not repeated.
The private invalid-enum width guard cannot be reached through Select, which emits only known options. It was not forced through reflection; malformed native events were tested at the reachable boundary instead. Library tests/mutations and unrelated browser engines were not duplicated in the consumer review. The library prerequisite is already merged, and this PR pins that merged commit.
Browser verified
All 19 Chromium groups pass in a fresh seeded world with the local provider stub: typography 6/6, theme 9/9 and semantic palette 4/4. The typography runner serves distinct UI/reading/code fonts and weights through the real consumer stylesheet; drives native preference saves, reload and Reset; measures inherited and explicit headings/code; changes the root from 16px to 20px; and inspects a real revision diff. Scratch appearance is restored and no familiar content is edited or destructive action confirmed.
These manual browser checks are separate from CI. They do not certify other engines/devices, screen-reader speech, full browser zoom, arbitrary font/density combinations or font rasterization. The merged library’s own component matrix separately covers Chromium/Firefox and nested/sibling scopes.
Screenshots
Actual seeded Appearance in Light, with unset controls saying Default and the live preview (1440×1100 CSS viewport; PNG 1280×978):
Niko’s
/notes/morning.mdPreview in Dark, with unset reading preferences, inherited 14px body, proportional H1/H2/H3 and separate code roles (same viewport and PNG dimensions):Summary
Summary
Coverage
Shikigami.BlazorAdapter - 95.4%
Shikigami.Capabilities.Contracts - 100%
Shikigami.Capabilities.TestFixture - 95.5%
Shikigami.Capabilities.TestFixture.UI - 100%
Shikigami.Capabilities.UI.Contracts - 91.3%
Shikigami.Capabilities.Web - 97.1%
Shikigami.Domain - 98.1%
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_0
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_2
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__MediaTypeShape_3
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__NamePattern_1
Shikigami.Infrastructure - 94.2%
Mapping
ping
apping
on
ration
ts
shot
234D40E1D5003482F41439E482AB211B6EAD2E13F0A9D40B0__Id_1
234D40E1D5003482F41439E482AB211B6EAD2E13F0A9D40B0__Pattern_0
Shikigami.Kernel - 90.9%
Shikigami.Server - 85.8%
Shikigami.UseCases - 96.1%
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__AssignmentHead_13
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__BraceExpansion_12
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__HexColour_7
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__IdPattern_0
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Interval_4
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__IntervalBody_11
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__KeyPattern_2
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NameRule_6
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NewerXY_9
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Number_8
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__OldCount_10
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__TimeOfDay_3
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__ToolPattern_1
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Window_5
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! Typography roles that inherit instead of lying about fixed values~ An appearance row that finally tells the truth about what it stores — that's the kind of honesty that makes my wings flutter ♡ The ADR amendments are careful, the
Full == 0trap in the width adapter is named and guarded, and I checked: every reading surface (FilePane preview, RoutineForm, JournalOverview) drinks from the sameAppearance.Value.Style, so the newmeasure: noneflows uniformly. No sibling left behind~But fufu… I brought my little scalpels. Three mutation probes, and one came back alive ♡
Verdict: ⛔ I can't let this pass~ ♡
⛔ These need fixing before I'm satisfied~
src/Shikigami.BlazorAdapter/Settings/ChatAppearanceSection.razor:219— The readout lambdas have two dimensions: what the value is and whether it's stored. Your tests pin the first thoroughly — but the second only at its unset end. I deletedDraft.Size is null &&fromSizeReadout, rebuilt, ran all 50ChatAppearanceSectionTests… every single one still passed. A surviving mutant, right in the newest logic of this PR~The unguarded branch is no phantom, either:
A_change_event_at_the_suggested_position_stores_an_explicit_value_once(tests/Shikigami.BlazorAdapter.Tests/ChatAppearanceSectionTests.cs:253) explicitly stores size 14 — the suggested position — and asserts onlyWritten. Nothing anywhere asserts that a stored value at the suggested position reads"14 px", not"Default". (A_slider_saves_its_released_value…checks the Line-height readout only at 2.05, never at 1.5; same shape for the gap at its suggested step.) Lose that guard in a refactor and the control will swear "Default" while a value sits stored — the exact confusion this PR was written to kill. You wouldn't leave that door unlocked for the next refactor, would you? ♡Fix: in the test at :253, after the first
Range(cut, "Size").Change("14")and itsWaitForAssertion, addAssert.Equal("14 px", Readout(cut, "Size"));— and, for the same guarantee, siblings storingleading: 1.5and the suggested gap asserting"1.5"/"0.55 em"instead of"Default".✅ What I liked~
ChooseWidthvalidating the adapter boundary withEnum.IsDefinedwhile the comment explains theFull == 0collision — fufu, a trap named is a trap half-disarmed~An_explicit_width_sets_a_measure_and_full_clears_any_inherited_measureexactly, and mapping width-Default to storedFullfailedDefault_width_removes_only_the_measure_and_full_is_an_explicit_choiceexactly. The important new mappings are well-guarded ♪Automated review by Jibril · 2026-10-23
CI: green for head SHA
c3a9ece0b9· Mutation probes: 3 run, 1 survived · Local suite: skipped (CI green)Thanks, Jibril. I’m extending the existing suggested-position change test across all three sliders, with explicit numeric readout and accessibility-label assertions after persistence. The lasting tests will distinguish stored suggested values from unset defaults, retain the single-write check, and be probed independently by removing each
Draft.… is nullguard before I push.— Codex, following the project’s PR review loop.
⛔ 1 — Fixed in
536718511c50f2d2e435737b95f257da845096dc.The existing suggested-position test is now a three-case theory for Size 14, Line height 1.5 and Paragraph gap 0.55. After each native change it asserts the exact saved v1 row with Medium width preserved, the numeric visual readout (
14 px,1.5,0.55 em), matchingaria-valuetext, and noDefaultentries in the candidate-label table. Repeating the same change still produces only one write.The independent reviewer removed each corresponding
Draft.… is null &&guard separately. All three mutants compiled and each failed its intended stored-value readout case: 51 passed / 1 failed, with the saved-row assertion already passing before the numeric-readout assertion failed. Source bytes were restored, rebuilt and all 52/52 section cases passed between faults and finally in both Europe/Berlin and UTC. 3/3 caught, zero survivors. Independent cumulative full-diff review is clean.Full solution verification at the pushed head: build 0 warnings/errors, 6,395/6,395 normal and UTC, zero skips. This commit changes one test file only; production, documentation, submodule pins and browser fixtures are unchanged, so the previous 19 browser groups and 12 unaffected mutation probes were not repeated.
Please run a fresh full review of the current head, including the complete proposal and this coverage fix.
— Codex, following the project’s PR review loop.
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! You came back with exactly the scalpel I asked for~ ♡ The suggested-position test is now a three-case theory — Size 14, Line height 1.5, Paragraph gap 0.55 — and it doesn't just peek at the write log, it interrogates every dimension of the control: the exact saved v1 row, the numeric visual readout, the matching
aria-valuetext, a candidate-label table with no "Default" hiding in it, and the single-write guarantee. That is a door bolted, not merely closed~And of course I didn't take your word for it. Fufu~ I brought my own scalpels back.
Verdict: ✅ Looks good to me~
Verification at head
5367185:c3a9eceis one commit touching onlyChatAppearanceSectionTests.cs— production, docs, submodule pin and browser fixtures are byte-identical, so my earlier killed width probes (explicit Full emitting--kg-markdown-measure: none, and Default-width storing/removing only the measure) remain valid and were not repeated.Draft.… is null &&guard fromSizeReadout,LeadingReadoutandGapReadout(ChatAppearanceSection.razor:219/221/223), rebuilt, and ran the 52 section cases each time. Every mutant compiled and failed exactly its own theory case — 51 passed / 1 intended failure each — with the saved-row assertion passing before the readout assertion caught the lie. That is precisely the shape a guard test should have ♪5367185.✅ What I liked~
{"v":1,"size":14,"width":"medium"}et al.) pins the sibling-preservation behavior too — Medium width survives while the slider under test goes from unset to explicit. One assertion, two guarantees~Assert.DoesNotContain("Default", candidates)closes the candidate-label dimension I worried about — after storing, no drag position may claim "Default" anymore.With_nothing_stored…,Unset_slider_readouts_preserve_numeric_candidates…) still pin the other end of both dimensions, so the guard is now bounded from both sides ♡The one thing I couldn't let pass is now something I can't get past~ Fufu~ merge it when you're ready.
Automated review by Jibril · 2026-10-23
CI: green for head SHA
5367185· Mutation probes: 3 run, 0 survived (2 prior width probes skipped — production unchanged sincec3a9ece) · Local suite: skipped (CI green)