bread-theme: mark five declared-but-unconsumed schema keys as such in schema and theme.toml

audit-schema-consumption.md's recurring defect: a key that validates
but does nothing, five separate instances (css/extra.css overlay,
tokens.font_family, tokens.font_fallback, tokens.font_size_base,
tokens.accent_to). All five are consumed only by breadbar/breadbox,
which this pass doesn't touch, so per the audit's own (a)/(b)/(c)
choice this is (b): document the gap at both the schema accessor and
every theme.toml site that sets the key, so the manifest states its
design intent honestly instead of implying the value has an effect it
doesn't.

Also documents modules.clock.format/show_date (consumed only by
ClockStyle::Plain, silently ignored by Flip/None) and
bar.window.margin.bottom (parsed, never applied by breadbar) the same
way.
This commit is contained in:
Breadway 2026-08-25 16:21:24 +08:00
parent 94ab7216c2
commit 0ec20714c5
6 changed files with 116 additions and 3 deletions

View file

@ -19,6 +19,10 @@ name = "Glass Workbench"
id = "glass-workbench"
[tokens]
# Declared-but-not-yet-consumed: see liquid-motion/theme.toml's identical
# note next to these three keys — neither breadbar nor breadbox reads them;
# the font that actually renders comes from bread_theme::stylesheet()'s own
# hardcoded constant instead.
font_family = "IBM Plex Sans"
font_fallback = "Inter, Noto Sans, sans-serif"
font_size_base = 13
@ -36,7 +40,12 @@ bg_alpha = 0.72
spring = "cubic-bezier(0.22, 1.2, 0.36, 1)"
spring_settle = "cubic-bezier(0.22, 1.2, 0.36, 1)"
# Palette token NAMES, not hex — #7a9a88 is this palette's `green`. Equal
# from/to because the demo's accent is flat, not a gradient.
# from/to because the demo's accent is flat, not a gradient. accent_from IS
# read (Pill-style workspace fill, theme.rs); accent_to is declared-but-
# not-yet-consumed regardless of style — nothing reads it outside the
# breadbar Trail gradient this theme doesn't use, and even Trail hardcodes
# its own literal gradient rather than substituting it. See
# Tokens::accent_to's doc comment.
accent_from = "green"
accent_to = "green"
# Demo: `.ws button { height: 20px }`. Liquid-motion's chip_height (32) is

View file

@ -17,6 +17,11 @@ name = "Liquid Motion"
id = "liquid-motion"
[tokens]
# Declared-but-not-yet-consumed: neither breadbar nor breadbox reads
# font_family/font_fallback/font_size_base. Both get the font that actually
# renders from bread_theme::stylesheet()'s own hardcoded FONT_FAMILY
# constant — a separate, ecosystem-wide system shared by every bread GUI,
# not this per-theme manifest. See Tokens::font_family's doc comment.
font_family = "Varela Round, sans-serif"
font_fallback = "sans-serif"
font_size_base = 14
@ -37,6 +42,12 @@ spring = "cubic-bezier(0.22, 1.35, 0.36, 1)"
spring_settle = "cubic-bezier(0.22, 1.2, 0.36, 1)"
# "accent" flows through as @accent (the workspace-trail gradient's start);
# these are palette token NAMES, not hex - pywal still drives colour.
# Declared-but-not-yet-consumed (accent_to only): breadbar's Trail-style CSS
# hardcodes the literal gradient `linear-gradient(90deg, @accent, @teal)`
# instead of substituting these two tokens (it never calls
# ShellTheme::css(), the only thing that does the substitution) — this
# theme's "teal" is what the demo intends, not what actually renders if a
# future theme changed it. See Tokens::accent_to's doc comment.
accent_from = "accent"
accent_to = "teal"
# Not in the plan's §4 schema list, but breadbar::CHIP_HEIGHT / ::ICON_PX
@ -48,6 +59,9 @@ icon_px = 24
anchors = ["top", "left", "right"]
width = "fill"
height = 44
# No `bottom` set here (or by either sibling builtin) — it's accepted by the
# schema but breadbar never applies it (no set_margin(Edge::Bottom, ...)
# call exists). See Margin::bottom's doc comment before relying on it.
margin = { top = 12, left = 16, right = 16 }
exclusive = "auto"
# breadbar never calls gtk4-layer-shell's set_keyboard_mode today, which
@ -77,6 +91,11 @@ show_empty = true
[modules.clock]
style = "flip"
# Declared-but-not-yet-consumed under style = "flip": bar::clock::time()
# hardcodes a 24h HH:MM layout regardless of `format`; only style = "plain"
# ever calls formatted(&format). Set here to state the layout this clock
# actually draws, not because anything reads it. Same for show_date — only
# ever attached to the Plain style's box.
format = "%H:%M"
show_date = false

