Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Roadmap

MOTIR-3998Done

Nothing in the guard tier can SEE a material leak — the cascade model skips every combinator by construction, so the style axis needs a rendered isolation guard

Opened by Zhu Yue ·

MOTIR-3947 shipped 10 of 11 style previews wearing the wrong material for months with a full green board. This card is about why nothing caught it.

The gap, quoted from the instrument itself

tests/theme/paletteCascade.ts — the cascade model scopedPreviewIsolation.test.ts resolves every assertion through — states its own limit in its header:

The model deliberately does NOT understand descendant/child combinators or class selectors: any rule carrying one is component-scoped ([data-style='glass'] .card), not part of the root token layer, and is skipped.

That is a correct design decision for a TOKEN-layer model and it means the suite that proves the palette and type axes isolated is structurally incapable of seeing the style axis's defect. The style axis does not break in the token layer; it breaks in the selector layer. So there is no assertion to add to that lane — the guard has to render.

What to do

Add a spec to the browser lane, beside tests/e2e/appearance-sync.spec.ts and tests/e2e/shell-a11y-tokens.spec.ts. app/tokens/page.tsx already renders the eleven scoped StyleVignette tiles (its style gallery, ~line 349) and is not behind auth, so the surface exists.

The oracle is the stylesheet, never a table of expected values — the rule scopedPreviewIsolation.test.ts already establishes for the palette axis, and for the same reason: a hard-coded expectation needs re-typing every time a style is tuned, and the first person to skip that turns the guard into a test of a stale table.

  1. For each of the eleven styles, read the computed material properties of the tile's data-surface elements (card, modal, sidebar, input) plus its .sv-canvas: background-color, background-image, backdrop-filter, box-shadow, border-color, and the ::after reads that hand-drawn-indie and retrofuturism paint with.
  2. Compare each against what that same tile renders when <html> carries its own style — identical DOM in both arms, so the only variable is the ancestor. Drive <html data-style> through the page's own style control rather than by injecting an attribute.
  3. Assert over more than one ancestor. Under warm-editorial the matrix is 11/11 even with the defect present, because the base ships no block and has nothing to leak — a spec that only ever runs under the default style passes on a broken page. Exercise at least glassmorphism and neumorphism (1/11 each before the fix) and warm-editorial as the control.

Acceptance criteria

Every criterion is checkable on this card's own branch, before it merges.

  1. The spec FAILS against the pre-fix stylesheet — check out the commit before [the @scope rewrite], run the spec there, and quote the failure and its count in the pull-request body. A guard authored after its fix and never run against the defect asserts a tautology; this criterion is the whole reason the card exists and it is not discharged by reasoning about it.
  2. It passes on this branch, whose base already carries [the @scope rewrite] — reported as the matrix rather than a bare boolean. The failing output must name WHICH tile wore WHICH ancestor's material, because that is what makes a future regression diagnosable from the CI log alone. The pull request's own green check is the evidence; do not write a criterion that can only be read after this card has merged.
  3. At least three ancestors are exercised, one of which is a non-material style used as the control.
  4. It runs in the pull request's ordinary lane — no e2e-at-scale label, no new CI job, no new test project in vitest.config.ts.
  5. tests/theme/paletteCascade.ts's header gains one sentence naming where the style axis's guard now lives, so the next reader of that limit is pointed at the answer instead of concluding the axis is unguarded.
  6. Ships in motir-core only.

Discussion

No comments yet.

Adding to this discussion signs you in on app.motir.co and brings you back to this request.

Add a comment