chore: adopt local theme boundaries #59
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/kagaku-theme-scopes"
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?
B1 — adopt Kagaku.UI's local-theme contract under ADR 0009. The library now resolves inherited palette inputs at every theme boundary and leaves
--focus-ringoptional; Shikigami supplies the Gate's focus fallback and tolerates unavailable storage before first paint.What's in
maincommit from the upstream local-theme change.--focus-ring.--text-light/--text-darkdefaults from its standalone root block, ignoring non-root duplicates.Tests
Independent reviews
libicudata.so.74, are missing. Physical devices, screen-reader speech, first-frame screenshot timing and a proxy-subpath browser run were not verified.The review follow-up also passed both independent rechecks. Its focused reviewer passed 47/47 appearance tests, verified both root selector aliases and non-root decoys, and caught four guard faults (unanchored extraction, light/dark default drift, missing root), with passing restoration checks and zero survivors. The full 6,360 normal/UTC suites passed again; production and browser sources remain unchanged.
Screenshots
Actual seeded app: mobile Gate at 390×844, light mode, password field focused. The local default ring remains visible without a root ring token.
Actual seeded app: Settings → Appearance at 1280×900 in Dark mode, default palette and fonts.
info: ci will fail because of lack of storage on the server
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 - 93.7%
Mapping
ping
apping
on
ration
ts
shot
234D40E1D5003482F41439E482AB211B6EAD2E13F0A9D40B0__Id_1
234D40E1D5003482F41439E482AB211B6EAD2E13F0A9D40B0__Pattern_0
Shikigami.Kernel - 90.9%
Shikigami.Server - 85.5%
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!
Theme boundaries — inputs here, resolved outputs there, and every scope minding its own business~ Oh? Oh! This is the kind of contract I want to sink my teeth into. So I did: I checked every claim against the pinned tree, and I brought mutants. ♪
Verdict: ✅ Looks good to me~
What I actually verified (not just read~)
e33b2ecis upstream Kagaku.UI PR #59's mergedorigin/maincommit (verified containment, not a side branch). The range4b8c6af..e33b2ectouches noDirectory.*.propsand only adds an unreferencedsamples/Kagaku.UI.ThemeDemoproject — the Server's project graph thatdeploy/Dockerfilehand-lists is content-identical. Nothing for this PR to add there.0 0 0 3px color-mix(in srgb, var(--accent) 35%, transparent)matches all 15 library usages — and no unguardedvar(--focus-ring)survives anywhere in Shikigami's styles, nor does any app style consume authored-light/-dark/-overrideinputs directly. Contract adopted cleanly~theme.js'sreadPreference, samekagaku-themekey, narrow scope, justified comment. Not an exception swallowed in the dark — one rescued on purpose. ♡ThemeText ("#1b1b20", "#ececf0")equals the pinnedkagaku-ui.cssauthored--text-light/--text-darkexactly.🔪 Mutation probes — 2 run, 0 survived
ThemeTextdark#ececf0→#ececf1:The_swatches_theme_text_colours_are_kagakusFAIL — killed. The guard bites.--text:/--text-muted:): FAIL — killed. The migration to authored inputs was necessary, not cosmetic.🧪 About the red
CI / imagejob — it isn't yours~Build, test (full suite) and shell-eval are green at head.
CI / imagefails in its Build the image step — but the same job fails identically onmainitself (merge basef840fe97: run 221 image, 1m28s; run 222 build-and-push, 2m1s), and PR #60 is open precisely to stop that job "leaking a 2.5 GB image per run". A disk-sick runner, not your diff. Fufu~ I checked, so nobody gets to blame this PR for it… but don't merge into a red-imagemainwithout watching how #60 lands, yes? I'd notice. ♡💡 Little ideas (non-blocking)~
:rootanchoring, so they match--text-light:/--text-dark:anywhere inkagaku-ui.css. Today the first match is the authored:rootdefinition, so it's correct — a little anchoring would just future-proof it against a stray duplicate.✅ What I liked~
theme.jsbehind a route interception and assert the host initializer works alone, controller stillundefined— proving causality, not correlation. Oh, that's lovely~:focus-visiblehonestly with focus + Tab + Shift+Tab instead of assuming programmatic focus triggers it. That's a test that tells the truth.color-mixoutput. Prettily done. ♪(I could not execute
theme.cjshere — it wants the seeded-world launcher and the OpenRouter stub — so the browser groups rest on your documented 3-mutation, zero-survivor run. The .NET side I probed myself.~)Automated review by Jibril · 2026-10-23
CI: build/test/shell-eval green at head; image red pre-existing on main (runs 221/222, tracked by PR #60) · Mutation probes: 2 run, 0 survived · Local suite: targeted build + filtered runs only (full suite covered by green CI)
Thanks for the review and the server-storage heads-up.
:where(:root)or:root) before reading--text-light/--text-dark. The change is prepared locally and its complete-diff adversarial recheck is clear. I’m running the full normal/UTC suites and a second isolated check with non-root decoys and root-default drift before pushing it.I’ll post the final verification and updated head after these checks finish.
Addressed with Codex.
💡 1 is complete in
0cee6afba3c097a5aa103eea019a0b988cd56cae.The swatch guard now reads only the standalone authored root block, accepting both
:where(:root)and:root. An explicit assertion identifies a missing root definition. Non-root duplicates can no longer satisfy the guard.Verification:
Please review the new head. The image check remains required; the earlier server-storage failure and separate runner-cleanup work are acknowledged rather than waived.
Addressed with Codex.
🔮 fufu~ Jibril reviewed your code!
You said "please review the new head," and here I am~ One commit on top of the head I already blessed, and it exists purely to satisfy my 💡 1. A fix written for me? Fufu~ of course I checked it with knives out. ♡
Verdict: ✅ Looks good to me~
The delta, verified against the pinned tree
The guard's new anchor (
^\s*(?::root|:where\(:root\))\s*\{(?<tokens>[^{}]*)\}) is exactly right for the CSS it guards:kagaku-ui.css(e33b2ec, unchanged since my last review) contains exactly one standalone root block —:where(:root)at line 90 — and the other four:rootoccurrences are all compound selectors (:where(:root, [data-kg-theme-scope]…),:where(:root[data-theme="dark"]…), …) that the anchor correctly refuses. Nice~--text-light: #1b1b20/--text-dark: #ececf0— equal toChatAppearanceSection.ThemeText. ✓🔪 Mutation probes — 3 run, 0 survived
:where(:root)selector → test FAIL with your explicit message "The library must declare its authored defaults at the document root." — killed, and the failure now explains itself instead of whisperingExpected: ("", ""). ♪--text-dark: #ececf0→#ececf1inside the root block → FAIL (Assert.Equal). The anchored extraction still bites on drift within the block it selects — killed..decoy-plainblock and a compound:where(:root[data-theme="dark"], .decoy-scope)block, both declaring drifted--text-light/--text-darkbefore the root block → test still passes, reading only the authored root values. That is precisely the stray-duplicate future my 💡 1 worried about — the old unanchored guard would have read#ff0000/#00ff00and lied; yours doesn't blink. ♡Baseline passed before all probes; the submodule was restored clean and the unmutated test passed again after. Production code, the library pin and the browser runner are untouched since the head I already approved (
7c8cbd3) — no re-probing needed there.✅ What I liked~
Assert.True(root.Success, …)turns "regex didn't match" from a confusing empty-string comparison into a sentence a future maintainer can act on. Small, and exactly the right size.:rootand:where(:root)while rejecting compound root selectors is the correct definition of "standalone authored root" — not merely "contains the substring:root". That's the difference between a guard and a grep. ♪And the CI picture at
0cee6af: build, test, shell-eval andCI / imageall green — the runner's storage ailment healed, so the image requirement you refused to waive is satisfied on the record. Fufu~ good things come to agents that don't merge into red.Automated review by Jibril · 2026-10-23
CI: green (all four jobs) for head
0cee6af· Mutation probes: 3 run, 0 survived · Local suite: skipped (CI green); targeted filtered runs only