View file

@ -26,6 +26,8 @@ name = "Spotlight"
id = "spotlight"
[tokens]
# Declared-but-not-yet-consumed: see liquid-motion/theme.toml's identical
# note next to these three keys — neither breadbar nor breadbox reads them.
font_family = "Outfit"
font_fallback = "Varela Round, sans-serif"
font_size_base = 13
@ -44,7 +46,9 @@ spring = "cubic-bezier(0.22, 1.35, 0.36, 1)"
spring_settle = "cubic-bezier(0.22, 1.35, 0.36, 1)"
# Palette token NAMES, not hex — #e87898 is this palette's `pink`. Equal
# from/to because the demo's accent here is flat, not liquid-motion's
# accent→teal gradient.
# accent→teal gradient. accent_from IS read (the dots' active fill,
# theme.rs); accent_to is declared-but-not-yet-consumed, same as every
# other theme's — see Tokens::accent_to's doc comment.
accent_from = "pink"
accent_to = "pink"
# Demo: `.barrow { height: 36px }` with no separate workspace-chip height —
@ -108,6 +112,10 @@ dot_widths = [6, 10, 14, 18]
# (`04-spotlight.html`: `q.placeholder = t` in `clock()`, replaced by the
# search prompt only once focused/open).
style = "none"
# Declared-but-not-yet-consumed under style = "none": no clock module is
# built at all, so there's no format/date to apply this to — see
# ClockModule::format's doc comment. Kept for the same "state actual design
# intent" reason as liquid-motion's Flip-style note.
format = "%H:%M"
show_date = false
placeholder_clock = true

View file

@ -85,7 +85,12 @@ pub(super) struct RawManifest {
pub(super) surfaces: Option<HashMap<String, RawSurface>>,
pub(super) compositor: Option<HashMap<String, RawLayerRule>>,
/// Overlay CSS path, resolved relative to the theme file's own
/// directory, appended last by `ShellTheme::css`. (Schema note: plan §4
/// directory, appended last by `ShellTheme::css`. Declared-but-not-yet-
/// consumed in production: `ShellTheme::css` (the only reader of this
/// field's resolved `extra_css`) is not called by breadbar or breadbox
/// today — see that method's doc comment. Setting this key is currently
/// a no-op for a real running shell (it IS exercised by this crate's own
/// tests). (Schema note: plan §4
/// shows `css = "extra.css"` textually after the `[compositor]` table
/// with no table header of its own between them, which in real TOML
/// would nest it *inside* `[compositor]`. Treated here as a top-level
@ -132,6 +137,8 @@ pub(super) struct RawMargin {
pub(super) top: i64,
pub(super) left: i64,
pub(super) right: i64,
/// See [`super::types::Margin::bottom`] — accepted and resolved, but
/// breadbar never applies it.
pub(super) bottom: i64,
}

View file

@ -115,6 +115,24 @@ impl ShellTheme {
/// Token substitution into the theme's CSS template, plus the optional
/// `extra.css` overlay appended last — plan §5.
///
/// **Declared-but-not-yet-consumed in production**, as of this writing:
/// neither breadbar nor breadbox calls this method. Both hand-roll their
/// own CSS instead (`breadbar::theme::load_css` reads individual
/// `Tokens::xxx()` accessors and `format!`s a literal stylesheet;
/// `breadbox::main::build_css` reads only `launcher.radius`). That means
/// the compiled-in `assets/shell/*/*.css` templates this method
/// substitutes into render nothing a user ever sees, and a theme's
/// `css = "extra.css"` overlay (parsed, path-resolved, read from disk,
/// token-substituted into [`Self::extra_css`] below) is fully
/// implemented and then never applied. This method itself is correct
/// and covered by this crate's own tests
/// (`builtin_css_substitutes_tokens_and_leaves_palette_names_untouched`,
/// `extra_css_overlay_is_appended_and_token_substituted`) — the gap is
/// entirely on the consumer side, in breadbar/breadbox, not here. Wiring
/// either app onto this method (replacing their own hand-rolled builders)
/// is out of scope for this crate to do unilaterally, since it's a
/// behavior change to code this crate doesn't own.
///
/// `palette` is accepted to match the plan §5 signature and for parity
/// with [`crate::stylesheet_resolved`]-style consumers in the future,
/// but is deliberately unused today: per this task's brief, `@accent` /

View file

@ -88,6 +88,14 @@ pub struct Margin {
pub top: i32,
pub left: i32,
pub right: i32,
/// Declared-but-not-yet-consumed: parsed and carried all the way
/// through resolution, but breadbar only calls
/// `gtk4_layer_shell::LayerShell::set_margin` for
/// `Edge::{Top,Left,Right}` (`breadbar/src/main.rs`) — there is no
/// `Edge::Bottom` call anywhere in that crate. All three built-in
/// themes happen to omit `margin.bottom` (defaulting to 0, this
/// struct's own `Default`), which is exactly why the gap has stayed
/// invisible: a theme author who *does* set it would see no effect.
pub bottom: i32,
}
@ -150,7 +158,22 @@ pub struct WorkspacesModule {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClockModule {
pub style: ClockStyle,
/// Consumed only by `ClockStyle::Plain` (`breadbar::bar::clock`'s
/// `formatted()`, called from `main.rs` only in the `Plain` arm) —
/// `Flip` and `None` never read it; `Flip`'s own `time()` hardcodes a
/// 24h `HH:MM` layout regardless of this field. All three built-in
/// themes set `format = "%H:%M"` (which happens to match `Flip`'s
/// hardcoded layout, masking the gap for two of the three styles); see
/// each `theme.toml`'s own note next to it for which styles actually
/// honour this.
pub format: String,
/// Consumed only by `ClockStyle::Plain`, same scoping as
/// [`Self::format`] — `date_lbl` is only ever attached under the
/// `Plain` arm's box, so this value can never be observed under
/// `Flip`/`None`. Currently harmless in practice (every built-in theme
/// that isn't `Plain` sets this `false`, so there's nothing to ignore),
/// but the same "declared, scoped to one style" caveat as `format`
/// applies.
pub show_date: bool,
/// `style = "none"` + this `true`: no module renders a clock label of
/// its own — `launcher_entry`'s placeholder text becomes the time
@ -327,12 +350,27 @@ impl Tokens {
}
}
/// Declared-but-not-yet-consumed in production: neither breadbar nor
/// breadbox calls this accessor. Both get their actual rendered font
/// from [`crate::stylesheet`]'s own hardcoded `crate::tokens::FONT_FAMILY`
/// constant — a completely separate, ecosystem-wide font system shared
/// by every bread GUI (not just shell-themed ones), unrelated to this
/// per-theme manifest field. Setting `[tokens] font_family = "..."` in a
/// theme.toml today has zero effect on what actually renders; every
/// built-in theme sets this key anyway (see the "not yet consumed" note
/// next to it in each `theme.toml`), preserved as an honest declaration
/// of the demo's intended font pending someone deciding how (or
/// whether) a per-shell-theme font should override the ecosystem-wide
/// one — that's a design decision for whoever owns `stylesheet()`, not
/// a mechanical wire-up this crate can do to itself.
pub fn font_family(&self) -> String {
self.str_or("font_family", crate::tokens::FONT_FAMILY)
}
/// See [`Self::font_family`] — same "declared but never read" status.
pub fn font_fallback(&self) -> String {
self.str_or("font_fallback", "sans-serif")
}
/// See [`Self::font_family`] — same "declared but never read" status.
pub fn font_size_base(&self) -> i64 {
self.int_or("font_size_base", crate::tokens::FONT_SIZE_BASE as i64)
}
@ -372,6 +410,20 @@ impl Tokens {
pub fn accent_from(&self) -> String {
self.str_or("accent_from", "accent")
}
/// Declared-but-not-yet-consumed in production, for a subtler reason
/// than most of this file's other "never read" fields: this crate's own
/// CSS templates DO read `{accent_to}` (the `WorkspaceStyle::Trail`
/// gradient stop in `assets/shell/liquid-motion/liquid-motion.css`,
/// exercised by `super::ShellTheme::css` and this module's own tests),
/// but breadbar
/// never calls that method — its hand-rolled Trail CSS
/// (`breadbar::theme::load_css`) hardcodes the literal gradient
/// `linear-gradient(90deg, @accent, @teal)` instead of substituting
/// `accent_from`/`accent_to`, so a theme that set a *different*
/// `accent_to` than liquid-motion's "teal" would see no change in the
/// running bar. Every built-in theme still sets this key so the
/// manifest states its actual design intent; see each `theme.toml`'s
/// own note next to it.
pub fn accent_to(&self) -> String {
let from = self.accent_from();
self.str_or("accent_to", &from)