jekyll-theme-zer0 1.31.0 → 1.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1044 -1038
- data/README.md +17 -3
- data/_data/backlog.yml +3 -3
- data/_data/i18n/fr.yml +30 -14
- data/_data/i18n/manifest.yml +63 -45
- data/_data/theme-manifest.yml +11 -11
- data/_includes/components/halfmoon.html +5 -3
- data/_includes/content/intro.html +14 -3
- data/_includes/core/footer.html +3 -1
- data/_includes/core/head.html +4 -17
- data/_includes/navigation/breadcrumbs.html +21 -15
- data/_sass/core/_navbar.scss +30 -4
- data/_sass/theme/_skins.scss +6 -2
- data/assets/js/halfmoon.js +11 -1
- data/assets/js/search-modal.js +35 -3
- data/scripts/bin/validate +1 -0
- data/scripts/validate-features.rb +5 -8
- metadata +2 -2
data/CHANGELOG.md
CHANGED
|
@@ -12,36 +12,17 @@ hand-written prose covering the same releases in more depth; they sit below
|
|
|
12
12
|
their version because release-please inserts each new release at the top of the
|
|
13
13
|
file. Only `## [Unreleased]` describes work that has not shipped yet.
|
|
14
14
|
|
|
15
|
-
## [1.31.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
### Features
|
|
19
|
-
|
|
20
|
-
* **navigation:** two clean navbar label tiers, merged chevron, centred grid ([#495](https://github.com/bamr87/zer0-mistakes/issues/495)) ([9ebb29a](https://github.com/bamr87/zer0-mistakes/commit/9ebb29a4662fbc4c62d3fdd8df9c282bdd181204))
|
|
21
|
-
* **theme:** four consumer extension points for notes/knowledge-base builds ([#492](https://github.com/bamr87/zer0-mistakes/issues/492)) ([1e2b228](https://github.com/bamr87/zer0-mistakes/commit/1e2b2283303012b28b9e81209fb66d0344aa0597))
|
|
15
|
+
## [1.31.1](https://github.com/bamr87/zer0-mistakes/compare/v1.31.0...v1.31.1) (2026-10-17)
|
|
22
16
|
|
|
23
17
|
|
|
24
18
|
### Bug Fixes
|
|
25
19
|
|
|
26
|
-
* **
|
|
27
|
-
* **
|
|
28
|
-
* **
|
|
29
|
-
* **
|
|
30
|
-
* **
|
|
31
|
-
* **
|
|
32
|
-
* **includes:** stop the draft chip shifting the Site Builder on first save ([#489](https://github.com/bamr87/zer0-mistakes/issues/489)) ([d472aa2](https://github.com/bamr87/zer0-mistakes/commit/d472aa267e164212cf8b844e701cfcdad08e4d8d))
|
|
33
|
-
* **layouts:** one main landmark per page on post, notebook and note ([#487](https://github.com/bamr87/zer0-mistakes/issues/487)) ([78b0910](https://github.com/bamr87/zer0-mistakes/commit/78b0910fb2258591eab9ba13efb5ac037eee80c5))
|
|
34
|
-
* **navigation:** stop Liquid whitespace-trim gluing navbar attributes ([#477](https://github.com/bamr87/zer0-mistakes/issues/477)) ([4349ea1](https://github.com/bamr87/zer0-mistakes/commit/4349ea17d690e5e6b8585f1d3a33b3ea4d3bf4fe))
|
|
35
|
-
* **scripts:** default xAI preview renderer to grok-imagine-image-2.0 ([#499](https://github.com/bamr87/zer0-mistakes/issues/499)) ([95cebdb](https://github.com/bamr87/zer0-mistakes/commit/95cebdb535799544f05ed5929e528a074448ef63)), closes [#474](https://github.com/bamr87/zer0-mistakes/issues/474)
|
|
36
|
-
* **tests:** make the Liquid nested-tag and gem-content checks able to fail ([#478](https://github.com/bamr87/zer0-mistakes/issues/478)) ([8510d08](https://github.com/bamr87/zer0-mistakes/commit/8510d0824f79823f66f765f12db9be9b67fff3ae))
|
|
37
|
-
* **tokens:** let the active skin win over site theme_color for skin-owned tokens ([#502](https://github.com/bamr87/zer0-mistakes/issues/502)) ([af468e0](https://github.com/bamr87/zer0-mistakes/commit/af468e072543a448e7be80230f3d3a246b5e758e))
|
|
38
|
-
* **ui:** make the cookie consent banner a compact bottom bar ([#510](https://github.com/bamr87/zer0-mistakes/issues/510)) ([2d7d0db](https://github.com/bamr87/zer0-mistakes/commit/2d7d0db7f9f6b1433b63d8be76103cce2fd7fb05))
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
### Performance Improvements
|
|
42
|
-
|
|
43
|
-
* **js:** lazy-load Mermaid and cytoscape, defer PostHog, stop nav reflows ([#508](https://github.com/bamr87/zer0-mistakes/issues/508)) ([702789c](https://github.com/bamr87/zer0-mistakes/commit/702789cecf93d8e9b9f7013168ca47f0294064eb))
|
|
44
|
-
* **sitemap:** keep one page of the index in the DOM and build cards lazily ([#511](https://github.com/bamr87/zer0-mistakes/issues/511)) ([9e42fcb](https://github.com/bamr87/zer0-mistakes/commit/9e42fcbd9421a994fd22a347bbef95573ce340a9))
|
|
20
|
+
* **a11y:** name mobile intro actions, 24px nav chevrons, badge links ([#507](https://github.com/bamr87/zer0-mistakes/issues/507)) ([59963a9](https://github.com/bamr87/zer0-mistakes/commit/59963a958fb08cff9d49c00eac9e4c430d70a5c5))
|
|
21
|
+
* **color-mode:** mark the selected mode pressed on first paint ([#521](https://github.com/bamr87/zer0-mistakes/issues/521)) ([#526](https://github.com/bamr87/zer0-mistakes/issues/526)) ([2a60e73](https://github.com/bamr87/zer0-mistakes/commit/2a60e7328709f9902721fb83f7d2923d0c3f204a))
|
|
22
|
+
* **footer:** keep newsletter hint in the a11y tree below md ([#522](https://github.com/bamr87/zer0-mistakes/issues/522)) ([#525](https://github.com/bamr87/zer0-mistakes/issues/525)) ([90489d3](https://github.com/bamr87/zer0-mistakes/commit/90489d36a73bdb7f7182219efed6a399a145b388))
|
|
23
|
+
* **includes:** drop orphaned itemprop metas from <head> ([#517](https://github.com/bamr87/zer0-mistakes/issues/517)) ([47f4ff8](https://github.com/bamr87/zer0-mistakes/commit/47f4ff8f8f44933d65a7d38e6b0552d2288f8180)), closes [#513](https://github.com/bamr87/zer0-mistakes/issues/513)
|
|
24
|
+
* **navigation:** keep unlinked crumbs out of the BreadcrumbList ([#518](https://github.com/bamr87/zer0-mistakes/issues/518)) ([4fda7ab](https://github.com/bamr87/zer0-mistakes/commit/4fda7ab63a31c3614df30a13d38453568a7d5ff5))
|
|
25
|
+
* **tests:** serve the Visual Snapshots stack without LiveReload ([#530](https://github.com/bamr87/zer0-mistakes/issues/530)) ([6f61421](https://github.com/bamr87/zer0-mistakes/commit/6f6142182654b09a15c6460bf1643d2b6719a5b2))
|
|
45
26
|
|
|
46
27
|
## [Unreleased]
|
|
47
28
|
|
|
@@ -52,68 +33,422 @@ file. Only `## [Unreleased]` describes work that has not shipped yet.
|
|
|
52
33
|
- `styles:` / `scripts:` frontmatter — per-page CSS and JS resolved through `relative_url`, with `scripts:` deferred after the theme bundle. A page that declares neither emits nothing at all.
|
|
53
34
|
- `lastmod` and `description` on every `/assets/data/wiki-index.json` entry — ISO-8601 and the authored subtitle, always defined (`null` when the document has neither), no new traversal.
|
|
54
35
|
|
|
55
|
-
|
|
36
|
+
- **Bring your own AI provider — Claude or Grok — and an open, coding-session-style
|
|
37
|
+
Site Builder (ZER0-087)** — the chat proxy gains a provider layer
|
|
38
|
+
(`templates/deploy/chat-proxy/providers.js`): xAI's Grok is a first-class
|
|
39
|
+
provider (`XAI_API_KEY`, `CHAT_PROVIDER`, `XAI_CHAT_MODEL`) for the chat
|
|
40
|
+
widget, the feedback triage and the Site Builder, translated server-side to
|
|
41
|
+
and from the Anthropic Messages dialect so no client changed. The Site
|
|
42
|
+
Builder's Connect step shows which providers the local dev proxy already has
|
|
43
|
+
keys for (masked), takes a token for the session (sent once to localhost,
|
|
44
|
+
kept in the proxy's memory, optionally saved to `.env` with mode 600), offers
|
|
45
|
+
the model catalog, an image renderer (Grok Imagine / OpenAI Images) and two
|
|
46
|
+
session modes: the guided nine steps, or an open session that can open an
|
|
47
|
+
existing site under the target root, read/edit/write/delete its files, run
|
|
48
|
+
`git status`/`diff`/`log`, generate images into `assets/`, run `jekyll build`
|
|
49
|
+
inside the container and stop a long tool run. Generated sites are
|
|
50
|
+
pre-configured for the chosen provider (`ai_chat.provider`, `preview_images`,
|
|
51
|
+
`.env.example`). The dev proxy now starts without a credential. Also fixes a
|
|
52
|
+
pre-existing 162px horizontal overflow of the whole `/setup/` page at phone
|
|
53
|
+
widths (the Connect step's command boxes could not shrink). (evidence:
|
|
54
|
+
[`test/visual/evidence/site-builder-providers/`](test/visual/evidence/site-builder-providers/README.md)
|
|
55
|
+
— Connect step: 2 provider cards, 2 session modes, token field is a password
|
|
56
|
+
input inert offline; mocked proxy: "needs a token" → "Grok connected"; Build:
|
|
57
|
+
existing sites listed, Open sets the target; mobile overflow 162px → 0px)
|
|
58
|
+
- **CI now produces a UI pull request's visual artifacts instead of only
|
|
59
|
+
checking for them (ZER0-085)** — `visual-evidence-autogen.yml` renders every
|
|
60
|
+
same-repo PR in the same jammy Playwright image the snapshot gate uses, runs
|
|
61
|
+
the PR's `test/visual/*-evidence.mjs` generators (or the new generic
|
|
62
|
+
base-vs-head generator `test/visual/pr-evidence.mjs`, which renders the base
|
|
63
|
+
branch and the head side by side), verifies the 9-skin baselines, and pushes
|
|
64
|
+
the montages + `metrics.json` to the branch. Stale baselines are refreshed
|
|
65
|
+
**only** when the new `visual-evidence-reviewer` agent, having viewed the
|
|
66
|
+
expected | actual | diff montage, judges the diff to be the change the PR
|
|
67
|
+
describes — a code step disposes, the model only proposes ([#417](https://github.com/bamr87/zer0-mistakes/issues/417)
|
|
68
|
+
is why). The evidence gate now requires generated proof (a README alone no
|
|
69
|
+
longer passes), `ci-self-repair` leaves a red `Visual Snapshots` job to this
|
|
70
|
+
lane, and `test/update-snapshots.sh` gained `PRE_TEST_SCRIPT` /
|
|
71
|
+
`POST_TEST_SCRIPT` / `SKIP_PLAYWRIGHT` hooks. Closes the gap that kept
|
|
72
|
+
[#454](https://github.com/bamr87/zer0-mistakes/pull/454) red: its authoring
|
|
73
|
+
agents ran where Docker was gated, and nothing in CI could render what they
|
|
74
|
+
could not. Kill switch: repo variable `VISUAL_EVIDENCE_AUTOGEN_ENABLED=false`.
|
|
75
|
+
The lane restores its own tooling from the base branch before it runs, so it
|
|
76
|
+
works on branches cut before it shipped: without that its first real run on
|
|
77
|
+
#454 died in 20 seconds (that branch has no copy of the orchestrator), and a
|
|
78
|
+
branch carrying an older `update-snapshots.sh` would have silently generated
|
|
79
|
+
nothing at all.
|
|
80
|
+
- **Site Builder — a Claude-guided setup wizard that ends with a running site
|
|
81
|
+
(ZER0-086, extends ZER0-067)** — `/setup/` (and the `welcome` layout) grew
|
|
82
|
+
from a five-step `_config.yml` form into a nine-step builder: Connect →
|
|
83
|
+
Prerequisites → Identity → URLs → Structure → Appearance → Voice →
|
|
84
|
+
Integrations → Build. An embedded Claude session rides alongside every step
|
|
85
|
+
through the local dev proxy (Claude Code OAuth, `claude setup-token`; the
|
|
86
|
+
token never reaches the page). It sees the whole wizard state on every turn
|
|
87
|
+
and acts on it with tools: fill in fields, override a generated file, run
|
|
88
|
+
live prerequisite checks (Docker, Git, gh, VS Code, Node, Claude CLI — a
|
|
89
|
+
fixed command table), read the theme's real source and search the docs,
|
|
90
|
+
resolve a project folder, write the generated project, run `docker compose
|
|
91
|
+
up|ps|logs|down`, and check the new site answers — each mutation behind a
|
|
92
|
+
confirmation card. The form half still works with no proxy at all (GitHub
|
|
93
|
+
Pages included): it generates `_config.yml`, `_config_dev.yml`, `Gemfile`,
|
|
94
|
+
`docker-compose.yml`, `index.md`, navigation, about page, welcome post, one
|
|
95
|
+
index page per collection, `.gitignore`, `zer0.install.yml`, `.env.example`
|
|
96
|
+
and `README.md`, with per-file download and a self-extracting bash bundle.
|
|
97
|
+
Forms gained a site brief, a URL **Suggest** button, a site-type quick-pick,
|
|
98
|
+
a navigation row editor, skin cards with a live **Preview on this page**
|
|
99
|
+
toggle, tone/audience pickers, integration switches with conditional
|
|
100
|
+
sub-fields, a copy button on every command, and a toast for feedback. New:
|
|
101
|
+
`_data/site_builder.yml` (steps, prerequisites mirroring
|
|
102
|
+
`machine-setup.md`, catalogs, framework brief),
|
|
103
|
+
`templates/deploy/chat-proxy/wizard-store.mjs` (the dev-only sandbox behind
|
|
104
|
+
`/api/wizard/*`), `assets/js/site-builder.js`, `_includes/setup/{claude-
|
|
105
|
+
session,prereq-checklist}.html`, the `site_builder:` config block, a
|
|
106
|
+
quickstart page and a feature reference. (evidence:
|
|
107
|
+
[`test/visual/evidence/site-builder/`](test/visual/evidence/site-builder/README.md))
|
|
108
|
+
A first recorded end-to-end run then shaped the build half: the generated
|
|
109
|
+
`docker-compose.yml` publishes LiveReload on the site's port + 1 (a fixed
|
|
110
|
+
35729 collided with the theme's own dev container and the new site never
|
|
111
|
+
started) and shares one gem cache across generated sites; every enabled
|
|
112
|
+
collection now ships a valid starter document (a doc, a quickstart step, a
|
|
113
|
+
note with a wiki-link, a structured recipe) and the cookbook index uses the
|
|
114
|
+
theme's `cookbook` layout over the real `recipes` collection; `_config.yml`
|
|
115
|
+
sets `collections_dir: pages` (without it every collection but posts was
|
|
116
|
+
invisible to Jekyll); each site gets its own `assets/images/logo.svg`
|
|
117
|
+
monogram and gem-based sites turn the SVG background layers off, because
|
|
118
|
+
the published gem ships no theme images; a revoked Claude credential now
|
|
119
|
+
says so and names the fix. Validation is a scenario
|
|
120
|
+
runner, `test/visual/site-builder-walkthrough.mjs`, that samples random
|
|
121
|
+
briefs per site type (`test/visual/site-builder-scenarios.mjs`), drives the
|
|
122
|
+
wizard on video, builds the site with Docker and asserts its routes, title
|
|
123
|
+
and skin — replayable by seed.
|
|
124
|
+
The builder then gained a **schema-driven site plan**: `plan_schema` in
|
|
125
|
+
`_data/site_builder.yml` (a JSON-Schema subset validated in the browser)
|
|
126
|
+
describes what the agent may produce — a landing page (five templates,
|
|
127
|
+
nine section types, hero + CTAs), navigation shape (flat or grouped
|
|
128
|
+
dropdowns, sidebar none/auto/docs tree), theme overrides (nine palettes or
|
|
129
|
+
custom colours, seven font pairings, three corner radii) and up to twelve
|
|
130
|
+
example pages with Markdown bodies — and the generators turn it into
|
|
131
|
+
`index.md` (a Liquid landing engine) + `_data/landing.yml`,
|
|
132
|
+
`_data/navigation/main.yml` and `docs.yml`, `assets/css/user-overrides.css`
|
|
133
|
+
+ `_includes/custom/head.html`, and one file per page. Claude submits plans
|
|
134
|
+
with `set_site_plan` behind a confirmation card; the Structure and
|
|
135
|
+
Appearance steps expose the same choices as controls, with a page planner
|
|
136
|
+
and a **Preview on this page** toggle that applies the generated overrides
|
|
137
|
+
to the wizard itself. The scenario runner randomises the plan too and
|
|
138
|
+
asserts the built site's landing template, palette colour, web fonts and
|
|
139
|
+
planned routes.
|
|
140
|
+
- **Mermaid diagrams are now accessible figures with a toolbar (ZER0-013)** —
|
|
141
|
+
every ```` ```mermaid ```` fence (and legacy `<div class="mermaid">`) renders
|
|
142
|
+
as a `<figure>` with a rendered SVG and a small toolbar: zoom out / in / reset
|
|
143
|
+
(50–400 %, real layout — the SVG is resized, so the frame scrolls and
|
|
144
|
+
drag-to-pan, `Ctrl`+wheel and the `+` / `-` / `0` keys all work), **View
|
|
145
|
+
fullscreen** (a native `<dialog>` — the fix for a wide diagram shrunk to
|
|
146
|
+
illegibility on a phone; `Esc` closes it and focus returns to the opener),
|
|
147
|
+
**Copy diagram source**, and **Download as SVG** (page background baked in so
|
|
148
|
+
a dark-mode export stays readable). On pointer devices the toolbar floats over
|
|
149
|
+
the top-right corner on hover/focus; on touch devices it is a static row above
|
|
150
|
+
the diagram so it never covers it. `accTitle` becomes the visible
|
|
151
|
+
`<figcaption>` and the diagram's accessible name, `accDescr` its `<desc>`,
|
|
152
|
+
and the scrollable frame is a focusable, labelled region. A syntax error no
|
|
153
|
+
longer blanks the block: the figure shows the parse message, a hint, and the
|
|
154
|
+
source in a `<details>`, with *copy* still enabled. Colours are **derived from
|
|
155
|
+
the live design tokens** (`--bs-primary`, `--bs-body-bg`, `--zer0-color-*`)
|
|
156
|
+
through Mermaid's `base` theme, so diagrams follow the colour mode, the
|
|
157
|
+
selected skin and any `theme_color` override, and re-render in place when
|
|
158
|
+
those change; dark mode is decided by background luminance, so wizard mode and
|
|
159
|
+
dark skins get legible ink, and a contrast guard keeps nodes visible when the
|
|
160
|
+
brand equals the page colour. Pie slices, git branches and mind-map branches
|
|
161
|
+
get a 12-colour series fanned out from the brand hue. `securityLevel` now
|
|
162
|
+
defaults to `strict` (`mermaid.security_level: loose` restores `click`
|
|
163
|
+
callbacks / HTML labels); `mermaid.toolbar`, `fullscreen` and `download` can
|
|
164
|
+
switch the controls off. Implemented as `_includes/components/mermaid.html`
|
|
165
|
+
(loader: config JSON + two `defer` scripts — the 3.3 MB bundle used to load
|
|
166
|
+
synchronously in `<head>`) + `assets/js/mermaid-diagrams.js` +
|
|
167
|
+
`_sass/components/_mermaid.scss`, replacing ~400 lines of inline
|
|
168
|
+
`<script>`/`<style>` in the include; the `!important` SVG overrides that
|
|
169
|
+
flattened `classDef`/`style` colours and pie slices are gone. Toolbar strings
|
|
170
|
+
are `diagram_*` keys in `_data/ui-text.yml`. The docs page
|
|
171
|
+
(`/docs/features/mermaid-diagrams/`) now renders a live example of every
|
|
172
|
+
diagram type, the caption directive, per-node styling and the error state.
|
|
173
|
+
Guarded by `test/visual/features/mermaid.spec.js` (12 tests, smoke tier)
|
|
174
|
+
(evidence: [`test/visual/evidence/mermaid/`](test/visual/evidence/mermaid/README.md)
|
|
175
|
+
— dark-mode toggle keeps the SVG (before: SVG lost, stylesheet text on
|
|
176
|
+
screen); page overflow 0px at 320/390px; 11/12 docs diagrams rendered, 1
|
|
177
|
+
shown as an error card with its source kept).
|
|
56
178
|
|
|
57
|
-
- **
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
as `landing`, no longer shows the subtitle at all; add `site.subtitle` to
|
|
77
|
-
that layout's hero to keep it.
|
|
78
|
-
- **The below-`lg` menu toggle is labelled "Menu"** ([#405](https://github.com/bamr87/zer0-mistakes/issues/405)),
|
|
79
|
-
so it is distinguishable from the sidebar hamburger beside it. Override the
|
|
80
|
-
string with `ui.nav_menu_toggle_label`.
|
|
81
|
-
- The desktop navbar grid gives its two side tracks a shared minimum
|
|
82
|
-
(`--zer0-navbar-side-min`, default `9rem`) so the menubar is optically
|
|
83
|
-
centred in the bar rather than only within its own track.
|
|
179
|
+
- **Cookbook & recipes collection (ZER0-084)** — a `recipes` collection that
|
|
180
|
+
renders structured front matter as a working recipe page: `layout: recipe`
|
|
181
|
+
builds a fact bar (prep/cook/rest/total, yield, difficulty, cuisine, oven),
|
|
182
|
+
a grouped ingredient checklist, a numbered method with per-step timings and
|
|
183
|
+
temperatures, a baker's-percentage ratio table computed at build time, a
|
|
184
|
+
per-serving nutrition panel, and one `schema.org/Recipe` JSON-LD block.
|
|
185
|
+
`assets/js/recipe-scaler.js` adds serving scaling and live US↔metric
|
|
186
|
+
conversion — including volume↔weight via `_data/ingredient_densities.yml`
|
|
187
|
+
— as progressive enhancement, so every amount is still rendered exactly as
|
|
188
|
+
authored with JavaScript disabled. `layout: cookbook` indexes recipes into
|
|
189
|
+
course sections from `_data/recipe_courses.yml`. Twelve new
|
|
190
|
+
`components/recipe-*.html` includes, `_sass/components/_recipe.scss` (with
|
|
191
|
+
print styles), a demo cookbook at `/recipes/`, and docs at
|
|
192
|
+
[Cookbook collection](pages/_docs/features/cookbook-collection.md). Regression
|
|
193
|
+
coverage: `test/visual/features/recipes.spec.js` (smoke tier) and "Cookbook
|
|
194
|
+
Recipe Collection" in `test/test_core.sh` (evidence:
|
|
195
|
+
[`test/visual/evidence/recipes-collection/`](test/visual/evidence/recipes-collection/README.md)
|
|
196
|
+
— 0px page overflow across 320–1440px; 1 cup butter → 227 g, 500 g flour →
|
|
197
|
+
4 cups; ratio percentages identical at 1× and 3×).
|
|
84
198
|
|
|
85
|
-
|
|
199
|
+
- **Page-view counter (ZER0-083)** — the theme now tracks a view for the page
|
|
200
|
+
being read and displays the count in the article meta row, next to the
|
|
201
|
+
reading time (`👁 12 views`). Two providers, configured under `page_views:`
|
|
202
|
+
in `_config.yml`: `local` (the default — counts live in the visitor's
|
|
203
|
+
`localStorage`, so it works on GitHub Pages with no server, no network, and
|
|
204
|
+
no third party) and `remote` (counts come from an HTTP counter endpoint you
|
|
205
|
+
control, with `{path}` substitution, a configurable method, and a dotted
|
|
206
|
+
`count_key` for the response shape). Privacy gates mirror the `posthog:`
|
|
207
|
+
block — Do Not Track, Global Privacy Control, and an optional
|
|
208
|
+
`require_consent` tie-in to the cookie-consent "analytics" category — and
|
|
209
|
+
they suppress *recording* only, never the display of a count that is already
|
|
210
|
+
known; a view blocked pending consent is recorded when consent arrives.
|
|
211
|
+
`dedupe: session` counts one view per page per browser session so reloads do
|
|
212
|
+
not inflate it. The badge include (`components/page-views.html`) ships hidden
|
|
213
|
+
and is revealed only once a count exists, carrying its own leading separator
|
|
214
|
+
so a page with no data leaves no dangling bullet. New:
|
|
215
|
+
`_includes/components/page-views.html`,
|
|
216
|
+
`_includes/components/page-views-init.html`, `assets/js/page-views.js`,
|
|
217
|
+
`_sass/components/_page-views.scss`. Regression spec:
|
|
218
|
+
`test/visual/features/page-views.spec.js`. Docs:
|
|
219
|
+
[`docs/features/page-views.md`](docs/features/page-views.md)
|
|
220
|
+
(evidence: [`test/visual/evidence/page-views/`](test/visual/evidence/page-views/README.md)).
|
|
86
221
|
|
|
87
|
-
- **
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
- **Mermaid, cytoscape and PostHog no longer load up front, and the auto-hide navbar stops forcing reflows.** `assets/js/mermaid-diagrams.js` now converts fences into figures straight away but injects the ~1 MB Mermaid bundle only when a diagram exists and the first one comes within 400px of the viewport (IntersectionObserver); `components/mermaid.html` passes the bundle URL as `window.zer0MermaidSrc` (a script global, not DOM text, and only http(s) URLs are injected) instead of a `<script defer>`. The local-graph panel loads cytoscape on first open instead of on every indexed page. `analytics/posthog.html` keeps the queueing stub but fetches `array.js` after `load` + idle, and `core/head.html` no longer includes it a second time (`root.html` already did, so every production page called `posthog.init()` twice). `auto-hide-nav.js` measures the navbar with a ResizeObserver (rAF read/next-frame write fallback) and caches the height instead of reading `offsetHeight` at DOMContentLoaded and on resize. Lighthouse mobile, local static build: home TBT 1,705 → 651 ms and weight 5,581 → 2,327 KiB; `/docs/features/mermaid-diagrams/` TBT 2,017 → 243 ms; `auto-hide-nav.js` gone from forced-reflow. New lazy-load test in `test/visual/features/mermaid.spec.js`.
|
|
95
|
-
### Fixed
|
|
222
|
+
- **Search shortcut affordances (ZER0-032)** — the navbar search button now
|
|
223
|
+
advertises its keyboard shortcuts, matching the design-system navbar
|
|
224
|
+
pattern: a quiet `/` kbd chip (xl-up), a hover title ("Search — press / or
|
|
225
|
+
Ctrl+K", shown as `⌘K` on macOS), and `aria-keyshortcuts`; the sidebar (`b`)
|
|
226
|
+
and table-of-contents (`t`) hide toggles gained shortcut hover hints, and
|
|
227
|
+
the keyboard-shortcuts modal now lists `⌘/Ctrl+K`
|
|
228
|
+
(evidence: [`test/visual/evidence/search-shortcut-hint/`](test/visual/evidence/search-shortcut-hint/README.md)).
|
|
96
229
|
|
|
97
|
-
- **
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
230
|
+
- **Live design-system pages (ZER0-082)** — the design system is now
|
|
231
|
+
part of the site itself: `_design-system/` is force-included in the Jekyll
|
|
232
|
+
build so `styles.css`, every token file, specimen cards, and component
|
|
233
|
+
sources get real URLs under `/_design-system/`; a new `/design/` hub page
|
|
234
|
+
renders the foundation specimens in live iframes (colors, skins, type,
|
|
235
|
+
spacing, radii, motion, layers, iconography), catalogs the component twins,
|
|
236
|
+
and links the Claude Design page canvas (all 24 layouts as a browsable
|
|
237
|
+
presentation). Navbar: About → Design System. Regression spec:
|
|
238
|
+
`test/visual/features/design-hub.spec.js`.
|
|
239
|
+
|
|
240
|
+
- **Claude Design system round-trip (ZER0-081)** — the design-token layer is now
|
|
241
|
+
aligned with the zer0-mistakes Claude Design project
|
|
242
|
+
(`claude.ai/design/p/e75121c0-9210-42d1-ade3-2c8af9111cbe`): new
|
|
243
|
+
`--zer0-radius-*`, `--zer0-logo-*`, and `--zer0-text-display-*` tokens in
|
|
244
|
+
`_sass/tokens/`; the design project vendored as a git mirror under
|
|
245
|
+
`_design-system/` (plain-CSS tokens, React component specs, guideline cards,
|
|
246
|
+
website UI kit — sync contract in `_design-system/SYNC.md`); and
|
|
247
|
+
`scripts/design-system-check.rb` wired into the core test suite so the theme
|
|
248
|
+
and the mirror cannot drift silently. Callouts, landing feature cards, mobile
|
|
249
|
+
nav, tables, and focus rings now consume the radius tokens (value-preserving —
|
|
250
|
+
rendered output unchanged, pinned by a new runtime token assertion in
|
|
251
|
+
`test/visual/core/styling.spec.js`).
|
|
252
|
+
- **Design-system component twins (PR #391)** — `Fab`/`FabStack`, `PostCard`,
|
|
253
|
+
and `Skeleton` join Button/Badge/Card/FeatureCard/Callout/Input in
|
|
254
|
+
`_design-system/components/`, plus new Motion and Layers foundation cards;
|
|
255
|
+
all pushed live to the Claude Design project. The feature registry is
|
|
256
|
+
re-synced (`features/features.yml` ↔ `_data/features.yml` — #389's ZER0-081
|
|
257
|
+
entry had landed in the `_data` mirror only, which the registry validator
|
|
258
|
+
rejects) and `docs/ui/components.md` gains a theme-source →
|
|
259
|
+
design-system-twin map.
|
|
260
|
+
|
|
261
|
+
- **`giscus-discussions doctor`** — a new subcommand that verifies the entire
|
|
262
|
+
comment chain end-to-end: repository public, Discussions enabled, `giscus.enabled: true`, `data-repo-id` actually belonging to this repo (the fork trap), `data-category-id` resolving to a real category, and — the part nothing else could check — whether the giscus GitHub App is installed, by asking the Giscus API itself. Exits non-zero with a specific remediation line per failure.
|
|
263
|
+
- **Giscus health check in CI** — `.github/workflows/giscus-digest.yml` (already
|
|
264
|
+
scheduled weekly) now runs `doctor` and fails the job with a summary when comments are down, so a sitewide comment outage surfaces on its own instead of waiting for a reader to report it.
|
|
265
|
+
- **Troubleshooting: "The giscus app is not installed"** — a new section in the
|
|
266
|
+
feature docs with captured screenshots of both the broken widget and the giscus.app configurator rejecting the repo, an explanation of why this step is uniquely easy to skip, a fork-specific warning, and a copy-pasteable `curl` health check.
|
|
267
|
+
- **Obsidian graph frontend revamp** — the graph views now mirror the Obsidian
|
|
268
|
+
desktop experience. The full graph page gains a floating **Graph settings**
|
|
269
|
+
card (Filters / Display / Forces): search with `tag:`/`path:` operators,
|
|
270
|
+
per-collection toggles generated from the wiki-index (count badge + color
|
|
271
|
+
swatch, doubling as the legend), show-orphans and show-unresolved switches,
|
|
272
|
+
node-size / link-thickness / label-fade sliders, repel-force and
|
|
273
|
+
link-distance sliders with animated re-layout, plus a zoom / fit / fullscreen
|
|
274
|
+
button stack, an Obsidian-style hover preview card, live dark-mode restyling,
|
|
275
|
+
and localStorage persistence. The local graph panel gains a depth selector
|
|
276
|
+
(1–3) and outgoing/incoming direction switches that re-render the subgraph in
|
|
277
|
+
place. Same vendored cytoscape.js, unchanged `wiki-index.json` contract
|
|
278
|
+
(evidence:
|
|
279
|
+
[`test/visual/evidence/obsidian-graph-revamp/`](test/visual/evidence/obsidian-graph-revamp/README.md);
|
|
280
|
+
regression: `test/visual/features/obsidian-graph.spec.js`).
|
|
281
|
+
|
|
282
|
+
- **Theme-canary reporting contract** (`docs/systems/theme-canary-contract.md`) —
|
|
283
|
+
the canonical upstream bug-intake protocol for downstream theme-scout agents
|
|
284
|
+
(it-journey, lifehacker.dev): required `theme-canary` + `from-<consumer>`
|
|
285
|
+
labels, a deterministic 12-hex dedupe key + hidden body marker, the mandated
|
|
286
|
+
open-AND-closed pre-filing search, a 5-issues-per-consumer-per-run cap, and a
|
|
287
|
+
required evidence format that records the theme version/commit observed (so
|
|
288
|
+
fixed-in-release triage is mechanical). Ships with the matching
|
|
289
|
+
`theme-canary.yml` issue form.
|
|
290
|
+
|
|
291
|
+
- **`examples/` — self-contained demo sites built on the theme.** New top-level
|
|
292
|
+
directory (excluded from the theme's own site build and from the gem) for
|
|
293
|
+
complete Jekyll sites that show the theme configured for a particular kind of
|
|
294
|
+
site. Each has its own `_config.yml`, `Gemfile`, and content, and builds
|
|
295
|
+
against the local theme sources via `_config_dev.yml`.
|
|
296
|
+
- `examples/swerve-of-shore/` — **Swerve of Shore**, a serialized literary
|
|
297
|
+
reading blog rebuilt from
|
|
298
|
+
[swerveofshore.com](https://www.swerveofshore.com/) with the site owner's
|
|
299
|
+
permission. 52 pages, 0 broken internal links. Exercises a `series` output
|
|
300
|
+
collection with nested per-section paths, a data-driven taxonomy
|
|
301
|
+
(`_data/episodes.yml`) that generates the sidebar rail, the episode
|
|
302
|
+
schedule with live entry counts, and a section page for every node — so a
|
|
303
|
+
nav target resolves even where nothing is written yet. Also covers article
|
|
304
|
+
hero images (`show_hero`), entries ordered by number rather than date, the
|
|
305
|
+
shared `post-card` component in a single-column feed, and a full editorial
|
|
306
|
+
light-mode restyle done entirely through `assets/css/user-overrides.css` —
|
|
307
|
+
no theme files touched. The site's identity, taxonomy, entry titles/dates,
|
|
308
|
+
and featured images are reproduced, along with a short quoted excerpt per
|
|
309
|
+
entry (the opening the original publishes in its own RSS feed), attributed
|
|
310
|
+
and linked back. The essays themselves are not reproduced.
|
|
311
|
+
- `examples/README.md` — how to run one and the conventions for adding
|
|
312
|
+
another.
|
|
313
|
+
- **Theme propagation system — releases now reach the sites built on them.**
|
|
314
|
+
Releasing ended at RubyGems; nothing told the five downstream consumers a new
|
|
315
|
+
version existed, so all three pinned sites were still on v1.26.0 when v1.27.0
|
|
316
|
+
shipped and the two unpinned ones had been silently tracking `main`.
|
|
317
|
+
- `_data/consumers.yml` — registry of every consumer, its consumption mode
|
|
318
|
+
(`remote_theme_pinned` / `remote_theme_floating` / `gem` / `path`), and every
|
|
319
|
+
file that holds a version pin.
|
|
320
|
+
- `scripts/propagate.rb` — reports pin drift across the registry
|
|
321
|
+
(`--format text|json|github`, `--strict`) or dispatches a `theme-release`
|
|
322
|
+
event to each consumer (`--dispatch`).
|
|
323
|
+
- `.github/workflows/propagate-theme.yml` — dispatches on release publish;
|
|
324
|
+
weekly drift report. Never pushes to a consumer: each one opens its own PR so
|
|
325
|
+
its own CI gates the bump.
|
|
326
|
+
- `templates/consumer/` — the consumer's half of the contract:
|
|
327
|
+
`bump-theme-pins.sh` (rewrites `remote_theme`, `theme_repo`, and Gemfile gem
|
|
328
|
+
constraints in one pass; `--check`, `--dry-run`, `--latest`, `--pin`),
|
|
329
|
+
`theme-bump.yml` (dispatch + weekly schedule + manual), and a
|
|
330
|
+
`.theme-overrides.yml` starter. The schedule matters most for gem-mode
|
|
331
|
+
consumers, which have no `remote_theme` and so pick up nothing automatically.
|
|
332
|
+
- `docs/systems/theme-propagation.md` — how the whole flow fits together.
|
|
333
|
+
- **`./scripts/bin/manifest --check`** — verifies the committed theme manifest
|
|
334
|
+
matches the working tree, ignoring `generated_at`. `--dry-run` now emits only
|
|
335
|
+
YAML on stdout (progress logs moved to stderr) so its output can be diffed
|
|
336
|
+
directly.
|
|
337
|
+
- **Consumer extension hooks (`_includes/custom/`).** Four empty stubs the
|
|
338
|
+
chrome now includes at fixed points — `custom/head.html` (end of `<head>`),
|
|
339
|
+
`custom/body-start.html` (right after `<body>`, e.g. GTM noscript),
|
|
340
|
+
`custom/footer.html` (after the theme footer), `custom/body-end.html` (last
|
|
341
|
+
thing before `</body>`). A consumer site shadows just the stub to inject
|
|
342
|
+
JSON-LD, fonts, verification tags, or scripts — no more forking
|
|
343
|
+
`core/head.html`/`root.html` and drifting from the theme. Documented in
|
|
344
|
+
`_includes/README.md`.
|
|
345
|
+
- **`components/card-grid.html` + `components/data-card.html`.** A generic,
|
|
346
|
+
data-driven card grid (title/url/icon/badge/meta-pills/buttons schema) for
|
|
347
|
+
org hub dashboards, fleet registries, service grids, and link boards —
|
|
348
|
+
the markup consumer sites have been hand-rolling per page. Includes an
|
|
349
|
+
optional empty-state message.
|
|
350
|
+
- **`_layouts/404.html` — the 404 page as a theme layout.** The full 404
|
|
351
|
+
experience (including the unconfigured-site setup guide) now lives in the
|
|
352
|
+
theme; a consumer's `/404.html` shrinks from a 224-line vendored copy to a
|
|
353
|
+
4-line front-matter stub (`layout: "404"`). Setup mode is branded with
|
|
354
|
+
`site.title` instead of a hardcoded theme welcome, and the stub page's body
|
|
355
|
+
renders below the standard content for site-specific additions.
|
|
356
|
+
- **`color_mode_lock` config.** Pin the site to one color mode: visitor
|
|
357
|
+
preference and OS scheme are ignored, the light/dark/auto switcher is
|
|
358
|
+
removed, and `core/color-mode-init.html` + `halfmoon.js` enforce the lock
|
|
359
|
+
pre-paint. Replaces consumer JS workarounds that re-asserted a mode on every
|
|
360
|
+
`matchMedia` change.
|
|
361
|
+
- **PostHog privacy options** (`posthog.privacy.*`): `respect_gpc` (honor the
|
|
362
|
+
Global Privacy Control signal alongside DNT, default on), `require_consent`
|
|
363
|
+
(start opted out with memory-only persistence until the visitor accepts the
|
|
364
|
+
cookie-consent "analytics" category), and `geoip_disable` (no IP→location
|
|
365
|
+
resolution). Upstreams the deltas consumer sites were maintaining in a
|
|
366
|
+
full fork of `analytics/posthog.html`.
|
|
367
|
+
- **`news:` config surface for the news/section layouts.** `category_base`
|
|
368
|
+
(e.g. `/categories/` instead of the hardcoded `/news/`), `index_url`,
|
|
369
|
+
`hero: false`, `archives_url`, and a `newsletter` block (endpoint-or-mailto,
|
|
370
|
+
or hidden entirely — the old markup shipped a form that submitted nowhere).
|
|
371
|
+
|
|
372
|
+
- **ABC board books (`book-abc` layout) — the "ABC & Language" series.** A new
|
|
373
|
+
immersive, single-scroll toddler alphabet layout (`_layouts/book-abc.html`)
|
|
374
|
+
driven entirely by an `alphabet:` front-matter list — one big letter, one
|
|
375
|
+
word, one picture per card, with A–Z quick-jump anchors and a cover hero.
|
|
376
|
+
The big letter is HTML typography (never baked into the art), and a card
|
|
377
|
+
whose plate is still `planned` shows a tinted "illustration coming soon"
|
|
378
|
+
placeholder so a book reads end-to-end before any art renders. New
|
|
379
|
+
`_includes/components/abc-letter.html` renders each card; `_sass/components/_book.scss`
|
|
380
|
+
gains `.abc-board` / `.abc-letter-*` styles plus a `.abc-style--<id>` skin per
|
|
381
|
+
shared art-style id. `components/bookshelf.html` now lists both `book` and
|
|
382
|
+
`book-abc` books, grouped into series shelves from `_data/series.yml`;
|
|
383
|
+
`book-card.html` shows a letter count for ABC books. Ships a demo book
|
|
384
|
+
(`pages/_books/abc-demo/`) + default series metadata (`_data/series.yml`).
|
|
385
|
+
Regression test [`test/visual/features/book-abc.spec.js`](test/visual/features/book-abc.spec.js)
|
|
386
|
+
and before/after evidence in
|
|
387
|
+
[`test/visual/evidence/book-abc/`](test/visual/evidence/book-abc/). Docs:
|
|
388
|
+
[`docs/features/abc-books.md`](docs/features/abc-books.md).
|
|
389
|
+
- **`nav: pages` sidebar mode — auto-build the left tree from page URLs.** A new
|
|
390
|
+
sidebar mode (`_includes/navigation/sidebar-pagetree.html`) derives a
|
|
391
|
+
collapsible section tree purely from page permalinks under a `sidebar.base`
|
|
392
|
+
prefix — no curated `_data/navigation/*.yml` file to write or keep in sync.
|
|
393
|
+
Enable per page / collection / site with `sidebar: {nav: pages, base: /docs/,
|
|
394
|
+
order_by: nav_order, title: …}`. It covers plain pages (`site.html_pages`) and
|
|
395
|
+
collection documents (`site.documents`) alike, groups them by first path
|
|
396
|
+
segment, humanizes section labels from the URL (never leaking a generic
|
|
397
|
+
"Index" title), sorts each section by a numeric `order_by` (natural order),
|
|
398
|
+
supports per-page `sidebar_label` / `sidebar_exclude`, and marks only the
|
|
399
|
+
current page active with its section expanded server-side — pure Liquid, so
|
|
400
|
+
it is GitHub Pages / `remote_theme` safe. Documented at
|
|
401
|
+
`/docs/features/sidebar-page-tree/`.
|
|
402
|
+
- **Claude Code OAuth in the AI installer** — the spec-driven installer
|
|
403
|
+
(`scripts/bin/install`) is now multi-provider. `scripts/install/ai/client.sh`
|
|
404
|
+
resolves a provider via `ZER0_AI_PROVIDER` (default `auto`), preferring the
|
|
405
|
+
logged-in `claude` CLI (**Claude Code OAuth** — zero key handling), then the
|
|
406
|
+
Anthropic Messages API (`CLAUDE_CODE_OAUTH_TOKEN` OAuth bearer or
|
|
407
|
+
`ANTHROPIC_API_KEY`), then OpenAI. `install doctor` reports the active
|
|
408
|
+
provider; `--ai-provider` / `--ai-model` / `ZER0_AI_MODEL` tune it; `--no-ai`
|
|
409
|
+
/ `ZER0_NO_AI=1` disable it. User context is sanitized before every call.
|
|
410
|
+
- **Config-file layer for the installer** — new `scripts/install/config.sh`
|
|
411
|
+
discovers and merges `~/.config/zer0/install.yml`, `<target>/zer0.install.yml`,
|
|
412
|
+
`<target>/.zer0/config.yml`, and `--config FILE` (precedence:
|
|
413
|
+
defaults < profile < config < env < flags). Recognises site / github / theme /
|
|
414
|
+
deploy / agents / tasks / ai keys; API keys stay environment-only.
|
|
415
|
+
- **`install suggest`** subcommand — recommend a profile + deploy target
|
|
416
|
+
(AI-assisted with rule-based fallback) — plus `--yes` as an alias for
|
|
417
|
+
`--auto-accept`.
|
|
418
|
+
- Installer regression matrix (`test/test_installer.sh`) now covers AI
|
|
419
|
+
provider resolution, text extraction across provider shapes, the config-file
|
|
420
|
+
layer + precedence, and the `doctor` AI check (all offline).
|
|
114
421
|
|
|
115
422
|
### Changed
|
|
116
423
|
|
|
424
|
+
- **Navbar label tiers reduced from three to two** ([#405](https://github.com/bamr87/zer0-mistakes/issues/405)).
|
|
425
|
+
Top-level nav items now render as icon + full label above 51rem of centre
|
|
426
|
+
track and icon-only below it; `text-overflow: ellipsis` is gone, so a label
|
|
427
|
+
is never cut to "Quicksta…". Icons now survive in **both** tiers — the old
|
|
428
|
+
41–50.99rem tier dropped them to buy width for bare labels. **Behaviour
|
|
429
|
+
change:** centre-track widths between 41rem and 51rem (roughly 992–1200px
|
|
430
|
+
viewports) previously showed bare labels and now show icons, with the
|
|
431
|
+
existing `.nav-tooltip` carrying the name on hover.
|
|
432
|
+
- **Dropdown chevrons merged into their parent row** ([#405](https://github.com/bamr87/zer0-mistakes/issues/405)).
|
|
433
|
+
The split toggle is now absolutely positioned inside padding the parent link
|
|
434
|
+
reserves, and hover applies to the whole row, so there is no dead zone
|
|
435
|
+
between the label and its chevron. It remains a real `<button>` with
|
|
436
|
+
`aria-expanded`, `aria-haspopup` and its visually-hidden label unchanged.
|
|
437
|
+
(evidence: [`test/visual/evidence/navbar-tiers-405/`](test/visual/evidence/navbar-tiers-405/README.md) — chevron dead zone up to 4px → overlapping; 0 truncated labels across 6 widths)
|
|
438
|
+
- **The navbar carries logo + title only** ([#405](https://github.com/bamr87/zer0-mistakes/issues/405)).
|
|
439
|
+
`site.subtitle` moved out of `_includes/core/branding.html` and onto the home
|
|
440
|
+
hero (`_layouts/home.html`), returning its width to the menubar. It renders
|
|
441
|
+
under the page heading on pages that use the `home` layout, and is hidden
|
|
442
|
+
with it by `hide_title` or `hide_intro`. A homepage on another layout, such
|
|
443
|
+
as `landing`, no longer shows the subtitle at all; add `site.subtitle` to
|
|
444
|
+
that layout's hero to keep it.
|
|
445
|
+
- **The below-`lg` menu toggle is labelled "Menu"** ([#405](https://github.com/bamr87/zer0-mistakes/issues/405)),
|
|
446
|
+
so it is distinguishable from the sidebar hamburger beside it. Override the
|
|
447
|
+
string with `ui.nav_menu_toggle_label`.
|
|
448
|
+
- The desktop navbar grid gives its two side tracks a shared minimum
|
|
449
|
+
(`--zer0-navbar-side-min`, default `9rem`) so the menubar is optically
|
|
450
|
+
centred in the bar rather than only within its own track.
|
|
451
|
+
|
|
117
452
|
- The stable-height spec now walks Connect **first and last** and records
|
|
118
453
|
`#wizardTabContent`'s document-y **top** beside each Back/Next offset. The
|
|
119
454
|
contract itself (`spread ≤ 1`) is unchanged; what is new is that a shift
|
|
@@ -139,576 +474,169 @@ file. Only `## [Unreleased]` describes work that has not shipped yet.
|
|
|
139
474
|
— base vs head on a post and a note page, page overflow 0px → 0px across 6
|
|
140
475
|
widths, 9 pixel baselines unchanged).
|
|
141
476
|
|
|
142
|
-
|
|
477
|
+
- **`claude-run` is now the fleet's shared `ai-runner` kit.** The composite
|
|
478
|
+
action and its new `scripts/ai/run.sh` are byte-identical copies of
|
|
479
|
+
lifehacker.dev's (the kit source of truth) instead of a hand-rolled variant.
|
|
480
|
+
What changes for the two callers (`issue-autopilot.yml`,
|
|
481
|
+
`visual-evidence-autogen.yml`): an AI call that was attempted and rejected —
|
|
482
|
+
revoked credential, exhausted quota, `is_error` payload, CLI install failure
|
|
483
|
+
— now fails the step with the reason as a `::error::` annotation, where the
|
|
484
|
+
old action exited 0 and a dead run read green; the OAuth-first rule is
|
|
485
|
+
enforced with `env -u ANTHROPIC_API_KEY`; the model override is the canonical
|
|
486
|
+
`AI_MODEL` (or the new `model` input) rather than `ZER0_AI_MODEL`, and
|
|
487
|
+
`max-turns` is a new input. Metering (`scripts/ai/usage.rb`,
|
|
488
|
+
`usage_report.rb`, prices in `_data/ai_pricing.yml`) and the Claude API
|
|
489
|
+
fallback (`scripts/ai/api_call.rb`) ride along as optional companions. The
|
|
490
|
+
exit-code contract is pinned by `scripts/ci/test_ai_runner.sh`, wired into
|
|
491
|
+
`./scripts/bin/test`. The action's six existing inputs are unchanged.
|
|
492
|
+
- **`claude-run` is consumed by reference from the hub.** `issue-autopilot.yml` and `visual-evidence-autogen.yml` now call `bamr87/bamr87/.github/actions/claude-run@main` (identical inputs) instead of a vendored `./.github/actions/claude-run`; the local action, `scripts/ai/run.sh`, and the vendored contract test (`scripts/ci/test_ai_runner.sh` + its `scripts/test/lib/` bridge) are deleted, while the consumer companions the hub runner probes for — `scripts/ai/usage.rb`, `usage_report.rb`, `api_call.rb`, `_data/ai.yml`, `_data/ai_pricing.yml`, `tools/unwrap-prose.py` — stay ([bamr87/bamr87#254](https://github.com/bamr87/bamr87/pull/254)).
|
|
493
|
+
- **Consumer registry corrections.** `ai-world-view/ai-world-view.github.io`
|
|
494
|
+
is `remote_theme_floating` (both its `_config.yml` and `hub.yml` pins are
|
|
495
|
+
untagged), not `remote_theme_pinned`; `amr-bash/bash-365.com` is registered
|
|
496
|
+
as a consumer (floating `remote_theme`, unconstrained gem on Azure, path gem
|
|
497
|
+
for dev).
|
|
143
498
|
|
|
499
|
+
- **The page-feedback widget now files the fleet's issue contract, not its own
|
|
500
|
+
(UPS-FB).** The theme built its own issue body, its own escaping, and its own
|
|
501
|
+
URL-length trimming — and so did the 404 page and the AI chat, three builders
|
|
502
|
+
in one repo with three different behaviours. All three now go through
|
|
503
|
+
`FleetFeedbackCore` in `assets/js/fleet-feedback.js`, vendored byte-identically
|
|
504
|
+
from the fleet kit (`bamr87/bamr87` `templates/feedback/`, held to the hub's
|
|
505
|
+
copy by the drift gate). It is the same builder the fleet's `<fleet-feedback>`
|
|
506
|
+
web component uses, so an issue filed from a page here and one filed from a
|
|
507
|
+
React app elsewhere are byte-identical to the pipeline that triages them.
|
|
144
508
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
* **includes:** make theme-color track the page surface, not the accent ([#447](https://github.com/bamr87/zer0-mistakes/issues/447)) ([f1fda85](https://github.com/bamr87/zer0-mistakes/commit/f1fda857bb0cf5bd64bebfc1215ba0a906f05e5c))
|
|
152
|
-
* **includes:** themed Mermaid figures + toolbar ([#455](https://github.com/bamr87/zer0-mistakes/issues/455)) ([96776fa](https://github.com/bamr87/zer0-mistakes/commit/96776fa48bbe7b63058d1d246962019c745d7b93))
|
|
153
|
-
* **scripts:** adopt the shared ai-runner kit for claude-run; consumers registry fixes; hub baseline ([#475](https://github.com/bamr87/zer0-mistakes/issues/475)) ([feb4133](https://github.com/bamr87/zer0-mistakes/commit/feb41332eb15d2c13fe0c0f6d15b61007e14daa3))
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
### Bug Fixes
|
|
157
|
-
|
|
158
|
-
* **a11y:** decouple heading size from heading level in theme chrome ([#450](https://github.com/bamr87/zer0-mistakes/issues/450)) ([bb92eb5](https://github.com/bamr87/zer0-mistakes/commit/bb92eb583c955e76339a9c7ab98532b35e226b36))
|
|
159
|
-
* **a11y:** give footer icon links an accessible name, announce search results ([#441](https://github.com/bamr87/zer0-mistakes/issues/441)) ([a1811e8](https://github.com/bamr87/zer0-mistakes/commit/a1811e81ac0c17b0836994be7c48eba51252bae7))
|
|
160
|
-
* **a11y:** stop emitting sidebar/TOC controls on layouts that render no offcanvas ([#443](https://github.com/bamr87/zer0-mistakes/issues/443)) ([619322d](https://github.com/bamr87/zer0-mistakes/commit/619322d8fd7c6e2a700ba154e065bf65caf67461))
|
|
161
|
-
* **ci:** run the autogen lane's tooling from the base branch, not the PR ([#464](https://github.com/bamr87/zer0-mistakes/issues/464)) ([8473050](https://github.com/bamr87/zer0-mistakes/commit/8473050be2b4ddfd994c7bea8a8c35e37a66b7f8))
|
|
162
|
-
* **ci:** stop the UI audit reporting a measurement blackout as a clean run ([#471](https://github.com/bamr87/zer0-mistakes/issues/471)) ([ab92619](https://github.com/bamr87/zer0-mistakes/commit/ab9261946e088417dabe4291590da1c7a964d4fa))
|
|
163
|
-
* **content:** raw-protect Liquid that is written as documentation ([#446](https://github.com/bamr87/zer0-mistakes/issues/446)) ([6123c1f](https://github.com/bamr87/zer0-mistakes/commit/6123c1f1e6ffd167376d4ef421b0a9f78af3985e))
|
|
164
|
-
* **includes:** declare charset inside the 1024-byte window, make the feed discoverable ([#440](https://github.com/bamr87/zer0-mistakes/issues/440)) ([4025205](https://github.com/bamr87/zer0-mistakes/commit/40252050ec21c70aa1d84820fdcde6d564e03478)), closes [#372](https://github.com/bamr87/zer0-mistakes/issues/372) [#371](https://github.com/bamr87/zer0-mistakes/issues/371)
|
|
165
|
-
* **includes:** expose skin-button selected state via aria-pressed ([#469](https://github.com/bamr87/zer0-mistakes/issues/469)) ([6579b16](https://github.com/bamr87/zer0-mistakes/commit/6579b1621a5eff147e224977633728aadc960505)), closes [#467](https://github.com/bamr87/zer0-mistakes/issues/467)
|
|
166
|
-
* **install:** stop seeding the theme's own navigation into consumers ([#449](https://github.com/bamr87/zer0-mistakes/issues/449)) ([232857c](https://github.com/bamr87/zer0-mistakes/commit/232857c66d7c3abccb166b5151a7f80a74dd17ca))
|
|
167
|
-
* **navigation:** scroll spy bolds the section actually being read ([#456](https://github.com/bamr87/zer0-mistakes/issues/456)) ([5ff38bf](https://github.com/bamr87/zer0-mistakes/commit/5ff38bf98faf96cdc3bf63ea3f0e7b10e21f3aab))
|
|
168
|
-
* **sass:** stop navbar controls flickering under a stationary pointer ([#453](https://github.com/bamr87/zer0-mistakes/issues/453)) ([fc84b9a](https://github.com/bamr87/zer0-mistakes/commit/fc84b9a4c714f8e04b8a0f940bed9e3795c144bc)), closes [#404](https://github.com/bamr87/zer0-mistakes/issues/404)
|
|
169
|
-
* **scripts:** restore nested translation placeholders instead of leaking them ([#452](https://github.com/bamr87/zer0-mistakes/issues/452)) ([00cab73](https://github.com/bamr87/zer0-mistakes/commit/00cab73d915f4e116040ef6ca4c0381669ae4eb2))
|
|
170
|
-
|
|
509
|
+
What that adds to every filed issue: sections in a fixed order, a
|
|
510
|
+
`<!-- fleet-feedback v1 type=... -->` marker the issue pipeline reads to
|
|
511
|
+
recognise an already-structured report, and a real over-budget path. The AI
|
|
512
|
+
chat in particular used to `.slice(0, 6000)` its body — silently dropping
|
|
513
|
+
whatever Claude had written past that point — and now trims by section and
|
|
514
|
+
hands the full text to the clipboard.
|
|
171
515
|
|
|
172
|
-
|
|
516
|
+
The theme keeps its Bootstrap modal and its AI triage step; only the body
|
|
517
|
+
assembly moved. Two UIs, one contract.
|
|
173
518
|
|
|
174
|
-
|
|
175
|
-
|
|
519
|
+
- **Request-type labels map onto the fleet issue-pipeline taxonomy.**
|
|
520
|
+
`enhancement`/`documentation` become `feature`/`docs`; `area:docs`/`area:feat`
|
|
521
|
+
drop out. Every label the widget applies exists in this repo (GitHub silently
|
|
522
|
+
drops the ones that do not), and a widget-filed issue is now pipeline-eligible
|
|
523
|
+
on the next scan. The zero-`_data` fallback taxonomy carries them too, so
|
|
524
|
+
`remote_theme` consumers benefit the moment those labels exist in their repo.
|
|
176
525
|
|
|
177
|
-
|
|
526
|
+
- **Captured console lines are redacted before they enter the buffer.** Bearer
|
|
527
|
+
tokens, API keys, JWTs, GitHub tokens and email addresses are masked on the
|
|
528
|
+
way in, so a secret cannot be previewed, copied, or filed even by accident.
|
|
529
|
+
Credentials reach the console more often than anyone expects — an
|
|
530
|
+
`Authorization` header logged by a fetch wrapper, a signed URL in a 403.
|
|
178
531
|
|
|
179
|
-
|
|
532
|
+
- **The capture buffer hooks `console.warn` and `console.error` only.**
|
|
533
|
+
Previously `log`, `info` and `debug` were captured too. At a 40-entry ring,
|
|
534
|
+
debug chatter evicts the one line that explains the failure — which is the
|
|
535
|
+
line a report exists to carry. `_includes/core/console-capture.html` is now a
|
|
536
|
+
two-line loader for the vendored buffer rather than 60 lines of inline script,
|
|
537
|
+
which also *shrinks* `<head>` and buys back room for the charset meta that has
|
|
538
|
+
to land in the first 1024 bytes (#372).
|
|
180
539
|
|
|
181
|
-
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
— now fails the step with the reason as a `::error::` annotation, where the
|
|
188
|
-
old action exited 0 and a dead run read green; the OAuth-first rule is
|
|
189
|
-
enforced with `env -u ANTHROPIC_API_KEY`; the model override is the canonical
|
|
190
|
-
`AI_MODEL` (or the new `model` input) rather than `ZER0_AI_MODEL`, and
|
|
191
|
-
`max-turns` is a new input. Metering (`scripts/ai/usage.rb`,
|
|
192
|
-
`usage_report.rb`, prices in `_data/ai_pricing.yml`) and the Claude API
|
|
193
|
-
fallback (`scripts/ai/api_call.rb`) ride along as optional companions. The
|
|
194
|
-
exit-code contract is pinned by `scripts/ci/test_ai_runner.sh`, wired into
|
|
195
|
-
`./scripts/bin/test`. The action's six existing inputs are unchanged.
|
|
196
|
-
- **`claude-run` is consumed by reference from the hub.** `issue-autopilot.yml` and `visual-evidence-autogen.yml` now call `bamr87/bamr87/.github/actions/claude-run@main` (identical inputs) instead of a vendored `./.github/actions/claude-run`; the local action, `scripts/ai/run.sh`, and the vendored contract test (`scripts/ci/test_ai_runner.sh` + its `scripts/test/lib/` bridge) are deleted, while the consumer companions the hub runner probes for — `scripts/ai/usage.rb`, `usage_report.rb`, `api_call.rb`, `_data/ai.yml`, `_data/ai_pricing.yml`, `tools/unwrap-prose.py` — stay ([bamr87/bamr87#254](https://github.com/bamr87/bamr87/pull/254)).
|
|
197
|
-
- **Consumer registry corrections.** `ai-world-view/ai-world-view.github.io`
|
|
198
|
-
is `remote_theme_floating` (both its `_config.yml` and `hub.yml` pins are
|
|
199
|
-
untagged), not `remote_theme_pinned`; `amr-bash/bash-365.com` is registered
|
|
200
|
-
as a consumer (floating `remote_theme`, unconstrained gem on Azure, path gem
|
|
201
|
-
for dev).
|
|
540
|
+
- **TOC scroll spy now bolds the section you are actually reading** — the
|
|
541
|
+
highlighted entry in the right-hand Table of Contents jumped around and sat
|
|
542
|
+
one to three sections ahead of the viewport. Measured on `/docs/features/toc/`
|
|
543
|
+
at 1280×820, the wrong entry was bolded at **19–23 of 25 scroll positions**
|
|
544
|
+
— the count moves between runs because which implementation won depended on
|
|
545
|
+
callback timing, which is the bug in one sentence.
|
|
202
546
|
|
|
203
|
-
|
|
547
|
+
Three implementations were toggling `.active` on the same
|
|
548
|
+
`#TableOfContents a` links, so whichever fired last won. Bootstrap's native
|
|
549
|
+
ScrollSpy was wired up twice — `data-bs-spy="scroll"
|
|
550
|
+
data-bs-target="#TableOfContents"` on `<body>` in `_layouts/root.html` *and*
|
|
551
|
+
on `.bd-main` in `_layouts/default.html` (whose `data-bs-offset="100"` had
|
|
552
|
+
been dead since Bootstrap 5.2 replaced that option with
|
|
553
|
+
`data-bs-root-margin`). `assets/js/ui-enhancements.js` ran a third observer
|
|
554
|
+
over *every* `a[href^="#"]` on the page, clearing `.active` from all of them
|
|
555
|
+
each time a `section[id]` intersected. Both Bootstrap hooks are removed —
|
|
556
|
+
the `<body>` one was also stripping server-rendered `.active` classes off
|
|
557
|
+
admin sidebar links, which `fixtures.gotoBeforeScrollSpy` exists to work
|
|
558
|
+
around — and the `ui-enhancements.js` observer is now scoped away from TOC
|
|
559
|
+
and sidebar links.
|
|
204
560
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
the
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
siblings do not match), both loops read from a process substitution so a
|
|
219
|
-
failure propagates, and the gem check extracts `data.tar.gz` and asserts
|
|
220
|
-
`_layouts/` and `assets/` are really in it. The layout balance check, now
|
|
221
|
-
live, blanks Liquid comment bodies before counting, so prose in a comment that
|
|
222
|
-
quotes a closing delimiter (as `_layouts/root.html`'s per-page-scripts note
|
|
223
|
-
does) is no longer read as an unbalanced tag. New `test/test_core_checks.sh`
|
|
224
|
-
drives both checks against known-good and known-bad fixtures, so a check that
|
|
225
|
-
stops being able to fail is itself a test failure. `./test/test_core.sh` now
|
|
226
|
-
runs clean: 26/26, no `[ERROR]` line, no gzip/tar noise.
|
|
227
|
-
- **Every navbar link emitted invalid HTML — attributes glued together with no
|
|
228
|
-
separating whitespace (#465)** — the Liquid whitespace-trim markers around the
|
|
229
|
-
conditional `aria-current` in `_includes/navigation/navbar.html` ate the
|
|
230
|
-
newlines that separated the surrounding attributes, so the primary nav
|
|
231
|
-
rendered `aria-label="News"aria-current="page"title="News"` (the WHATWG
|
|
232
|
-
`missing-whitespace-between-attributes` parse error). The leading {% raw %}`{%-`{% endraw %}
|
|
233
|
-
stripped the newline after `aria-label` and the trailing {% raw %}`-%}`{% endraw %} the whitespace
|
|
234
|
-
before `title`, which means **two of the four sites were broken on every page,
|
|
235
|
-
not just the current one**: where the conditional sits between two
|
|
236
|
-
unconditional attributes both markers fire even when the `if` emits nothing.
|
|
237
|
-
Parsers recover, so nothing looked broken — but the attributes affected are
|
|
238
|
-
exactly `aria-label`, `aria-current` and `title`, and a stricter parser is
|
|
239
|
-
entitled to drop the "you are here" announcement for screen-reader users. All
|
|
240
|
-
four sites now use the non-trimming {% raw %}`{% if %}`{% endraw %} form already present at line 26
|
|
241
|
-
of the same file, with the separator outside the tag. Two guards in
|
|
242
|
-
`test/test_core.sh`: `test_navbar_attribute_whitespace` renders the real
|
|
243
|
-
include through Liquid across both `aria-current` branches and both nav modes
|
|
244
|
-
(6 of 8 rendered variants were invalid before the fix), and
|
|
245
|
-
`test_attribute_whitespace_in_markup` models the trim rules over every include
|
|
246
|
-
and layout with no gem dependency — it found a second live instance, a literal
|
|
247
|
-
missing space in `components/theme-preview-gallery.html`, fixed here too.
|
|
248
|
-
`test_jekyll_build` re-checks the delivered `_site` bytes. No visual change.
|
|
249
|
-
- **The weekly UI/UX audit was blind, and reported it as clean.** `sweep.mjs`
|
|
250
|
-
built its pages with `browser.newPage()`, which `@axe-core/playwright`
|
|
251
|
-
refuses; the throw was caught by a single per-route `try` that also discarded
|
|
252
|
-
the overflow, console-error and link-collection data already gathered for
|
|
253
|
-
that route. Screenshots still succeeded, so the harness looked alive while
|
|
254
|
-
every accessibility, console, overflow and broken-link result on every route
|
|
255
|
-
was silently dropped — and the report rendered the absence as "0 axe
|
|
256
|
-
violations / 0 broken links". Pages are now built from `browser.newContext()`,
|
|
257
|
-
each measurement fails independently, a scan that errored is reported as
|
|
258
|
-
UNKNOWN rather than clean, and a measurement that fails on every route turns
|
|
259
|
-
the sweep red the way a total capture failure already did. On the demo site
|
|
260
|
-
the sweep goes from 18/21 captured with 21 blackout entries to **21/21
|
|
261
|
-
captured, 0 harness errors, 191 links crawled and 8 genuinely broken links
|
|
262
|
-
found** ([#468](https://github.com/bamr87/zer0-mistakes/issues/468)).
|
|
263
|
-
- **Theme-skin buttons now announce which skin is applied.** The Theme Skin
|
|
264
|
-
group in Settings → Appearance conveyed selection only through the Bootstrap
|
|
265
|
-
`.active` class, which carries no accessibility semantics, so screen readers
|
|
266
|
-
announced nine identical unlabelled buttons — WCAG 2.1 SC 4.1.2 (Name, Role,
|
|
267
|
-
Value). Each button now ships `aria-pressed`, and the click and "Reset
|
|
268
|
-
background" handlers keep it in sync with `.active` through one shared
|
|
269
|
-
helper, matching the sibling color-mode group
|
|
270
|
-
([#467](https://github.com/bamr87/zer0-mistakes/issues/467)).
|
|
561
|
+
The theme's own spy (`assets/js/modules/navigation/scroll-spy.js`) was wrong
|
|
562
|
+
on its own terms too: it asked IntersectionObserver for the "most visible"
|
|
563
|
+
heading, but headings are a few pixels tall, so every heading inside the
|
|
564
|
+
observer band reports the same `intersectionRatio` — the winner was whichever
|
|
565
|
+
entry happened to be in that callback's batch, and a heading scrolling *out*
|
|
566
|
+
of the band triggered no re-evaluation at all. It now applies a positional
|
|
567
|
+
rule: the active heading is the last one whose top has crossed the reading
|
|
568
|
+
line (the document's `scroll-padding-top`, the same offset anchor navigation
|
|
569
|
+
uses), with the last heading winning once the page is scrolled to the bottom
|
|
570
|
+
so trailing sections shorter than the viewport are still reachable. The
|
|
571
|
+
answer is recomputed from scratch on each rAF-throttled scroll frame from
|
|
572
|
+
cached heading offsets, re-measured on resize and content reflow
|
|
573
|
+
(`ResizeObserver`), so it cannot drift out of sync.
|
|
271
574
|
|
|
272
|
-
|
|
575
|
+
Two smaller fixes ride along. Clicking a TOC entry now holds that entry
|
|
576
|
+
active while the smooth scroll animates, instead of flashing every heading
|
|
577
|
+
passed on the way. And keeping the active entry visible inside the TOC no
|
|
578
|
+
longer calls `scrollIntoView()`, which bubbles up and scrolls the *page* —
|
|
579
|
+
feeding straight back into the spy; it adjusts the TOC container's own
|
|
580
|
+
`scrollTop`, resolving that container at call time (`.bd-toc` on desktop,
|
|
581
|
+
`.offcanvas-body` on mobile) rather than assuming one. The active link also
|
|
582
|
+
carries `aria-current="true"`.
|
|
273
583
|
|
|
584
|
+
`config.scrollSpy.rootMargin`/`threshold` are replaced by
|
|
585
|
+
`config.scrollSpy.offset` (`null` = derive from `scroll-padding-top`) and
|
|
586
|
+
`tolerance`. Guarded by `test/visual/features/scroll-spy.spec.js` (smoke
|
|
587
|
+
tier), which is 5 failed / 1 passed against the pre-fix theme and 6 passed
|
|
588
|
+
with the fix. (evidence:
|
|
589
|
+
[`test/visual/evidence/scroll-spy/`](test/visual/evidence/scroll-spy/README.md)
|
|
590
|
+
— wrong TOC highlight at 19/25 scroll positions → 0)
|
|
591
|
+
- **Navbar controls no longer flicker under a stationary pointer (#404)** —
|
|
592
|
+
`.nav-link:hover`, the Search/Settings utility buttons and the two sidebar/TOC
|
|
593
|
+
FABs applied `transform: translateY(-1px)`. A 1px lift moves the element out
|
|
594
|
+
from under a pointer parked on the row it vacates, so hover exits, the element
|
|
595
|
+
drops back under the pointer, and hover re-enters — an infinite flicker with
|
|
596
|
+
no pointer movement at all. Nav items are thin enough for a 1px lift to
|
|
597
|
+
reliably do it.
|
|
274
598
|
|
|
275
|
-
|
|
599
|
+
Deleting those declarations was **not sufficient**, and the reason is the
|
|
600
|
+
substantive finding here: `_sass/components/_ui-enhancements.scss` applies
|
|
601
|
+
`transform: translateY(-2px)` to `.btn:hover` — *every* button in the theme.
|
|
602
|
+
The utility buttons and both FABs are `.btn`s, so with the navbar's own 1px
|
|
603
|
+
lift removed the buttons kept flickering on the inherited 2px one — measured
|
|
604
|
+
on the built site, the Settings button lost and regained hover 14 times in
|
|
605
|
+
800ms with the pointer completely still. The fix therefore cancels it
|
|
606
|
+
explicitly with `transform: none`, the corrective pattern this repo already
|
|
607
|
+
uses in `_post-navigation.scss` and its `prefers-reduced-motion` blocks. The
|
|
608
|
+
FABs get the same treatment by the same reasoning — they are the same kind of
|
|
609
|
+
`.btn` with the same lift — but they were not rendered at any viewport reached
|
|
610
|
+
during verification, so that half is reasoned, not observed.
|
|
276
611
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
* **layouts:** add cookbook collection with recipe scaling and unit conversion ([#414](https://github.com/bamr87/zer0-mistakes/issues/414)) ([bb8eefa](https://github.com/bamr87/zer0-mistakes/commit/bb8eefa2beea0104fec28d173a1e57f369acada8))
|
|
282
|
-
* **pages:** publish the design system and page canvas on the live site ([#392](https://github.com/bamr87/zer0-mistakes/issues/392)) ([6cf73cd](https://github.com/bamr87/zer0-mistakes/commit/6cf73cdf2cca9ec02394b6ae1ba7e39c19969134))
|
|
283
|
-
* **sass:** align design tokens with the Claude Design system ([#389](https://github.com/bamr87/zer0-mistakes/issues/389)) ([7fc2fe0](https://github.com/bamr87/zer0-mistakes/commit/7fc2fe02683d652c0326536158bd48b3690df51f))
|
|
612
|
+
Background, colour and shadow transitions are untouched, and the controls keep
|
|
613
|
+
a pressed cue as `:active { transform: translateY(1px) }` — safe, because
|
|
614
|
+
`:active` only holds while the button is held down, so the pointer cannot
|
|
615
|
+
leave and re-enter in a loop.
|
|
284
616
|
|
|
617
|
+
Three corrections to the issue as filed. The vacated row is the **bottom**
|
|
618
|
+
edge, not the top — a probe parked on the top edge passes without exercising
|
|
619
|
+
the bug at all. Only a transform on the **hovered element's own box** can
|
|
620
|
+
flicker: `&:hover i { transform: scale(1.1) }` moves a child and never shrinks
|
|
621
|
+
the parent's hit box, so those went for consistency, not as causes. And
|
|
622
|
+
`.nav-link:hover`, named as the primary culprit, was **dead code** — its lift
|
|
623
|
+
sat inside `@media (min-width: 992px) { @container navbar-main (max-width:
|
|
624
|
+
75rem) }`, and measured on the built site at 1040/1140/1200/1280px its
|
|
625
|
+
computed hover transform is `none` at every width, on `main` too. Every
|
|
626
|
+
flicker actually observed was on the utility buttons.
|
|
285
627
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
* **layouts:** move keyboard focus to the skip-link target (tabindex="-1") ([#395](https://github.com/bamr87/zer0-mistakes/issues/395)) ([f5db650](https://github.com/bamr87/zer0-mistakes/commit/f5db65048e48ca71eedebc04d02d051e0b3152a6)), closes [#278](https://github.com/bamr87/zer0-mistakes/issues/278)
|
|
299
|
-
* **layouts:** stop emitting dead sub-topic anchors in section sidebars ([#402](https://github.com/bamr87/zer0-mistakes/issues/402)) ([f50e790](https://github.com/bamr87/zer0-mistakes/commit/f50e790c4bfd56fefa4a74d7876de90c9776c689))
|
|
300
|
-
* **layouts:** upgrade the no-js class to "js" so the hook works ([#428](https://github.com/bamr87/zer0-mistakes/issues/428)) ([a2d31f5](https://github.com/bamr87/zer0-mistakes/commit/a2d31f5533a4fb4793042e32326c1a78c9954268)), closes [#319](https://github.com/bamr87/zer0-mistakes/issues/319)
|
|
301
|
-
* **navigation:** fit all nav items, full-bleed bar, language into Settings ([#423](https://github.com/bamr87/zer0-mistakes/issues/423)) ([689006e](https://github.com/bamr87/zer0-mistakes/commit/689006e7654e900a4509c30539fcf12bd7f397c6))
|
|
302
|
-
* **scripts:** correct consumer auditor, plugin contract, and JSON-LD scope ([#400](https://github.com/bamr87/zer0-mistakes/issues/400)) ([b466cad](https://github.com/bamr87/zer0-mistakes/commit/b466cad526501e7e7a0eef5f24a12c5bbd181dc7))
|
|
303
|
-
* **scripts:** recover from a rejected Anthropic credential, and link the cookbook ([#419](https://github.com/bamr87/zer0-mistakes/issues/419)) ([fac6bee](https://github.com/bamr87/zer0-mistakes/commit/fac6beeb7af7dcae96f727bf0cf581b080e95f15))
|
|
304
|
-
* **ui-audit:** serve without --detach so the sweep can capture, and fail loudly when it cannot ([#434](https://github.com/bamr87/zer0-mistakes/issues/434)) ([fac6415](https://github.com/bamr87/zer0-mistakes/commit/fac641574c951b2887d94f8b39561fb8b6f8fe8c)), closes [#321](https://github.com/bamr87/zer0-mistakes/issues/321)
|
|
305
|
-
|
|
306
|
-
## [Unreleased]
|
|
307
|
-
|
|
308
|
-
### Added
|
|
309
|
-
|
|
310
|
-
- **Bring your own AI provider — Claude or Grok — and an open, coding-session-style
|
|
311
|
-
Site Builder (ZER0-087)** — the chat proxy gains a provider layer
|
|
312
|
-
(`templates/deploy/chat-proxy/providers.js`): xAI's Grok is a first-class
|
|
313
|
-
provider (`XAI_API_KEY`, `CHAT_PROVIDER`, `XAI_CHAT_MODEL`) for the chat
|
|
314
|
-
widget, the feedback triage and the Site Builder, translated server-side to
|
|
315
|
-
and from the Anthropic Messages dialect so no client changed. The Site
|
|
316
|
-
Builder's Connect step shows which providers the local dev proxy already has
|
|
317
|
-
keys for (masked), takes a token for the session (sent once to localhost,
|
|
318
|
-
kept in the proxy's memory, optionally saved to `.env` with mode 600), offers
|
|
319
|
-
the model catalog, an image renderer (Grok Imagine / OpenAI Images) and two
|
|
320
|
-
session modes: the guided nine steps, or an open session that can open an
|
|
321
|
-
existing site under the target root, read/edit/write/delete its files, run
|
|
322
|
-
`git status`/`diff`/`log`, generate images into `assets/`, run `jekyll build`
|
|
323
|
-
inside the container and stop a long tool run. Generated sites are
|
|
324
|
-
pre-configured for the chosen provider (`ai_chat.provider`, `preview_images`,
|
|
325
|
-
`.env.example`). The dev proxy now starts without a credential. Also fixes a
|
|
326
|
-
pre-existing 162px horizontal overflow of the whole `/setup/` page at phone
|
|
327
|
-
widths (the Connect step's command boxes could not shrink). (evidence:
|
|
328
|
-
[`test/visual/evidence/site-builder-providers/`](test/visual/evidence/site-builder-providers/README.md)
|
|
329
|
-
— Connect step: 2 provider cards, 2 session modes, token field is a password
|
|
330
|
-
input inert offline; mocked proxy: "needs a token" → "Grok connected"; Build:
|
|
331
|
-
existing sites listed, Open sets the target; mobile overflow 162px → 0px)
|
|
332
|
-
- **CI now produces a UI pull request's visual artifacts instead of only
|
|
333
|
-
checking for them (ZER0-085)** — `visual-evidence-autogen.yml` renders every
|
|
334
|
-
same-repo PR in the same jammy Playwright image the snapshot gate uses, runs
|
|
335
|
-
the PR's `test/visual/*-evidence.mjs` generators (or the new generic
|
|
336
|
-
base-vs-head generator `test/visual/pr-evidence.mjs`, which renders the base
|
|
337
|
-
branch and the head side by side), verifies the 9-skin baselines, and pushes
|
|
338
|
-
the montages + `metrics.json` to the branch. Stale baselines are refreshed
|
|
339
|
-
**only** when the new `visual-evidence-reviewer` agent, having viewed the
|
|
340
|
-
expected | actual | diff montage, judges the diff to be the change the PR
|
|
341
|
-
describes — a code step disposes, the model only proposes ([#417](https://github.com/bamr87/zer0-mistakes/issues/417)
|
|
342
|
-
is why). The evidence gate now requires generated proof (a README alone no
|
|
343
|
-
longer passes), `ci-self-repair` leaves a red `Visual Snapshots` job to this
|
|
344
|
-
lane, and `test/update-snapshots.sh` gained `PRE_TEST_SCRIPT` /
|
|
345
|
-
`POST_TEST_SCRIPT` / `SKIP_PLAYWRIGHT` hooks. Closes the gap that kept
|
|
346
|
-
[#454](https://github.com/bamr87/zer0-mistakes/pull/454) red: its authoring
|
|
347
|
-
agents ran where Docker was gated, and nothing in CI could render what they
|
|
348
|
-
could not. Kill switch: repo variable `VISUAL_EVIDENCE_AUTOGEN_ENABLED=false`.
|
|
349
|
-
The lane restores its own tooling from the base branch before it runs, so it
|
|
350
|
-
works on branches cut before it shipped: without that its first real run on
|
|
351
|
-
#454 died in 20 seconds (that branch has no copy of the orchestrator), and a
|
|
352
|
-
branch carrying an older `update-snapshots.sh` would have silently generated
|
|
353
|
-
nothing at all.
|
|
354
|
-
- **Site Builder — a Claude-guided setup wizard that ends with a running site
|
|
355
|
-
(ZER0-086, extends ZER0-067)** — `/setup/` (and the `welcome` layout) grew
|
|
356
|
-
from a five-step `_config.yml` form into a nine-step builder: Connect →
|
|
357
|
-
Prerequisites → Identity → URLs → Structure → Appearance → Voice →
|
|
358
|
-
Integrations → Build. An embedded Claude session rides alongside every step
|
|
359
|
-
through the local dev proxy (Claude Code OAuth, `claude setup-token`; the
|
|
360
|
-
token never reaches the page). It sees the whole wizard state on every turn
|
|
361
|
-
and acts on it with tools: fill in fields, override a generated file, run
|
|
362
|
-
live prerequisite checks (Docker, Git, gh, VS Code, Node, Claude CLI — a
|
|
363
|
-
fixed command table), read the theme's real source and search the docs,
|
|
364
|
-
resolve a project folder, write the generated project, run `docker compose
|
|
365
|
-
up|ps|logs|down`, and check the new site answers — each mutation behind a
|
|
366
|
-
confirmation card. The form half still works with no proxy at all (GitHub
|
|
367
|
-
Pages included): it generates `_config.yml`, `_config_dev.yml`, `Gemfile`,
|
|
368
|
-
`docker-compose.yml`, `index.md`, navigation, about page, welcome post, one
|
|
369
|
-
index page per collection, `.gitignore`, `zer0.install.yml`, `.env.example`
|
|
370
|
-
and `README.md`, with per-file download and a self-extracting bash bundle.
|
|
371
|
-
Forms gained a site brief, a URL **Suggest** button, a site-type quick-pick,
|
|
372
|
-
a navigation row editor, skin cards with a live **Preview on this page**
|
|
373
|
-
toggle, tone/audience pickers, integration switches with conditional
|
|
374
|
-
sub-fields, a copy button on every command, and a toast for feedback. New:
|
|
375
|
-
`_data/site_builder.yml` (steps, prerequisites mirroring
|
|
376
|
-
`machine-setup.md`, catalogs, framework brief),
|
|
377
|
-
`templates/deploy/chat-proxy/wizard-store.mjs` (the dev-only sandbox behind
|
|
378
|
-
`/api/wizard/*`), `assets/js/site-builder.js`, `_includes/setup/{claude-
|
|
379
|
-
session,prereq-checklist}.html`, the `site_builder:` config block, a
|
|
380
|
-
quickstart page and a feature reference. (evidence:
|
|
381
|
-
[`test/visual/evidence/site-builder/`](test/visual/evidence/site-builder/README.md))
|
|
382
|
-
A first recorded end-to-end run then shaped the build half: the generated
|
|
383
|
-
`docker-compose.yml` publishes LiveReload on the site's port + 1 (a fixed
|
|
384
|
-
35729 collided with the theme's own dev container and the new site never
|
|
385
|
-
started) and shares one gem cache across generated sites; every enabled
|
|
386
|
-
collection now ships a valid starter document (a doc, a quickstart step, a
|
|
387
|
-
note with a wiki-link, a structured recipe) and the cookbook index uses the
|
|
388
|
-
theme's `cookbook` layout over the real `recipes` collection; `_config.yml`
|
|
389
|
-
sets `collections_dir: pages` (without it every collection but posts was
|
|
390
|
-
invisible to Jekyll); each site gets its own `assets/images/logo.svg`
|
|
391
|
-
monogram and gem-based sites turn the SVG background layers off, because
|
|
392
|
-
the published gem ships no theme images; a revoked Claude credential now
|
|
393
|
-
says so and names the fix. Validation is a scenario
|
|
394
|
-
runner, `test/visual/site-builder-walkthrough.mjs`, that samples random
|
|
395
|
-
briefs per site type (`test/visual/site-builder-scenarios.mjs`), drives the
|
|
396
|
-
wizard on video, builds the site with Docker and asserts its routes, title
|
|
397
|
-
and skin — replayable by seed.
|
|
398
|
-
The builder then gained a **schema-driven site plan**: `plan_schema` in
|
|
399
|
-
`_data/site_builder.yml` (a JSON-Schema subset validated in the browser)
|
|
400
|
-
describes what the agent may produce — a landing page (five templates,
|
|
401
|
-
nine section types, hero + CTAs), navigation shape (flat or grouped
|
|
402
|
-
dropdowns, sidebar none/auto/docs tree), theme overrides (nine palettes or
|
|
403
|
-
custom colours, seven font pairings, three corner radii) and up to twelve
|
|
404
|
-
example pages with Markdown bodies — and the generators turn it into
|
|
405
|
-
`index.md` (a Liquid landing engine) + `_data/landing.yml`,
|
|
406
|
-
`_data/navigation/main.yml` and `docs.yml`, `assets/css/user-overrides.css`
|
|
407
|
-
+ `_includes/custom/head.html`, and one file per page. Claude submits plans
|
|
408
|
-
with `set_site_plan` behind a confirmation card; the Structure and
|
|
409
|
-
Appearance steps expose the same choices as controls, with a page planner
|
|
410
|
-
and a **Preview on this page** toggle that applies the generated overrides
|
|
411
|
-
to the wizard itself. The scenario runner randomises the plan too and
|
|
412
|
-
asserts the built site's landing template, palette colour, web fonts and
|
|
413
|
-
planned routes.
|
|
414
|
-
- **Mermaid diagrams are now accessible figures with a toolbar (ZER0-013)** —
|
|
415
|
-
every ```` ```mermaid ```` fence (and legacy `<div class="mermaid">`) renders
|
|
416
|
-
as a `<figure>` with a rendered SVG and a small toolbar: zoom out / in / reset
|
|
417
|
-
(50–400 %, real layout — the SVG is resized, so the frame scrolls and
|
|
418
|
-
drag-to-pan, `Ctrl`+wheel and the `+` / `-` / `0` keys all work), **View
|
|
419
|
-
fullscreen** (a native `<dialog>` — the fix for a wide diagram shrunk to
|
|
420
|
-
illegibility on a phone; `Esc` closes it and focus returns to the opener),
|
|
421
|
-
**Copy diagram source**, and **Download as SVG** (page background baked in so
|
|
422
|
-
a dark-mode export stays readable). On pointer devices the toolbar floats over
|
|
423
|
-
the top-right corner on hover/focus; on touch devices it is a static row above
|
|
424
|
-
the diagram so it never covers it. `accTitle` becomes the visible
|
|
425
|
-
`<figcaption>` and the diagram's accessible name, `accDescr` its `<desc>`,
|
|
426
|
-
and the scrollable frame is a focusable, labelled region. A syntax error no
|
|
427
|
-
longer blanks the block: the figure shows the parse message, a hint, and the
|
|
428
|
-
source in a `<details>`, with *copy* still enabled. Colours are **derived from
|
|
429
|
-
the live design tokens** (`--bs-primary`, `--bs-body-bg`, `--zer0-color-*`)
|
|
430
|
-
through Mermaid's `base` theme, so diagrams follow the colour mode, the
|
|
431
|
-
selected skin and any `theme_color` override, and re-render in place when
|
|
432
|
-
those change; dark mode is decided by background luminance, so wizard mode and
|
|
433
|
-
dark skins get legible ink, and a contrast guard keeps nodes visible when the
|
|
434
|
-
brand equals the page colour. Pie slices, git branches and mind-map branches
|
|
435
|
-
get a 12-colour series fanned out from the brand hue. `securityLevel` now
|
|
436
|
-
defaults to `strict` (`mermaid.security_level: loose` restores `click`
|
|
437
|
-
callbacks / HTML labels); `mermaid.toolbar`, `fullscreen` and `download` can
|
|
438
|
-
switch the controls off. Implemented as `_includes/components/mermaid.html`
|
|
439
|
-
(loader: config JSON + two `defer` scripts — the 3.3 MB bundle used to load
|
|
440
|
-
synchronously in `<head>`) + `assets/js/mermaid-diagrams.js` +
|
|
441
|
-
`_sass/components/_mermaid.scss`, replacing ~400 lines of inline
|
|
442
|
-
`<script>`/`<style>` in the include; the `!important` SVG overrides that
|
|
443
|
-
flattened `classDef`/`style` colours and pie slices are gone. Toolbar strings
|
|
444
|
-
are `diagram_*` keys in `_data/ui-text.yml`. The docs page
|
|
445
|
-
(`/docs/features/mermaid-diagrams/`) now renders a live example of every
|
|
446
|
-
diagram type, the caption directive, per-node styling and the error state.
|
|
447
|
-
Guarded by `test/visual/features/mermaid.spec.js` (12 tests, smoke tier)
|
|
448
|
-
(evidence: [`test/visual/evidence/mermaid/`](test/visual/evidence/mermaid/README.md)
|
|
449
|
-
— dark-mode toggle keeps the SVG (before: SVG lost, stylesheet text on
|
|
450
|
-
screen); page overflow 0px at 320/390px; 11/12 docs diagrams rendered, 1
|
|
451
|
-
shown as an error card with its source kept).
|
|
452
|
-
|
|
453
|
-
### Fixed
|
|
454
|
-
|
|
455
|
-
- **Generated posts and notes were invisible on GitHub Pages** — every dated
|
|
456
|
-
document the wizard wrote was stamped `T09:00:00.000Z` on the day it was
|
|
457
|
-
generated. Jekyll refuses to publish future-dated documents unless
|
|
458
|
-
`future: true`, and GitHub Pages builds with the default, so a site generated
|
|
459
|
-
before 09:00 UTC went live with its posts and notes missing: linked from the
|
|
460
|
-
collection index and listed in the sitemap, but 404 when clicked. Generated
|
|
461
|
-
content is now stamped with the actual moment it was written, and a
|
|
462
|
-
regression test fails if any generated document carries a future date.
|
|
463
|
-
Found by publishing two example sites and clicking the links.
|
|
464
|
-
- **Every page of every generated site 404'd on `user-overrides.js`** — the
|
|
465
|
-
Site Builder writes `user_overrides: true` so the theme loads the palette and
|
|
466
|
-
font overrides it generates, but that same flag also makes the theme load
|
|
467
|
-
`assets/js/user-overrides.js`, which the wizard never created. Generated
|
|
468
|
-
sites now ship a commented stub, so the request resolves and site owners have
|
|
469
|
-
an obvious place to put their own JavaScript. Found while publishing example
|
|
470
|
-
sites built by the wizard.
|
|
471
|
-
- **Every generated landing page shipped an invisible button** —
|
|
472
|
-
`components/cta-button.html` mapped `variant: outline` to `btn-outline-light`,
|
|
473
|
-
which is white text on a white border, and the Site Builder's own default
|
|
474
|
-
call to action uses `outline` on a light hero. `outline` is now an outlined
|
|
475
|
-
*primary* button; `outline-light` is the explicit variant for a dark surface,
|
|
476
|
-
and the generated landing engine picks between them from `hero.variant`.
|
|
477
|
-
The theme's own homepage hero is `bg-primary text-white`, so its two
|
|
478
|
-
outlined buttons moved to `outline-light` and render exactly as before —
|
|
479
|
-
a consumer who copied `_data/landing.yml` into a site with a dark hero
|
|
480
|
-
should make the same one-word change.
|
|
481
|
-
- **A planned `landing.hero.image` was accepted and then thrown away** — the
|
|
482
|
-
site plan's schema has offered `landing.hero.image` since the Site Builder
|
|
483
|
-
shipped, but the landing engine it generates never rendered it, so an agent
|
|
484
|
-
(or a human) could set a hero image, see it validated, watch it land in
|
|
485
|
-
`_data/landing.yml`, and get a landing page with no picture. `index.md` now
|
|
486
|
-
renders it inside the hero, decorative (empty `alt`) so a screen reader does
|
|
487
|
-
not hear the headline twice. Found by building a site end to end through the
|
|
488
|
-
new Grok path, where the "Hero image with …" shortcut pointed straight at the
|
|
489
|
-
dead field.
|
|
490
|
-
- **A partial hero patch silently wiped the rest of the hero** —
|
|
491
|
-
`set_site_plan` replaced `landing.hero` wholesale, so the natural agent move
|
|
492
|
-
of "write the copy now, add the artwork two turns later"
|
|
493
|
-
(`{landing: {hero: {image}}}`) discarded the headline, subheadline and every
|
|
494
|
-
call to action, and the landing page quietly reverted to the site title and
|
|
495
|
-
the default buttons. The hero now merges field by field; `sections`,
|
|
496
|
-
`navigation.items` and `pages` still replace, because a shorter list has to
|
|
497
|
-
mean a shorter list. The tool description says so, and the regression test
|
|
498
|
-
pins both halves.
|
|
499
|
-
|
|
500
|
-
- **A new post appeared at its own URL but on no index** — the generated
|
|
501
|
-
`_config_dev.yml` turned on Jekyll's experimental incremental regeneration,
|
|
502
|
-
which rebuilds only documents whose own source changed. Adding a post left
|
|
503
|
-
the collection index, the home page's latest-posts list and the feed showing
|
|
504
|
-
the old set, with the post reachable only by typing its URL. New sites are
|
|
505
|
-
now generated with `incremental: false`; a full rebuild of a fresh site takes
|
|
506
|
-
about a second and is always right.
|
|
507
|
-
|
|
508
|
-
- **The 15-second status poll handed the composer back mid-turn** — the Site
|
|
509
|
-
Builder's proxy poll rebuilt the panel's enabled state from the connection
|
|
510
|
-
alone, so during a long action (a Docker build, an image render) the input
|
|
511
|
-
and Send button re-enabled themselves and the Stop button vanished, while
|
|
512
|
-
tools were still running. A second message could then interleave with the
|
|
513
|
-
first. The poll now respects the busy state.
|
|
514
|
-
- **A newly added post never appeared on the running site** — Jekyll's
|
|
515
|
-
`--watch` only tracks collection documents that existed when `serve` started,
|
|
516
|
-
so a page or post the assistant added to a running project stayed invisible
|
|
517
|
-
with no explanation. `write_project_file` now says so in its result and
|
|
518
|
-
offers a restart, and `run_compose` gained a `restart` action.
|
|
519
|
-
|
|
520
|
-
- **Switching colour mode destroyed every Mermaid diagram** — the old include's
|
|
521
|
-
`MutationObserver` re-render emptied each `.mermaid` div and refilled it with
|
|
522
|
-
the div's *current* text, which after the first render is the SVG's own
|
|
523
|
-
stylesheet, and never cleared Mermaid's `data-processed` flag, so
|
|
524
|
-
`mermaid.run()` skipped the div. Toggling dark mode on `/quickstart/`,
|
|
525
|
-
`/about/` or `/docs/ruby-101/` replaced the diagram with a wall of
|
|
526
|
-
`#mermaid-… {font-family: …}` text and a permanent "Loading diagram…" label
|
|
527
|
-
(reproduced headlessly on `main`: `svgs: 1 → 0` after the toggle). Sources are
|
|
528
|
-
now kept per figure and every render goes through `mermaid.render()`, so a
|
|
529
|
-
mode or skin change re-renders from the original definition — asserted by the
|
|
530
|
-
regression test in `test/visual/features/mermaid.spec.js`.
|
|
531
|
-
- **The Obsidian wiki-link resolver rewrote the inside of inline SVGs** —
|
|
532
|
-
`assets/js/obsidian-wiki-links.js` skips text under `CODE`/`PRE`/`A`/
|
|
533
|
-
`SCRIPT`/`STYLE` by comparing `nodeName`, but elements in the SVG namespace
|
|
534
|
-
report it in lower case (`style`, `text`), so a Mermaid diagram's own
|
|
535
|
-
`<style>` was walked and every `#id` selector in it was turned into a
|
|
536
|
-
`<a class="obsidian-tag">` link. The stylesheet lost its scoping: one
|
|
537
|
-
diagram's `#arrowhead path { fill }` became a bare `path { fill }` for the
|
|
538
|
-
whole page, and pie slices rendered dark grey while their legend showed the
|
|
539
|
-
right colours. The old include escaped it only because the resolver
|
|
540
|
-
special-cases the `.mermaid` class. The name check is now case-insensitive
|
|
541
|
-
and any `<svg>` subtree (graphics, never prose) is skipped, with
|
|
542
|
-
`.zer0-diagram` added to the class exemptions. `test/test_resolver.js` gains
|
|
543
|
-
a fixture with a lower-case `style`/`text` inside `<svg>`, and the Mermaid
|
|
544
|
-
spec asserts a pie slice's computed fill equals its own attribute and that no
|
|
545
|
-
unscoped `path` rule exists on the page.
|
|
546
|
-
|
|
547
|
-
### Changed
|
|
548
|
-
|
|
549
|
-
- **The page-feedback widget now files the fleet's issue contract, not its own
|
|
550
|
-
(UPS-FB).** The theme built its own issue body, its own escaping, and its own
|
|
551
|
-
URL-length trimming — and so did the 404 page and the AI chat, three builders
|
|
552
|
-
in one repo with three different behaviours. All three now go through
|
|
553
|
-
`FleetFeedbackCore` in `assets/js/fleet-feedback.js`, vendored byte-identically
|
|
554
|
-
from the fleet kit (`bamr87/bamr87` `templates/feedback/`, held to the hub's
|
|
555
|
-
copy by the drift gate). It is the same builder the fleet's `<fleet-feedback>`
|
|
556
|
-
web component uses, so an issue filed from a page here and one filed from a
|
|
557
|
-
React app elsewhere are byte-identical to the pipeline that triages them.
|
|
558
|
-
|
|
559
|
-
What that adds to every filed issue: sections in a fixed order, a
|
|
560
|
-
`<!-- fleet-feedback v1 type=... -->` marker the issue pipeline reads to
|
|
561
|
-
recognise an already-structured report, and a real over-budget path. The AI
|
|
562
|
-
chat in particular used to `.slice(0, 6000)` its body — silently dropping
|
|
563
|
-
whatever Claude had written past that point — and now trims by section and
|
|
564
|
-
hands the full text to the clipboard.
|
|
565
|
-
|
|
566
|
-
The theme keeps its Bootstrap modal and its AI triage step; only the body
|
|
567
|
-
assembly moved. Two UIs, one contract.
|
|
568
|
-
|
|
569
|
-
- **Request-type labels map onto the fleet issue-pipeline taxonomy.**
|
|
570
|
-
`enhancement`/`documentation` become `feature`/`docs`; `area:docs`/`area:feat`
|
|
571
|
-
drop out. Every label the widget applies exists in this repo (GitHub silently
|
|
572
|
-
drops the ones that do not), and a widget-filed issue is now pipeline-eligible
|
|
573
|
-
on the next scan. The zero-`_data` fallback taxonomy carries them too, so
|
|
574
|
-
`remote_theme` consumers benefit the moment those labels exist in their repo.
|
|
575
|
-
|
|
576
|
-
- **Captured console lines are redacted before they enter the buffer.** Bearer
|
|
577
|
-
tokens, API keys, JWTs, GitHub tokens and email addresses are masked on the
|
|
578
|
-
way in, so a secret cannot be previewed, copied, or filed even by accident.
|
|
579
|
-
Credentials reach the console more often than anyone expects — an
|
|
580
|
-
`Authorization` header logged by a fetch wrapper, a signed URL in a 403.
|
|
581
|
-
|
|
582
|
-
- **The capture buffer hooks `console.warn` and `console.error` only.**
|
|
583
|
-
Previously `log`, `info` and `debug` were captured too. At a 40-entry ring,
|
|
584
|
-
debug chatter evicts the one line that explains the failure — which is the
|
|
585
|
-
line a report exists to carry. `_includes/core/console-capture.html` is now a
|
|
586
|
-
two-line loader for the vendored buffer rather than 60 lines of inline script,
|
|
587
|
-
which also *shrinks* `<head>` and buys back room for the charset meta that has
|
|
588
|
-
to land in the first 1024 bytes (#372).
|
|
589
|
-
|
|
590
|
-
### Fixed
|
|
591
|
-
|
|
592
|
-
- **The 404 page files a report a maintainer can act on.** "Submit an Issue on
|
|
593
|
-
GitHub" opened a hand-built form containing two sentences of boilerplate — no
|
|
594
|
-
page context, no environment, no captured errors. It now opens the feedback
|
|
595
|
-
widget pre-typed as `fix-page` with the URL that failed (and the page that
|
|
596
|
-
linked to it) already in the description.
|
|
597
|
-
|
|
598
|
-
- **The feedback FAB survives its script failing to load.** It was a `<button>`
|
|
599
|
-
whose only behaviour came from JavaScript; with the widget now depending on a
|
|
600
|
-
second script, a 404 on either one would have left a decorative circle in the
|
|
601
|
-
corner. It is an anchor to the issue form, upgraded in place when the script
|
|
602
|
-
runs — the same progressive enhancement the inline "Improve" link already had.
|
|
603
|
-
|
|
604
|
-
- **The page-feedback Playwright spec dismisses the cookie-consent banner.** The
|
|
605
|
-
banner is a full-width bar on a layer above the FAB stack, so it swallowed
|
|
606
|
-
every click aimed at the FAB. Every other spec that touches lower-screen chrome
|
|
607
|
-
already seeded the consent choice through the shared fixture; this one never
|
|
608
|
-
did.
|
|
609
|
-
|
|
610
|
-
### Changed
|
|
611
|
-
|
|
612
|
-
- **TOC scroll spy now bolds the section you are actually reading** — the
|
|
613
|
-
highlighted entry in the right-hand Table of Contents jumped around and sat
|
|
614
|
-
one to three sections ahead of the viewport. Measured on `/docs/features/toc/`
|
|
615
|
-
at 1280×820, the wrong entry was bolded at **19–23 of 25 scroll positions**
|
|
616
|
-
— the count moves between runs because which implementation won depended on
|
|
617
|
-
callback timing, which is the bug in one sentence.
|
|
618
|
-
|
|
619
|
-
Three implementations were toggling `.active` on the same
|
|
620
|
-
`#TableOfContents a` links, so whichever fired last won. Bootstrap's native
|
|
621
|
-
ScrollSpy was wired up twice — `data-bs-spy="scroll"
|
|
622
|
-
data-bs-target="#TableOfContents"` on `<body>` in `_layouts/root.html` *and*
|
|
623
|
-
on `.bd-main` in `_layouts/default.html` (whose `data-bs-offset="100"` had
|
|
624
|
-
been dead since Bootstrap 5.2 replaced that option with
|
|
625
|
-
`data-bs-root-margin`). `assets/js/ui-enhancements.js` ran a third observer
|
|
626
|
-
over *every* `a[href^="#"]` on the page, clearing `.active` from all of them
|
|
627
|
-
each time a `section[id]` intersected. Both Bootstrap hooks are removed —
|
|
628
|
-
the `<body>` one was also stripping server-rendered `.active` classes off
|
|
629
|
-
admin sidebar links, which `fixtures.gotoBeforeScrollSpy` exists to work
|
|
630
|
-
around — and the `ui-enhancements.js` observer is now scoped away from TOC
|
|
631
|
-
and sidebar links.
|
|
632
|
-
|
|
633
|
-
The theme's own spy (`assets/js/modules/navigation/scroll-spy.js`) was wrong
|
|
634
|
-
on its own terms too: it asked IntersectionObserver for the "most visible"
|
|
635
|
-
heading, but headings are a few pixels tall, so every heading inside the
|
|
636
|
-
observer band reports the same `intersectionRatio` — the winner was whichever
|
|
637
|
-
entry happened to be in that callback's batch, and a heading scrolling *out*
|
|
638
|
-
of the band triggered no re-evaluation at all. It now applies a positional
|
|
639
|
-
rule: the active heading is the last one whose top has crossed the reading
|
|
640
|
-
line (the document's `scroll-padding-top`, the same offset anchor navigation
|
|
641
|
-
uses), with the last heading winning once the page is scrolled to the bottom
|
|
642
|
-
so trailing sections shorter than the viewport are still reachable. The
|
|
643
|
-
answer is recomputed from scratch on each rAF-throttled scroll frame from
|
|
644
|
-
cached heading offsets, re-measured on resize and content reflow
|
|
645
|
-
(`ResizeObserver`), so it cannot drift out of sync.
|
|
646
|
-
|
|
647
|
-
Two smaller fixes ride along. Clicking a TOC entry now holds that entry
|
|
648
|
-
active while the smooth scroll animates, instead of flashing every heading
|
|
649
|
-
passed on the way. And keeping the active entry visible inside the TOC no
|
|
650
|
-
longer calls `scrollIntoView()`, which bubbles up and scrolls the *page* —
|
|
651
|
-
feeding straight back into the spy; it adjusts the TOC container's own
|
|
652
|
-
`scrollTop`, resolving that container at call time (`.bd-toc` on desktop,
|
|
653
|
-
`.offcanvas-body` on mobile) rather than assuming one. The active link also
|
|
654
|
-
carries `aria-current="true"`.
|
|
655
|
-
|
|
656
|
-
`config.scrollSpy.rootMargin`/`threshold` are replaced by
|
|
657
|
-
`config.scrollSpy.offset` (`null` = derive from `scroll-padding-top`) and
|
|
658
|
-
`tolerance`. Guarded by `test/visual/features/scroll-spy.spec.js` (smoke
|
|
659
|
-
tier), which is 5 failed / 1 passed against the pre-fix theme and 6 passed
|
|
660
|
-
with the fix. (evidence:
|
|
661
|
-
[`test/visual/evidence/scroll-spy/`](test/visual/evidence/scroll-spy/README.md)
|
|
662
|
-
— wrong TOC highlight at 19/25 scroll positions → 0)
|
|
663
|
-
- **Navbar controls no longer flicker under a stationary pointer (#404)** —
|
|
664
|
-
`.nav-link:hover`, the Search/Settings utility buttons and the two sidebar/TOC
|
|
665
|
-
FABs applied `transform: translateY(-1px)`. A 1px lift moves the element out
|
|
666
|
-
from under a pointer parked on the row it vacates, so hover exits, the element
|
|
667
|
-
drops back under the pointer, and hover re-enters — an infinite flicker with
|
|
668
|
-
no pointer movement at all. Nav items are thin enough for a 1px lift to
|
|
669
|
-
reliably do it.
|
|
670
|
-
|
|
671
|
-
Deleting those declarations was **not sufficient**, and the reason is the
|
|
672
|
-
substantive finding here: `_sass/components/_ui-enhancements.scss` applies
|
|
673
|
-
`transform: translateY(-2px)` to `.btn:hover` — *every* button in the theme.
|
|
674
|
-
The utility buttons and both FABs are `.btn`s, so with the navbar's own 1px
|
|
675
|
-
lift removed the buttons kept flickering on the inherited 2px one — measured
|
|
676
|
-
on the built site, the Settings button lost and regained hover 14 times in
|
|
677
|
-
800ms with the pointer completely still. The fix therefore cancels it
|
|
678
|
-
explicitly with `transform: none`, the corrective pattern this repo already
|
|
679
|
-
uses in `_post-navigation.scss` and its `prefers-reduced-motion` blocks. The
|
|
680
|
-
FABs get the same treatment by the same reasoning — they are the same kind of
|
|
681
|
-
`.btn` with the same lift — but they were not rendered at any viewport reached
|
|
682
|
-
during verification, so that half is reasoned, not observed.
|
|
683
|
-
|
|
684
|
-
Background, colour and shadow transitions are untouched, and the controls keep
|
|
685
|
-
a pressed cue as `:active { transform: translateY(1px) }` — safe, because
|
|
686
|
-
`:active` only holds while the button is held down, so the pointer cannot
|
|
687
|
-
leave and re-enter in a loop.
|
|
688
|
-
|
|
689
|
-
Three corrections to the issue as filed. The vacated row is the **bottom**
|
|
690
|
-
edge, not the top — a probe parked on the top edge passes without exercising
|
|
691
|
-
the bug at all. Only a transform on the **hovered element's own box** can
|
|
692
|
-
flicker: `&:hover i { transform: scale(1.1) }` moves a child and never shrinks
|
|
693
|
-
the parent's hit box, so those went for consistency, not as causes. And
|
|
694
|
-
`.nav-link:hover`, named as the primary culprit, was **dead code** — its lift
|
|
695
|
-
sat inside `@media (min-width: 992px) { @container navbar-main (max-width:
|
|
696
|
-
75rem) }`, and measured on the built site at 1040/1140/1200/1280px its
|
|
697
|
-
computed hover transform is `none` at every width, on `main` too. Every
|
|
698
|
-
flicker actually observed was on the utility buttons.
|
|
699
|
-
|
|
700
|
-
Guarded by `test/visual/core/hover-stability.spec.js`: with the pointer on the
|
|
701
|
-
control's centre the border box must be byte-identical to its resting box and
|
|
702
|
-
the computed transform must be `none`; with the pointer held half a pixel
|
|
703
|
-
inside the bottom edge for 800ms, `mouseleave` must stay at zero. The verdict
|
|
704
|
-
is the *computed* value rather than "no matching rule exists", because
|
|
705
|
-
`.btn:hover` does still match these controls and always will — it is
|
|
706
|
-
overridden, not deleted. `mouseleave`, not `mouseout`: the latter also fires
|
|
707
|
-
when the pointer crosses onto a descendant, which is not the element losing
|
|
708
|
-
hover, and it produces a false positive on every `.nav-hover-dropdown` parent.
|
|
709
|
-
Against `main` the spec is 4 failed / 1 passed; with the fix, 5 passed.
|
|
710
|
-
Evidence in `test/visual/evidence/hover-flicker/` — the Settings button lost
|
|
711
|
-
hover 14 times in 800ms before, 0 after.
|
|
628
|
+
Guarded by `test/visual/core/hover-stability.spec.js`: with the pointer on the
|
|
629
|
+
control's centre the border box must be byte-identical to its resting box and
|
|
630
|
+
the computed transform must be `none`; with the pointer held half a pixel
|
|
631
|
+
inside the bottom edge for 800ms, `mouseleave` must stay at zero. The verdict
|
|
632
|
+
is the *computed* value rather than "no matching rule exists", because
|
|
633
|
+
`.btn:hover` does still match these controls and always will — it is
|
|
634
|
+
overridden, not deleted. `mouseleave`, not `mouseout`: the latter also fires
|
|
635
|
+
when the pointer crosses onto a descendant, which is not the element losing
|
|
636
|
+
hover, and it produces a false positive on every `.nav-hover-dropdown` parent.
|
|
637
|
+
Against `main` the spec is 4 failed / 1 passed; with the fix, 5 passed.
|
|
638
|
+
Evidence in `test/visual/evidence/hover-flicker/` — the Settings button lost
|
|
639
|
+
hover 14 times in 800ms before, 0 after.
|
|
712
640
|
|
|
713
641
|
Scoped to the navbar. The issue's original acceptance criterion — *no
|
|
714
642
|
transform in any `:hover` rule under `_sass/`* — is 42 rules across ~15 files
|
|
@@ -737,7 +665,6 @@ file. Only `## [Unreleased]` describes work that has not shipped yet.
|
|
|
737
665
|
constant, plus `test_theme_color_fallback_without_config` covering the
|
|
738
666
|
no-config consumer case.
|
|
739
667
|
|
|
740
|
-
|
|
741
668
|
- **Consumers no longer inherit the theme's own navigation (#332)** — `install.sh`
|
|
742
669
|
copied the theme's entire `_data/` into every consumer, so each site's *own*
|
|
743
670
|
`_data/navigation/*.yml` was a verbatim copy of the theme's and carried the
|
|
@@ -884,123 +811,327 @@ file. Only `## [Unreleased]` describes work that has not shipped yet.
|
|
|
884
811
|
`visibilitychange`. Before/after measurements are in
|
|
885
812
|
`test/visual/evidence/setup-wizard-nav-alignment/`.
|
|
886
813
|
|
|
887
|
-
- **Language switcher: icon-only trigger and a compact, positive menu (T-038, #406)** —
|
|
888
|
-
the navbar trigger drops its `EN` text span and the Bootstrap caret for a
|
|
889
|
-
38px square icon button, with `title` and `aria-label` carrying the language
|
|
890
|
-
name. In the menu (both the navbar dropdown and the Settings panel variant),
|
|
891
|
-
the current language is now marked with a tint and a check icon instead of
|
|
892
|
-
Bootstrap's `.active` primary fill, which read as a selected nav item rather
|
|
893
|
-
than "you are here". **Untranslated languages are no longer disabled rows** —
|
|
894
|
-
they link to the source page and still record the `zer0-lang` preference, so
|
|
895
|
-
the menu has no dead ends. Machine-generated translations carry a small
|
|
896
|
-
`auto` chip, and the per-row "(Not yet translated)" text — the main driver of
|
|
897
|
-
menu width — collapses into one footnote under a divider, referenced from
|
|
898
|
-
each marked row via `aria-describedby`. The dropdown menu is capped at 220px.
|
|
899
|
-
New `ui` keys `lang_machine_translated`, `lang_machine_translated_title` and
|
|
900
|
-
`lang_untranslated_note` in `_data/ui-text.yml`; each use carries a literal
|
|
901
|
-
fallback, because `core/i18n.html` replaces the `ui` map wholesale on a
|
|
902
|
-
translated page and `_data/i18n/<lang>.yml` will not have them until
|
|
903
|
-
`scripts/translate.rb` next runs.
|
|
814
|
+
- **Language switcher: icon-only trigger and a compact, positive menu (T-038, #406)** —
|
|
815
|
+
the navbar trigger drops its `EN` text span and the Bootstrap caret for a
|
|
816
|
+
38px square icon button, with `title` and `aria-label` carrying the language
|
|
817
|
+
name. In the menu (both the navbar dropdown and the Settings panel variant),
|
|
818
|
+
the current language is now marked with a tint and a check icon instead of
|
|
819
|
+
Bootstrap's `.active` primary fill, which read as a selected nav item rather
|
|
820
|
+
than "you are here". **Untranslated languages are no longer disabled rows** —
|
|
821
|
+
they link to the source page and still record the `zer0-lang` preference, so
|
|
822
|
+
the menu has no dead ends. Machine-generated translations carry a small
|
|
823
|
+
`auto` chip, and the per-row "(Not yet translated)" text — the main driver of
|
|
824
|
+
menu width — collapses into one footnote under a divider, referenced from
|
|
825
|
+
each marked row via `aria-describedby`. The dropdown menu is capped at 220px.
|
|
826
|
+
New `ui` keys `lang_machine_translated`, `lang_machine_translated_title` and
|
|
827
|
+
`lang_untranslated_note` in `_data/ui-text.yml`; each use carries a literal
|
|
828
|
+
fallback, because `core/i18n.html` replaces the `ui` map wholesale on a
|
|
829
|
+
translated page and `_data/i18n/<lang>.yml` will not have them until
|
|
830
|
+
`scripts/translate.rb` next runs.
|
|
831
|
+
|
|
832
|
+
- **Language selector moved from the navbar into Settings → Appearance** — the
|
|
833
|
+
header utility cluster is now Search + Settings only, returning ~70px to the
|
|
834
|
+
menubar. `components/language-toggle.html` grew a `variant` parameter: the new
|
|
835
|
+
`panel` variant (shipped) renders a self-contained **Language** section — an
|
|
836
|
+
always-visible list of languages with the active one checked and
|
|
837
|
+
untranslated targets disabled — as the first block of the Settings
|
|
838
|
+
Appearance tab, next to Color Mode and Theme Skin. The original header
|
|
839
|
+
dropdown remains available as `variant="navbar"` for consumers that prefer
|
|
840
|
+
it. Same data, same `localStorage("zer0-lang")` preference, same
|
|
841
|
+
never-a-dead-link contract; `test/visual/features/language-toggle.spec.js`
|
|
842
|
+
was updated to exercise it through the Settings panel.
|
|
843
|
+
|
|
844
|
+
- **`_data/consumers.yml` now covers the whole fleet** — added `zer0-pages`,
|
|
845
|
+
`irony-works`, `wargames` and `zer0-pages-remote`, which were unregistered and
|
|
846
|
+
therefore invisible to `propagate.rb` in both directions (no release dispatch,
|
|
847
|
+
never in the drift report). The `it-journey` risk note was corrected: its
|
|
848
|
+
"~55 shadowed files / ~75 lines of !important CSS working around #338" claim
|
|
849
|
+
is not supported by `audit-consumer` — only 2 files shadow a theme file, the
|
|
850
|
+
CSS is 31 lines in this theme's own documented `user_overrides` hook, and no
|
|
851
|
+
fix numbered #338 could be substantiated in that repo.
|
|
852
|
+
|
|
853
|
+
- **The news/section layouts work with zero `_data`.** Section navigation
|
|
854
|
+
falls back from `_data/navigation/posts.yml` to `site.categories`; the hero
|
|
855
|
+
falls back to the newest post when nothing is marked `breaking`/`featured`;
|
|
856
|
+
tags links render only when a tags page exists (honoring `site.tags_page`);
|
|
857
|
+
archive month links render only when an archives page exists. A data-less
|
|
858
|
+
consumer now gets a fully working magazine homepage instead of empty chrome
|
|
859
|
+
and 404 links.
|
|
860
|
+
- **Zero-`_data` resilience across components.** The skin quick-select and
|
|
861
|
+
theme customizer fall back to the compiled skin registry when
|
|
862
|
+
`_data/theme_skins.yml` is absent; the page-feedback widget falls back to a
|
|
863
|
+
generic four-type taxonomy when `_data/feedback_types.yml` is absent; the
|
|
864
|
+
landing get-started band (theme install cards) renders only when the site
|
|
865
|
+
ships a `landing.get_started` block — a data-less consumer no longer
|
|
866
|
+
advertises the theme's own install methods.
|
|
867
|
+
- **`home` layout accepts `hide_intro` as an alias of `hide_title`**, matching
|
|
868
|
+
the flag other layouts use for "suppress the generated page header".
|
|
869
|
+
- **`halfmoon.js` honors `color_mode_default`.** The switcher no longer
|
|
870
|
+
overrides the configured default with the OS preference on first visit
|
|
871
|
+
(previously the page could flip modes right after load).
|
|
872
|
+
- The default skin fallback is now `air` everywhere (`root.html`,
|
|
873
|
+
controls bar, customizer) — `dark` was never a compiled skin, so the old
|
|
874
|
+
fallback selected a skin that doesn't exist.
|
|
875
|
+
|
|
876
|
+
- Installer spec default `ai.provider` is now `auto` (was `openai`); the AI
|
|
877
|
+
wizard records the provider that actually served the run.
|
|
878
|
+
- **CI workflows now honor `CLAUDE_CODE_OAUTH_TOKEN`** — `ui-audit.yml`,
|
|
879
|
+
`ai-content-review.yml`, and `ci-self-repair.yml` previously gated their
|
|
880
|
+
Claude Code agent tier on `ANTHROPIC_API_KEY` alone, silently ignoring a
|
|
881
|
+
configured OAuth token. They now follow the same house convention as
|
|
882
|
+
`claude.yml` / `issue-autopilot.yml`: `CLAUDE_CODE_OAUTH_TOKEN` preferred,
|
|
883
|
+
`ANTHROPIC_API_KEY` used only when it's absent.
|
|
884
|
+
|
|
885
|
+
### Fixed
|
|
904
886
|
|
|
905
|
-
|
|
887
|
+
- **Color-mode toggle exposes the selected mode** ([#521](https://github.com/bamr87/zer0-mistakes/issues/521)).
|
|
888
|
+
`_includes/components/halfmoon.html` server-rendered Light/Dark/Auto all
|
|
889
|
+
`aria-pressed="false"`, and on load `assets/js/halfmoon.js` marked the
|
|
890
|
+
*resolved* OS scheme pressed, so a first visit on an `auto` site announced
|
|
891
|
+
"Dark, pressed" (WCAG 4.1.2). The configured mode is now server-rendered
|
|
892
|
+
`.active` + `aria-pressed="true"`, and the script marks the selected *mode*
|
|
893
|
+
(stored preference, else the site default) while still applying the
|
|
894
|
+
resolved scheme to `data-bs-theme`. Pinned by `test/visual/features/settings-panel.spec.js`.
|
|
895
|
+
- **Footer newsletter hint reaches screen readers on phones** ([#522](https://github.com/bamr87/zer0-mistakes/issues/522)).
|
|
896
|
+
The disabled `#footer-email` input's `aria-describedby` pointed at a
|
|
897
|
+
`d-none d-md-block` paragraph, so below `md` its only explanation was
|
|
898
|
+
`display:none`. The describedby target is now an always-present
|
|
899
|
+
`visually-hidden` span, and the visible paragraph is an `aria-hidden` duplicate.
|
|
900
|
+
The sighted layout is unchanged at every width. Pinned by `test/visual/core/accessibility.spec.js`.
|
|
901
|
+
- **Visual Snapshots no longer reload mid-test** ([#461](https://github.com/bamr87/zer0-mistakes/issues/461)).
|
|
902
|
+
`test/update-snapshots.sh` ran `npm ci` into the bind mount Jekyll was already
|
|
903
|
+
watching, and LiveReload reloaded the page under test ("Execution context was
|
|
904
|
+
destroyed"), hidden by `retries: 1`. The snapshot stack now starts with
|
|
905
|
+
`JEKYLL_LIVERELOAD=0` (no `--livereload`, plus `_config_snapshots.yml`, since
|
|
906
|
+
`_config_dev.yml` turns LiveReload on), and `test/lib/assert_no_livereload.sh`
|
|
907
|
+
fails the run if anything can still reload the page. Plain `docker compose up`
|
|
908
|
+
keeps LiveReload.
|
|
909
|
+
- **Mobile offcanvas TOC scroll spy is now under test** ([#457](https://github.com/bamr87/zer0-mistakes/issues/457)).
|
|
910
|
+
`test/visual/features/scroll-spy.spec.js` gains a 375px block that opens the
|
|
911
|
+
`#tocContents` offcanvas and asserts the active entry tracks the page and stays
|
|
912
|
+
visible inside `.offcanvas-body`. The no-op `gotoBeforeScrollSpy` fixture is
|
|
913
|
+
removed (the `data-bs-spy` it stripped is no longer rendered); its admin call
|
|
914
|
+
site uses `waitForJekyll`.
|
|
915
|
+
- **No orphaned microdata in `<head>`** ([#513](https://github.com/bamr87/zer0-mistakes/issues/513)).
|
|
916
|
+
`_includes/core/head.html` emitted `<meta itemprop="headline|description|datePublished|dateModified">`
|
|
917
|
+
with no `itemscope` ancestor, so every parser discarded them. The block is
|
|
918
|
+
removed; jekyll-seo-tag's JSON-LD and the article layouts' `BlogPosting` item
|
|
919
|
+
already publish the same facts. Pinned by `test/visual/core/head-contract.spec.js`.
|
|
920
|
+
- **Valid breadcrumb `BreadcrumbList` when a section has no index page** ([#512](https://github.com/bamr87/zer0-mistakes/issues/512)).
|
|
921
|
+
Since #204, an unlinked crumb ("Posts" on a site without `/posts/`, or a deep
|
|
922
|
+
middle segment) rendered as a `ListItem` with no `item`. That invalidated the
|
|
923
|
+
whole list, and Google dropped the breadcrumb rich result. Such crumbs now stay
|
|
924
|
+
visible as plain text outside the structured list, and `position` is renumbered
|
|
925
|
+
`1..n`. Every remaining `item` resolves. Pinned by `test/visual/features/breadcrumbs.spec.js`
|
|
926
|
+
(evidence: [`test/visual/evidence/breadcrumbs/`](test/visual/evidence/breadcrumbs/README.md):
|
|
927
|
+
the visible trail is unchanged, with 0px overflow before and after).
|
|
928
|
+
|
|
929
|
+
- **Intro action buttons keep their names on phones, nav chevrons meet the 24px target, and badge links are legible on every skin.** Below 576px the Share button and "Edit on GitHub" link in `_includes/content/intro.html` showed only an icon, so axe reported `button-name`/`link-name`; both now carry an `aria-label` matching their visible text. The edit and "View source" URLs no longer contain a double slash (`blob/main//pages/tags.md`) for pages outside a collection. The merged desktop split-toggle chevron (`_sass/core/_navbar.scss`) grows from 20px to 24px wide (WCAG 2.2 SC 2.5.8 `target-size`). Skin link colours (`_sass/theme/_skins.scss`) no longer apply to `a.badge`, which had turned tag/category chips purple-on-purple on neon (1.45:1, now 5.61:1). Regression test: `test/visual/features/intro-actions-a11y.spec.js`.
|
|
930
|
+
- **Closing the search modal returns focus to where it came from.** The modal is opened from code ("/", Ctrl/Cmd+K, the toggle's click handler), so Bootstrap's data-api focus restore never ran and Escape left focus on `<body>` (WCAG 2.4.3). `assets/js/search-modal.js` now remembers the opener (the clicked Search button, or the focused element) and falls back to the visible `[data-search-toggle]` when a shortcut opened it from the document. Two new tests in `test/visual/features/search.spec.js`.
|
|
931
|
+
- **The navbar brand title no longer truncates on phones.** Next to the sidebar toggle, logo, search and the labelled Menu toggle, a 14-character title at the 20px `.navbar-brand` size lost its tail ("Lifehacker.dev" → "Lifehacker…" on lifehacker.dev post pages at 400px: 121px for 133px of text). Below 576px `#navbar .site-title-text` steps down to 1rem (0.9375rem below 375px), and the logo drops Bootstrap's 1rem `margin-end`, which stacked on the brand group's 0.5rem gap. That title now fits from 375px up on pages with the sidebar toggle and from 320px up without it. Two new tests in `test/visual/features/intro-actions-a11y.spec.js`.
|
|
932
|
+
- **The cookie banner no longer covers the first screen.** Below 768px `components/cookie-consent.html` stacked a heading, a long sentence and three full-width buttons (the shim in `_sass/core/_sidebar-extras.scss`): 324px of an 850px-tall 400px viewport on it-journey.dev and lifehacker.dev, hiding most of the hero or article; on desktop it was 94px and sat over the lower hero copy. It is now a compact bar: a two-line summary over one row of three equal buttons on phones, and a single row from 768px up. The layout lives in `_sass/components/_cookie-banner.scss` and the stacking shim is gone. The banner is a labelled `region` ("Cookie consent"), and the button ids, the modal and the consent logic are unchanged. Height at 400px drops from 324px to 107px, and at 1366px from 94px to 48px. Pinned by `test/visual/features/cookie-banner-compact.spec.js`.
|
|
933
|
+
- **The active skin now moves the whole `--zer0-color-*` layer, not just Bootstrap's** ([#459](https://github.com/bamr87/zer0-mistakes/issues/459)). `_includes/core/tokens-inline.html` re-set `--zer0-color-primary`, `-link` and `-accent` from `theme_color` on `:root` after `main.css`. `:root` and `[data-theme-skin]` have the same specificity, so the config value won on source order. On any site that sets `theme_color`, components reading the theme layer therefore kept the config color in every skin, and `--zer0-color-primary` disagreed with its own `-rgb` companion. The skin now wins: those three keys are emitted only when no palette skin is active, as with `dark` and `contrast`. `theme_color` still sets `secondary`, `danger`, `warning`, `success` and `info`, and the Appearance-panel override still beats both. The rule is documented in [`docs/ui/design-tokens.md`](docs/ui/design-tokens.md#precedence-skin-vs-theme_color) and checked by `test/visual/features/appearance.spec.js` (evidence: [`test/visual/evidence/agent-issue-459/`](test/visual/evidence/agent-issue-459/README.md) — page overflow 0px at six widths; the nine skin baselines are unchanged).
|
|
934
|
+
- **A preview path without a leading slash no longer 404s.** `preview: images/previews/x.webp` was appended straight onto `assets_prefix`, so `components/preview-image.html`, `components/background-image.html`, `content/intro.html` and `content/seo.html` emitted `/assetsimages/previews/x.webp` for the card image, the hero background and `og:image` (165 it-journey content files use that form). All four now prepend `/` to a site-relative path before joining; URLs and `data:` URIs are left alone, and already-slashed or `/assets/`-prefixed paths render byte-identically. `preview-image.html` also gained optional `width`/`height` parameters (emitted only when passed); the article layout's related-post cards pass 1536×1024 so their box is reserved before the lazy image arrives (0px → 217px at 1366px). Pinned by the `Preview Path Join` unit test in `test/test_core.sh` and `test/visual/features/preview-path-join.spec.js`.
|
|
935
|
+
- **The sitemap index no longer puts every page in the DOM twice.** `content/sitemap.html` (the `/sitemap/` page, the search modal's "View all results" target, and it-journey.dev's `/search/`) kept all rows attached. Its script also eagerly built a second copy of every row as a card for the hidden card view: about 19,900 elements on it-journey's `/search/` (431 entries), with Lighthouse mobile TBT at 9.7 s. Rows are still rendered server-side, so the page works without JS and with `?q=`. The script now keeps only one page of 50 matches in the document and appends the next page with **Show more**. Search, filters and sorting work across every row, and cards are built on the first switch to card view, one page at a time. Card text is set through `textContent` rather than interpolated HTML. On the theme's own `/sitemap/` (386 entries), elements after load drop from 23,063 to 8,086, and local Lighthouse mobile TBT drops from 1,662 ms to 181 ms. Badge contrast is fixed too: the collection pill is `text-bg-info` (was white on `#0dcaf0`, 1.96:1), tag chips use `--bs-primary-text-emphasis`, and `+N` overflow chips (white on transparent) get body text and a border. Pinned by `test/visual/features/sitemap-pagination.spec.js`.
|
|
936
|
+
- **The xAI preview-image renderer defaults to `grok-imagine-image-2.0`** ([#474](https://github.com/bamr87/zer0-mistakes/issues/474)). `XAIProvider.default_model()` in `scripts/lib/preview_generator.py` still returned the retired `grok-2-image`, so a site with `preview_images.provider: xai` and no explicit `model:` sent a retired model upstream. An explicitly configured `grok-2-image` is still accepted as an xAI-family model.
|
|
937
|
+
- **A code-copy partial no longer restyles every button on the site** ([#412](https://github.com/bamr87/zer0-mistakes/issues/412)). `_sass/core/code-copy.scss` shipped a bare `.button, button:not(.copy)` rule — an element selector at specificity (0,1,1) that out-ranked `.btn` and any consumer's own class, applying `padding: 0 20px`, `font-size: 11px` and a hardcoded `#bbb` border site-wide. It is scoped to `.code-block-header` / `pre.highlight` now and uses `--zer0-*` tokens, so `#bbb` is gone from the compiled stylesheet. Every button on the site — the theme's own chrome included — gets its intended metrics back (evidence: [`test/visual/evidence/agent-issue-412/`](test/visual/evidence/agent-issue-412/README.md) — page overflow 0px at six widths; the nine skin baselines moved, and every red region in their diffs is a `<button>`).
|
|
938
|
+
- **The article hero no longer lazy-loads its LCP image or shoves the article down when it arrives** ([#485](https://github.com/bamr87/zer0-mistakes/issues/485)). `figure.featured-hero` inherited `components/preview-image.html`'s `loading="lazy"` default and had no reserved box. It now passes `loading="eager" fetchpriority="high" decoding="async"`, and its box is pinned by `.featured-hero img { aspect-ratio: 3 / 2 }`. The box is set in CSS rather than with `width`/`height` attributes, because preview assets vary in shape and `object-fit: cover` crops a portrait instead of stretching it. `preview-image.html` gained optional `fetchpriority`/`decoding` parameters that are emitted only when passed, so every other consumer renders byte-identically (evidence: [`test/visual/evidence/hero-lcp/`](test/visual/evidence/hero-lcp/README.md) — hero loading lazy → eager + fetchpriority=high; content shift when the hero lands 476px → 0px across 2 widths × landscape/portrait).
|
|
939
|
+
- **Mermaid, cytoscape and PostHog no longer load up front, and the auto-hide navbar stops forcing reflows.** `assets/js/mermaid-diagrams.js` now converts fences into figures straight away but injects the ~1 MB Mermaid bundle only when a diagram exists and the first one comes within 400px of the viewport (IntersectionObserver); `components/mermaid.html` passes the bundle URL as `window.zer0MermaidSrc` (a script global, not DOM text, and only http(s) URLs are injected) instead of a `<script defer>`. The local-graph panel loads cytoscape on first open instead of on every indexed page. `analytics/posthog.html` keeps the queueing stub but fetches `array.js` after `load` + idle, and `core/head.html` no longer includes it a second time (`root.html` already did, so every production page called `posthog.init()` twice). `auto-hide-nav.js` measures the navbar with a ResizeObserver (rAF read/next-frame write fallback) and caches the height instead of reading `offsetHeight` at DOMContentLoaded and on resize. Lighthouse mobile, local static build: home TBT 1,705 → 651 ms and weight 5,581 → 2,327 KiB; `/docs/features/mermaid-diagrams/` TBT 2,017 → 243 ms; `auto-hide-nav.js` gone from forced-reflow. New lazy-load test in `test/visual/features/mermaid.spec.js`.
|
|
906
940
|
|
|
907
|
-
- **
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
— 0px page overflow across 320–1440px; 1 cup butter → 227 g, 500 g flour →
|
|
925
|
-
4 cups; ratio percentages identical at 1× and 3×).
|
|
941
|
+
- **The Site Builder no longer jumps the first time it saves a draft.**
|
|
942
|
+
`showDraftChip()` cleared the "Draft saved" chip's `hidden` attribute, and the
|
|
943
|
+
2s timer that follows only removes `is-visible` — an opacity class — so the
|
|
944
|
+
first debounced save moved the chip from `display: none` into layout *for
|
|
945
|
+
good*. Its box is 26px against the 19px "Start over" button beside it, so
|
|
946
|
+
`.wizard-header` grew and took `#wizardTabContent` and every Back/Next row
|
|
947
|
+
below it down with it: 7px where the header's right-hand block had already
|
|
948
|
+
wrapped, a whole wrapped line where those 7px were what tipped it over. The
|
|
949
|
+
chip now holds its box from first paint and is hidden with `visibility`,
|
|
950
|
+
which is what `_setup-wizard.scss` said it did all along ("Kept in the layout
|
|
951
|
+
(no display toggling) so its appearance never shifts the header") and still
|
|
952
|
+
keeps it out of the accessibility tree when it has nothing to say. This is
|
|
953
|
+
what failed the `@critical` stable-height spec on every push to `main`
|
|
954
|
+
(`2029, 2036, 2036, …`), and with it the retry that spec's failure forced
|
|
955
|
+
([bamr87/bamr87#265](https://github.com/bamr87/bamr87/issues/265)) (evidence:
|
|
956
|
+
[`test/visual/evidence/agent-issue-265/`](test/visual/evidence/agent-issue-265/README.md)
|
|
957
|
+
— first draft save moved the wizard 42px on the base branch, 0px here).
|
|
926
958
|
|
|
927
|
-
- **
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
`
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
not
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
`
|
|
945
|
-
`
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
959
|
+
- **Two `test_core.sh` checks could never fail, and one shouted on every clean
|
|
960
|
+
run (#460).** The Liquid nested-tag check grepped for
|
|
961
|
+
{% raw %}`{{.*{{`{% endraw %}, which matches
|
|
962
|
+
any two *sibling* output tags on one line — it flagged 64 of the theme's
|
|
963
|
+
includes, starting with `navigation/sidebar-pagetree.html`'s valid
|
|
964
|
+
{% raw %}`{{ _base }}{{ _section }}`{% endraw %} — and its `return 1` sat inside a `find | while`
|
|
965
|
+
pipeline, i.e. a subshell, so the function printed `[ERROR]` and then reported
|
|
966
|
+
the check as passed. The gem-content check ran `tar -tzf` on the built `.gem`,
|
|
967
|
+
but a gem is an *uncompressed* tar wrapping `metadata.gz`, `data.tar.gz` and
|
|
968
|
+
`checksums.yaml.gz`, so gzip printed `stdin: not in gzip format` four times
|
|
969
|
+
and both branches fell through to "Gem may not contain…" without ever
|
|
970
|
+
inspecting the payload — a gem shipped with no `_layouts/` would have passed.
|
|
971
|
+
The nested-tag pattern is now {% raw %}`{{[^}]*{{`{% endraw %} (cannot cross the first `}`, so
|
|
972
|
+
siblings do not match), both loops read from a process substitution so a
|
|
973
|
+
failure propagates, and the gem check extracts `data.tar.gz` and asserts
|
|
974
|
+
`_layouts/` and `assets/` are really in it. The layout balance check, now
|
|
975
|
+
live, blanks Liquid comment bodies before counting, so prose in a comment that
|
|
976
|
+
quotes a closing delimiter (as `_layouts/root.html`'s per-page-scripts note
|
|
977
|
+
does) is no longer read as an unbalanced tag. New `test/test_core_checks.sh`
|
|
978
|
+
drives both checks against known-good and known-bad fixtures, so a check that
|
|
979
|
+
stops being able to fail is itself a test failure. `./test/test_core.sh` now
|
|
980
|
+
runs clean: 26/26, no `[ERROR]` line, no gzip/tar noise.
|
|
981
|
+
- **Every navbar link emitted invalid HTML — attributes glued together with no
|
|
982
|
+
separating whitespace (#465)** — the Liquid whitespace-trim markers around the
|
|
983
|
+
conditional `aria-current` in `_includes/navigation/navbar.html` ate the
|
|
984
|
+
newlines that separated the surrounding attributes, so the primary nav
|
|
985
|
+
rendered `aria-label="News"aria-current="page"title="News"` (the WHATWG
|
|
986
|
+
`missing-whitespace-between-attributes` parse error). The leading {% raw %}`{%-`{% endraw %}
|
|
987
|
+
stripped the newline after `aria-label` and the trailing {% raw %}`-%}`{% endraw %} the whitespace
|
|
988
|
+
before `title`, which means **two of the four sites were broken on every page,
|
|
989
|
+
not just the current one**: where the conditional sits between two
|
|
990
|
+
unconditional attributes both markers fire even when the `if` emits nothing.
|
|
991
|
+
Parsers recover, so nothing looked broken — but the attributes affected are
|
|
992
|
+
exactly `aria-label`, `aria-current` and `title`, and a stricter parser is
|
|
993
|
+
entitled to drop the "you are here" announcement for screen-reader users. All
|
|
994
|
+
four sites now use the non-trimming {% raw %}`{% if %}`{% endraw %} form already present at line 26
|
|
995
|
+
of the same file, with the separator outside the tag. Two guards in
|
|
996
|
+
`test/test_core.sh`: `test_navbar_attribute_whitespace` renders the real
|
|
997
|
+
include through Liquid across both `aria-current` branches and both nav modes
|
|
998
|
+
(6 of 8 rendered variants were invalid before the fix), and
|
|
999
|
+
`test_attribute_whitespace_in_markup` models the trim rules over every include
|
|
1000
|
+
and layout with no gem dependency — it found a second live instance, a literal
|
|
1001
|
+
missing space in `components/theme-preview-gallery.html`, fixed here too.
|
|
1002
|
+
`test_jekyll_build` re-checks the delivered `_site` bytes. No visual change.
|
|
1003
|
+
- **The weekly UI/UX audit was blind, and reported it as clean.** `sweep.mjs`
|
|
1004
|
+
built its pages with `browser.newPage()`, which `@axe-core/playwright`
|
|
1005
|
+
refuses; the throw was caught by a single per-route `try` that also discarded
|
|
1006
|
+
the overflow, console-error and link-collection data already gathered for
|
|
1007
|
+
that route. Screenshots still succeeded, so the harness looked alive while
|
|
1008
|
+
every accessibility, console, overflow and broken-link result on every route
|
|
1009
|
+
was silently dropped — and the report rendered the absence as "0 axe
|
|
1010
|
+
violations / 0 broken links". Pages are now built from `browser.newContext()`,
|
|
1011
|
+
each measurement fails independently, a scan that errored is reported as
|
|
1012
|
+
UNKNOWN rather than clean, and a measurement that fails on every route turns
|
|
1013
|
+
the sweep red the way a total capture failure already did. On the demo site
|
|
1014
|
+
the sweep goes from 18/21 captured with 21 blackout entries to **21/21
|
|
1015
|
+
captured, 0 harness errors, 191 links crawled and 8 genuinely broken links
|
|
1016
|
+
found** ([#468](https://github.com/bamr87/zer0-mistakes/issues/468)).
|
|
1017
|
+
- **Theme-skin buttons now announce which skin is applied.** The Theme Skin
|
|
1018
|
+
group in Settings → Appearance conveyed selection only through the Bootstrap
|
|
1019
|
+
`.active` class, which carries no accessibility semantics, so screen readers
|
|
1020
|
+
announced nine identical unlabelled buttons — WCAG 2.1 SC 4.1.2 (Name, Role,
|
|
1021
|
+
Value). Each button now ships `aria-pressed`, and the click and "Reset
|
|
1022
|
+
background" handlers keep it in sync with `.active` through one shared
|
|
1023
|
+
helper, matching the sibling color-mode group
|
|
1024
|
+
([#467](https://github.com/bamr87/zer0-mistakes/issues/467)).
|
|
949
1025
|
|
|
950
|
-
- **
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
the
|
|
956
|
-
|
|
1026
|
+
- **Generated posts and notes were invisible on GitHub Pages** — every dated
|
|
1027
|
+
document the wizard wrote was stamped `T09:00:00.000Z` on the day it was
|
|
1028
|
+
generated. Jekyll refuses to publish future-dated documents unless
|
|
1029
|
+
`future: true`, and GitHub Pages builds with the default, so a site generated
|
|
1030
|
+
before 09:00 UTC went live with its posts and notes missing: linked from the
|
|
1031
|
+
collection index and listed in the sitemap, but 404 when clicked. Generated
|
|
1032
|
+
content is now stamped with the actual moment it was written, and a
|
|
1033
|
+
regression test fails if any generated document carries a future date.
|
|
1034
|
+
Found by publishing two example sites and clicking the links.
|
|
1035
|
+
- **Every page of every generated site 404'd on `user-overrides.js`** — the
|
|
1036
|
+
Site Builder writes `user_overrides: true` so the theme loads the palette and
|
|
1037
|
+
font overrides it generates, but that same flag also makes the theme load
|
|
1038
|
+
`assets/js/user-overrides.js`, which the wizard never created. Generated
|
|
1039
|
+
sites now ship a commented stub, so the request resolves and site owners have
|
|
1040
|
+
an obvious place to put their own JavaScript. Found while publishing example
|
|
1041
|
+
sites built by the wizard.
|
|
1042
|
+
- **Every generated landing page shipped an invisible button** —
|
|
1043
|
+
`components/cta-button.html` mapped `variant: outline` to `btn-outline-light`,
|
|
1044
|
+
which is white text on a white border, and the Site Builder's own default
|
|
1045
|
+
call to action uses `outline` on a light hero. `outline` is now an outlined
|
|
1046
|
+
*primary* button; `outline-light` is the explicit variant for a dark surface,
|
|
1047
|
+
and the generated landing engine picks between them from `hero.variant`.
|
|
1048
|
+
The theme's own homepage hero is `bg-primary text-white`, so its two
|
|
1049
|
+
outlined buttons moved to `outline-light` and render exactly as before —
|
|
1050
|
+
a consumer who copied `_data/landing.yml` into a site with a dark hero
|
|
1051
|
+
should make the same one-word change.
|
|
1052
|
+
- **A planned `landing.hero.image` was accepted and then thrown away** — the
|
|
1053
|
+
site plan's schema has offered `landing.hero.image` since the Site Builder
|
|
1054
|
+
shipped, but the landing engine it generates never rendered it, so an agent
|
|
1055
|
+
(or a human) could set a hero image, see it validated, watch it land in
|
|
1056
|
+
`_data/landing.yml`, and get a landing page with no picture. `index.md` now
|
|
1057
|
+
renders it inside the hero, decorative (empty `alt`) so a screen reader does
|
|
1058
|
+
not hear the headline twice. Found by building a site end to end through the
|
|
1059
|
+
new Grok path, where the "Hero image with …" shortcut pointed straight at the
|
|
1060
|
+
dead field.
|
|
1061
|
+
- **A partial hero patch silently wiped the rest of the hero** —
|
|
1062
|
+
`set_site_plan` replaced `landing.hero` wholesale, so the natural agent move
|
|
1063
|
+
of "write the copy now, add the artwork two turns later"
|
|
1064
|
+
(`{landing: {hero: {image}}}`) discarded the headline, subheadline and every
|
|
1065
|
+
call to action, and the landing page quietly reverted to the site title and
|
|
1066
|
+
the default buttons. The hero now merges field by field; `sections`,
|
|
1067
|
+
`navigation.items` and `pages` still replace, because a shorter list has to
|
|
1068
|
+
mean a shorter list. The tool description says so, and the regression test
|
|
1069
|
+
pins both halves.
|
|
957
1070
|
|
|
958
|
-
- **
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
presentation). Navbar: About → Design System. Regression spec:
|
|
966
|
-
`test/visual/features/design-hub.spec.js`.
|
|
1071
|
+
- **A new post appeared at its own URL but on no index** — the generated
|
|
1072
|
+
`_config_dev.yml` turned on Jekyll's experimental incremental regeneration,
|
|
1073
|
+
which rebuilds only documents whose own source changed. Adding a post left
|
|
1074
|
+
the collection index, the home page's latest-posts list and the feed showing
|
|
1075
|
+
the old set, with the post reachable only by typing its URL. New sites are
|
|
1076
|
+
now generated with `incremental: false`; a full rebuild of a fresh site takes
|
|
1077
|
+
about a second and is always right.
|
|
967
1078
|
|
|
968
|
-
- **
|
|
969
|
-
|
|
970
|
-
(
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
`
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
- **
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1079
|
+
- **The 15-second status poll handed the composer back mid-turn** — the Site
|
|
1080
|
+
Builder's proxy poll rebuilt the panel's enabled state from the connection
|
|
1081
|
+
alone, so during a long action (a Docker build, an image render) the input
|
|
1082
|
+
and Send button re-enabled themselves and the Stop button vanished, while
|
|
1083
|
+
tools were still running. A second message could then interleave with the
|
|
1084
|
+
first. The poll now respects the busy state.
|
|
1085
|
+
- **A newly added post never appeared on the running site** — Jekyll's
|
|
1086
|
+
`--watch` only tracks collection documents that existed when `serve` started,
|
|
1087
|
+
so a page or post the assistant added to a running project stayed invisible
|
|
1088
|
+
with no explanation. `write_project_file` now says so in its result and
|
|
1089
|
+
offers a restart, and `run_compose` gained a `restart` action.
|
|
1090
|
+
|
|
1091
|
+
- **Switching colour mode destroyed every Mermaid diagram** — the old include's
|
|
1092
|
+
`MutationObserver` re-render emptied each `.mermaid` div and refilled it with
|
|
1093
|
+
the div's *current* text, which after the first render is the SVG's own
|
|
1094
|
+
stylesheet, and never cleared Mermaid's `data-processed` flag, so
|
|
1095
|
+
`mermaid.run()` skipped the div. Toggling dark mode on `/quickstart/`,
|
|
1096
|
+
`/about/` or `/docs/ruby-101/` replaced the diagram with a wall of
|
|
1097
|
+
`#mermaid-… {font-family: …}` text and a permanent "Loading diagram…" label
|
|
1098
|
+
(reproduced headlessly on `main`: `svgs: 1 → 0` after the toggle). Sources are
|
|
1099
|
+
now kept per figure and every render goes through `mermaid.render()`, so a
|
|
1100
|
+
mode or skin change re-renders from the original definition — asserted by the
|
|
1101
|
+
regression test in `test/visual/features/mermaid.spec.js`.
|
|
1102
|
+
- **The Obsidian wiki-link resolver rewrote the inside of inline SVGs** —
|
|
1103
|
+
`assets/js/obsidian-wiki-links.js` skips text under `CODE`/`PRE`/`A`/
|
|
1104
|
+
`SCRIPT`/`STYLE` by comparing `nodeName`, but elements in the SVG namespace
|
|
1105
|
+
report it in lower case (`style`, `text`), so a Mermaid diagram's own
|
|
1106
|
+
`<style>` was walked and every `#id` selector in it was turned into a
|
|
1107
|
+
`<a class="obsidian-tag">` link. The stylesheet lost its scoping: one
|
|
1108
|
+
diagram's `#arrowhead path { fill }` became a bare `path { fill }` for the
|
|
1109
|
+
whole page, and pie slices rendered dark grey while their legend showed the
|
|
1110
|
+
right colours. The old include escaped it only because the resolver
|
|
1111
|
+
special-cases the `.mermaid` class. The name check is now case-insensitive
|
|
1112
|
+
and any `<svg>` subtree (graphics, never prose) is skipped, with
|
|
1113
|
+
`.zer0-diagram` added to the class exemptions. `test/test_resolver.js` gains
|
|
1114
|
+
a fixture with a lower-case `style`/`text` inside `<svg>`, and the Mermaid
|
|
1115
|
+
spec asserts a pie slice's computed fill equals its own attribute and that no
|
|
1116
|
+
unscoped `path` rule exists on the page.
|
|
988
1117
|
|
|
989
|
-
|
|
1118
|
+
- **The 404 page files a report a maintainer can act on.** "Submit an Issue on
|
|
1119
|
+
GitHub" opened a hand-built form containing two sentences of boilerplate — no
|
|
1120
|
+
page context, no environment, no captured errors. It now opens the feedback
|
|
1121
|
+
widget pre-typed as `fix-page` with the URL that failed (and the page that
|
|
1122
|
+
linked to it) already in the description.
|
|
990
1123
|
|
|
991
|
-
- **
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
untranslated targets disabled — as the first block of the Settings
|
|
997
|
-
Appearance tab, next to Color Mode and Theme Skin. The original header
|
|
998
|
-
dropdown remains available as `variant="navbar"` for consumers that prefer
|
|
999
|
-
it. Same data, same `localStorage("zer0-lang")` preference, same
|
|
1000
|
-
never-a-dead-link contract; `test/visual/features/language-toggle.spec.js`
|
|
1001
|
-
was updated to exercise it through the Settings panel.
|
|
1124
|
+
- **The feedback FAB survives its script failing to load.** It was a `<button>`
|
|
1125
|
+
whose only behaviour came from JavaScript; with the widget now depending on a
|
|
1126
|
+
second script, a 404 on either one would have left a decorative circle in the
|
|
1127
|
+
corner. It is an anchor to the issue form, upgraded in place when the script
|
|
1128
|
+
runs — the same progressive enhancement the inline "Improve" link already had.
|
|
1002
1129
|
|
|
1003
|
-
|
|
1130
|
+
- **The page-feedback Playwright spec dismisses the cookie-consent banner.** The
|
|
1131
|
+
banner is a full-width bar on a layer above the FAB stack, so it swallowed
|
|
1132
|
+
every click aimed at the FAB. Every other spec that touches lower-screen chrome
|
|
1133
|
+
already seeded the consent choice through the shared fixture; this one never
|
|
1134
|
+
did.
|
|
1004
1135
|
|
|
1005
1136
|
- **Finished work kept reopening its own issues** — `scripts/sync-backlog.rb`
|
|
1006
1137
|
treats `_data/backlog.yml` as the source of truth and **reopens** any issue whose
|
|
@@ -1178,7 +1309,6 @@ worse than none.
|
|
|
1178
1309
|
`#info-section` above it, for browsers without `:has()`. Covered by "Settings
|
|
1179
1310
|
opened from the nav menu paints ABOVE it" in
|
|
1180
1311
|
`test/visual/features/mobile-overlay-stacking.spec.js` (evidence:
|
|
1181
|
-
[`test/visual/evidence/navbar-fit/`](test/visual/evidence/navbar-fit/README.md)
|
|
1182
1312
|
— `03-settings-stacking.png`: top element at the panel centre `a.nav-link`
|
|
1183
1313
|
→ the panel's own content; header `z-index` 1046 → 1030).
|
|
1184
1314
|
|
|
@@ -1277,49 +1407,6 @@ worse than none.
|
|
|
1277
1407
|
builds in safe mode and loads no local plugins, so nothing the theme ships is
|
|
1278
1408
|
mandatory; `required_plugin_paths` is now empty and the plugin is optional.
|
|
1279
1409
|
|
|
1280
|
-
### Changed
|
|
1281
|
-
|
|
1282
|
-
- **`_data/consumers.yml` now covers the whole fleet** — added `zer0-pages`,
|
|
1283
|
-
`irony-works`, `wargames` and `zer0-pages-remote`, which were unregistered and
|
|
1284
|
-
therefore invisible to `propagate.rb` in both directions (no release dispatch,
|
|
1285
|
-
never in the drift report). The `it-journey` risk note was corrected: its
|
|
1286
|
-
"~55 shadowed files / ~75 lines of !important CSS working around #338" claim
|
|
1287
|
-
is not supported by `audit-consumer` — only 2 files shadow a theme file, the
|
|
1288
|
-
CSS is 31 lines in this theme's own documented `user_overrides` hook, and no
|
|
1289
|
-
fix numbered #338 could be substantiated in that repo.
|
|
1290
|
-
|
|
1291
|
-
## [1.28.0](https://github.com/bamr87/zer0-mistakes/compare/v1.27.0...v1.28.0) (2026-08-09)
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
### Features
|
|
1295
|
-
|
|
1296
|
-
* **books:** children's picture-book collection with immersive layouts and components ([#328](https://github.com/bamr87/zer0-mistakes/issues/328)) ([e059d1a](https://github.com/bamr87/zer0-mistakes/commit/e059d1afdc95073c5ce5bf9d1516b362979ad402))
|
|
1297
|
-
* **ci:** deploy the site via Actions so examples reach the live domain ([#353](https://github.com/bamr87/zer0-mistakes/issues/353)) ([959243c](https://github.com/bamr87/zer0-mistakes/commit/959243c0e8e504fe5d8dba44b89016b413bc88da))
|
|
1298
|
-
* **docs:** theme-canary reporting contract for downstream theme-scouts (FF-0019) ([#358](https://github.com/bamr87/zer0-mistakes/issues/358)) ([c1c1b30](https://github.com/bamr87/zer0-mistakes/commit/c1c1b309c5504b014602982fc96ec80c3f8f70de))
|
|
1299
|
-
* **examples:** add serialized reading-blog example site ([#339](https://github.com/bamr87/zer0-mistakes/issues/339)) ([aca0b53](https://github.com/bamr87/zer0-mistakes/commit/aca0b53b88067bda80fb299f9d5148ccb185d618))
|
|
1300
|
-
* **includes:** config-driven favicon, GTM gating, og:image fallback fix, sidebar nav aliases ([#327](https://github.com/bamr87/zer0-mistakes/issues/327)) ([fe8aacc](https://github.com/bamr87/zer0-mistakes/commit/fe8aacc234003f9f170fcb3b8b29c60ac18ed94b))
|
|
1301
|
-
* **install:** Claude Code OAuth + multi-provider AI + config-file layer ([#330](https://github.com/bamr87/zer0-mistakes/issues/330)) ([fde414c](https://github.com/bamr87/zer0-mistakes/commit/fde414cce5286f90de1ad02ca6ca40d634be5611))
|
|
1302
|
-
* **layouts:** book-abc board-book layout + ABC art-style skins ([#336](https://github.com/bamr87/zer0-mistakes/issues/336)) ([d88038e](https://github.com/bamr87/zer0-mistakes/commit/d88038e806e0d1a492e5d12b4e10e55fd240d692))
|
|
1303
|
-
* **navigation:** nav: pages sidebar mode — auto-build the tree from page URLs ([#333](https://github.com/bamr87/zer0-mistakes/issues/333)) ([c0c627d](https://github.com/bamr87/zer0-mistakes/commit/c0c627d5f50051e8f5eb4f0d6681244acaaa8d85))
|
|
1304
|
-
* **obsidian:** revamp graph frontend with Obsidian-style controls ([#366](https://github.com/bamr87/zer0-mistakes/issues/366)) ([7143d9c](https://github.com/bamr87/zer0-mistakes/commit/7143d9cd137408ad82981c9f9835204bab3a3db5))
|
|
1305
|
-
* **theme:** consumer-adoption hardening — mobile overlay fixes, zero-data resilience, extension hooks ([#338](https://github.com/bamr87/zer0-mistakes/issues/338)) ([84bcce1](https://github.com/bamr87/zer0-mistakes/commit/84bcce15e66b0bc312f513cef4a9dd11f972a049))
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
### Bug Fixes
|
|
1309
|
-
|
|
1310
|
-
* **books:** pin abc-demo permalink so its cover lands at /books/abc-demo/ ([#345](https://github.com/bamr87/zer0-mistakes/issues/345)) ([943f463](https://github.com/bamr87/zer0-mistakes/commit/943f463c73081e7cc3d914c28a2ec2eea3d1b5ae))
|
|
1311
|
-
* **ci:** give the Dependabot label job an explicit GH_REPO ([#370](https://github.com/bamr87/zer0-mistakes/issues/370)) ([808b20e](https://github.com/bamr87/zer0-mistakes/commit/808b20ebbdcd5b0bc139b90947297cec6d226787))
|
|
1312
|
-
* **ci:** prefer CLAUDE_CODE_OAUTH_TOKEN over ANTHROPIC_API_KEY in all AI workflows ([#334](https://github.com/bamr87/zer0-mistakes/issues/334)) ([043848e](https://github.com/bamr87/zer0-mistakes/commit/043848eb84222240efc121e8112ddc12ab959a64))
|
|
1313
|
-
* **ci:** unbreak the production Pages build, frozen since 2026-08-05 ([#356](https://github.com/bamr87/zer0-mistakes/issues/356)) ([05465cf](https://github.com/bamr87/zer0-mistakes/commit/05465cfd5480a6bdfb0d164d56a892f2825ec1cf))
|
|
1314
|
-
* **i18n:** exclude admin config page from translation to unbreak Pages deploy ([#349](https://github.com/bamr87/zer0-mistakes/issues/349)) ([3f4890c](https://github.com/bamr87/zer0-mistakes/commit/3f4890cee3dd59b7f1cbc6ec235a863017b075fb))
|
|
1315
|
-
* **i18n:** normalise generated prose so translation runs keep CI green ([#342](https://github.com/bamr87/zer0-mistakes/issues/342)) ([70a7234](https://github.com/bamr87/zer0-mistakes/commit/70a723425b8cc6a77e1b845b212a8a7d127a7779))
|
|
1316
|
-
* **navigation:** mark only the current page active in the sidebar nav-tree ([#331](https://github.com/bamr87/zer0-mistakes/issues/331)) ([3f1b723](https://github.com/bamr87/zer0-mistakes/commit/3f1b723169258993d4530dd5817740e62734ccd4))
|
|
1317
|
-
* **sass:** restore mobile navigation in the example, collapsed to a 60px sliver ([#363](https://github.com/bamr87/zer0-mistakes/issues/363)) ([8c7d87a](https://github.com/bamr87/zer0-mistakes/commit/8c7d87af4fd476f06c16ce58ca4d4cd0e2c4169d))
|
|
1318
|
-
|
|
1319
|
-
## [Unreleased]
|
|
1320
|
-
|
|
1321
|
-
### Fixed
|
|
1322
|
-
|
|
1323
1410
|
- **The skip link never moved keyboard focus (#278)** — `_layouts/root.html`
|
|
1324
1411
|
rendered `<main id="main-content">` with no `tabindex`, and `<main>` is not natively focusable, so activating "Skip to main content" scrolled the page while focus stayed on `<body>`: the next `Tab` returned the user to the header nav they had just skipped. That defeats WCAG 2.4.1 (Bypass Blocks) on every consuming site, and the theme's own docs already prescribed the fix (`skip-to-content.md` → *Focus Not Moving* → "Add `tabindex=\"-1\"` to target") while the shipped layout omitted it. Now `<main id="main-content" tabindex="-1">`, paired with `#main-content:focus { outline: none; }` in `_sass/utilities/_focus.scss` so the container does not paint a ring — descendants keep theirs, and the rule is safe only because `-1` keeps the container out of the sequential `Tab` order. Measured across all three engines: focus lands on `#main-content` in Chromium, Firefox **and WebKit** (the engine the report named), where before it moved in none of them. The stale `<div id="main-content">` example in the English and French docs now matches the shipped markup.
|
|
1325
1412
|
- **Seven theme dialogs labelled themselves with a bare `<h5>`** — the search
|
|
@@ -1337,40 +1424,6 @@ widget showed `An error occurred: giscus is not installed on this repository` in
|
|
|
1337
1424
|
- **Docs claimed the widget "won't load on localhost"** — it does. Giscus keys
|
|
1338
1425
|
off the `data-repo` attribute, not the page origin, so the iframe renders and reports real errors locally. The false claim told developers to expect a non-working widget in dev, which is precisely what hid this bug. `pages/_docs/features/giscus-comments.md` now documents localhost as a genuine end-to-end check, with a table mapping each rendered state to its cause.
|
|
1339
1426
|
|
|
1340
|
-
### Added
|
|
1341
|
-
|
|
1342
|
-
- **`giscus-discussions doctor`** — a new subcommand that verifies the entire
|
|
1343
|
-
comment chain end-to-end: repository public, Discussions enabled, `giscus.enabled: true`, `data-repo-id` actually belonging to this repo (the fork trap), `data-category-id` resolving to a real category, and — the part nothing else could check — whether the giscus GitHub App is installed, by asking the Giscus API itself. Exits non-zero with a specific remediation line per failure.
|
|
1344
|
-
- **Giscus health check in CI** — `.github/workflows/giscus-digest.yml` (already
|
|
1345
|
-
scheduled weekly) now runs `doctor` and fails the job with a summary when comments are down, so a sitewide comment outage surfaces on its own instead of waiting for a reader to report it.
|
|
1346
|
-
- **Troubleshooting: "The giscus app is not installed"** — a new section in the
|
|
1347
|
-
feature docs with captured screenshots of both the broken widget and the giscus.app configurator rejecting the repo, an explanation of why this step is uniquely easy to skip, a fork-specific warning, and a copy-pasteable `curl` health check.
|
|
1348
|
-
- **Obsidian graph frontend revamp** — the graph views now mirror the Obsidian
|
|
1349
|
-
desktop experience. The full graph page gains a floating **Graph settings**
|
|
1350
|
-
card (Filters / Display / Forces): search with `tag:`/`path:` operators,
|
|
1351
|
-
per-collection toggles generated from the wiki-index (count badge + color
|
|
1352
|
-
swatch, doubling as the legend), show-orphans and show-unresolved switches,
|
|
1353
|
-
node-size / link-thickness / label-fade sliders, repel-force and
|
|
1354
|
-
link-distance sliders with animated re-layout, plus a zoom / fit / fullscreen
|
|
1355
|
-
button stack, an Obsidian-style hover preview card, live dark-mode restyling,
|
|
1356
|
-
and localStorage persistence. The local graph panel gains a depth selector
|
|
1357
|
-
(1–3) and outgoing/incoming direction switches that re-render the subgraph in
|
|
1358
|
-
place. Same vendored cytoscape.js, unchanged `wiki-index.json` contract
|
|
1359
|
-
(evidence:
|
|
1360
|
-
[`test/visual/evidence/obsidian-graph-revamp/`](test/visual/evidence/obsidian-graph-revamp/README.md);
|
|
1361
|
-
regression: `test/visual/features/obsidian-graph.spec.js`).
|
|
1362
|
-
|
|
1363
|
-
- **Theme-canary reporting contract** (`docs/systems/theme-canary-contract.md`) —
|
|
1364
|
-
the canonical upstream bug-intake protocol for downstream theme-scout agents
|
|
1365
|
-
(it-journey, lifehacker.dev): required `theme-canary` + `from-<consumer>`
|
|
1366
|
-
labels, a deterministic 12-hex dedupe key + hidden body marker, the mandated
|
|
1367
|
-
open-AND-closed pre-filing search, a 5-issues-per-consumer-per-run cap, and a
|
|
1368
|
-
required evidence format that records the theme version/commit observed (so
|
|
1369
|
-
fixed-in-release triage is mechanical). Ships with the matching
|
|
1370
|
-
`theme-canary.yml` issue form.
|
|
1371
|
-
|
|
1372
|
-
### Fixed
|
|
1373
|
-
|
|
1374
1427
|
- **Mobile navigation opened as an unusable 60px sliver in the Swerve of Shore
|
|
1375
1428
|
example.** Its skin set `backdrop-filter` on `.navbar` for a frosted sticky
|
|
1376
1429
|
header, which — per the CSS spec, alongside `transform`/`filter`/`perspective`
|
|
@@ -1407,158 +1460,48 @@ feature docs with captured screenshots of both the broken widget and the giscus.
|
|
|
1407
1460
|
the page that took the site down. Collection-only layouts are now dropped
|
|
1408
1461
|
from generated translations so the `path: fr` default (`layout: default`)
|
|
1409
1462
|
applies, and the affected page is regenerated.
|
|
1410
|
-
3. `CHANGELOG.md` is a published page (`/CHANGELOG/`), so its prose is parsed
|
|
1411
|
-
as Liquid. Two entries quoted Liquid tags without a `raw` guard; one of
|
|
1412
|
-
them genuinely executed `include_relative` on `_config.yml`, which in turn
|
|
1413
|
-
tripped over a literal `mermaid` tag written inside a config comment.
|
|
1414
|
-
Both entries are now guarded and the config comment no longer spells the
|
|
1415
|
-
tag out.
|
|
1416
|
-
|
|
1417
|
-
- **Production builds are now verified before merge.** `.github/workflows/pages.yml`
|
|
1418
|
-
builds (never deploys) on pull requests. No other job ran `jekyll build`
|
|
1419
|
-
against the production config, which is why all three faults above reached
|
|
1420
|
-
`main` with CI green.
|
|
1421
|
-
|
|
1422
|
-
- **GitHub Pages production deploy no longer fails on the translated config
|
|
1423
|
-
page.** The admin config utility `pages/_about/settings/config.md` embeds a
|
|
1424
|
-
raw `_config.yml` dump via {% raw %}`{% include_relative _config.yml %}`{% endraw %}, but the
|
|
1425
|
-
translation pipeline copied the page into `fr/about/settings/` without its
|
|
1426
|
-
sibling data file, so the production `github-pages` build died with
|
|
1427
|
-
`Could not locate the included file '_config.yml'`. The page is now excluded
|
|
1428
|
-
from translation (`translation.exclude` in `_config.yml`) — it has no
|
|
1429
|
-
prose to translate anyway — and the stale `fr/about/settings/config.md` plus
|
|
1430
|
-
its `_data/i18n/manifest.yml` entry are removed.
|
|
1431
|
-
- **Translation runs no longer break the `oneline` check.** `scripts/translate.rb`
|
|
1432
|
-
writes whatever the provider returns, and a provider is free to soft-wrap a
|
|
1433
|
-
translated paragraph across several lines — no prompt instruction reliably
|
|
1434
|
-
prevents it. Wrapped prose then landed in `fr/**`, turned
|
|
1435
|
-
`markdown-oneline.yml` red on the translation PR, and stayed red on `main`
|
|
1436
|
-
after it merged. Two of the currently committed translations were in exactly
|
|
1437
|
-
that state.
|
|
1438
|
-
- `translate.rb` now normalises every page it writes through
|
|
1439
|
-
`tools/unwrap-prose.py` — the same tool CI runs, so the rule has one source
|
|
1440
|
-
of truth instead of a reimplementation that could drift. Best-effort: a
|
|
1441
|
-
missing `python3` warns rather than failing an otherwise good run.
|
|
1442
|
-
- `.github/workflows/translate.yml` runs the same tool as a guaranteed
|
|
1443
|
-
backstop immediately before committing, then `--check`s its own work so a
|
|
1444
|
-
silent failure cannot just move the breakage to the PR's CI run.
|
|
1445
|
-
- The tool is resolved relative to `translate.rb` rather than `--root`;
|
|
1446
|
-
`--root` points at the content tree being translated, so the previous
|
|
1447
|
-
lookup missed the tool whenever the two differed.
|
|
1448
|
-
- Unwrapped the two affected files, so `oneline` passes on `main` again.
|
|
1449
|
-
- Regression test in `test/test_i18n.sh` backed by a new `stub-wrap`
|
|
1450
|
-
provider that soft-wraps at 40 columns. Asserting "output is unwrapped"
|
|
1451
|
-
against the plain stub would have passed whether or not normalisation ran.
|
|
1452
|
-
|
|
1453
|
-
### Added
|
|
1454
|
-
|
|
1455
|
-
- **`examples/` — self-contained demo sites built on the theme.** New top-level
|
|
1456
|
-
directory (excluded from the theme's own site build and from the gem) for
|
|
1457
|
-
complete Jekyll sites that show the theme configured for a particular kind of
|
|
1458
|
-
site. Each has its own `_config.yml`, `Gemfile`, and content, and builds
|
|
1459
|
-
against the local theme sources via `_config_dev.yml`.
|
|
1460
|
-
- `examples/swerve-of-shore/` — **Swerve of Shore**, a serialized literary
|
|
1461
|
-
reading blog rebuilt from
|
|
1462
|
-
[swerveofshore.com](https://www.swerveofshore.com/) with the site owner's
|
|
1463
|
-
permission. 52 pages, 0 broken internal links. Exercises a `series` output
|
|
1464
|
-
collection with nested per-section paths, a data-driven taxonomy
|
|
1465
|
-
(`_data/episodes.yml`) that generates the sidebar rail, the episode
|
|
1466
|
-
schedule with live entry counts, and a section page for every node — so a
|
|
1467
|
-
nav target resolves even where nothing is written yet. Also covers article
|
|
1468
|
-
hero images (`show_hero`), entries ordered by number rather than date, the
|
|
1469
|
-
shared `post-card` component in a single-column feed, and a full editorial
|
|
1470
|
-
light-mode restyle done entirely through `assets/css/user-overrides.css` —
|
|
1471
|
-
no theme files touched. The site's identity, taxonomy, entry titles/dates,
|
|
1472
|
-
and featured images are reproduced, along with a short quoted excerpt per
|
|
1473
|
-
entry (the opening the original publishes in its own RSS feed), attributed
|
|
1474
|
-
and linked back. The essays themselves are not reproduced.
|
|
1475
|
-
- `examples/README.md` — how to run one and the conventions for adding
|
|
1476
|
-
another.
|
|
1477
|
-
- **Theme propagation system — releases now reach the sites built on them.**
|
|
1478
|
-
Releasing ended at RubyGems; nothing told the five downstream consumers a new
|
|
1479
|
-
version existed, so all three pinned sites were still on v1.26.0 when v1.27.0
|
|
1480
|
-
shipped and the two unpinned ones had been silently tracking `main`.
|
|
1481
|
-
- `_data/consumers.yml` — registry of every consumer, its consumption mode
|
|
1482
|
-
(`remote_theme_pinned` / `remote_theme_floating` / `gem` / `path`), and every
|
|
1483
|
-
file that holds a version pin.
|
|
1484
|
-
- `scripts/propagate.rb` — reports pin drift across the registry
|
|
1485
|
-
(`--format text|json|github`, `--strict`) or dispatches a `theme-release`
|
|
1486
|
-
event to each consumer (`--dispatch`).
|
|
1487
|
-
- `.github/workflows/propagate-theme.yml` — dispatches on release publish;
|
|
1488
|
-
weekly drift report. Never pushes to a consumer: each one opens its own PR so
|
|
1489
|
-
its own CI gates the bump.
|
|
1490
|
-
- `templates/consumer/` — the consumer's half of the contract:
|
|
1491
|
-
`bump-theme-pins.sh` (rewrites `remote_theme`, `theme_repo`, and Gemfile gem
|
|
1492
|
-
constraints in one pass; `--check`, `--dry-run`, `--latest`, `--pin`),
|
|
1493
|
-
`theme-bump.yml` (dispatch + weekly schedule + manual), and a
|
|
1494
|
-
`.theme-overrides.yml` starter. The schedule matters most for gem-mode
|
|
1495
|
-
consumers, which have no `remote_theme` and so pick up nothing automatically.
|
|
1496
|
-
- `docs/systems/theme-propagation.md` — how the whole flow fits together.
|
|
1497
|
-
- **`./scripts/bin/manifest --check`** — verifies the committed theme manifest
|
|
1498
|
-
matches the working tree, ignoring `generated_at`. `--dry-run` now emits only
|
|
1499
|
-
YAML on stdout (progress logs moved to stderr) so its output can be diffed
|
|
1500
|
-
directly.
|
|
1501
|
-
- **Consumer extension hooks (`_includes/custom/`).** Four empty stubs the
|
|
1502
|
-
chrome now includes at fixed points — `custom/head.html` (end of `<head>`),
|
|
1503
|
-
`custom/body-start.html` (right after `<body>`, e.g. GTM noscript),
|
|
1504
|
-
`custom/footer.html` (after the theme footer), `custom/body-end.html` (last
|
|
1505
|
-
thing before `</body>`). A consumer site shadows just the stub to inject
|
|
1506
|
-
JSON-LD, fonts, verification tags, or scripts — no more forking
|
|
1507
|
-
`core/head.html`/`root.html` and drifting from the theme. Documented in
|
|
1508
|
-
`_includes/README.md`.
|
|
1509
|
-
- **`components/card-grid.html` + `components/data-card.html`.** A generic,
|
|
1510
|
-
data-driven card grid (title/url/icon/badge/meta-pills/buttons schema) for
|
|
1511
|
-
org hub dashboards, fleet registries, service grids, and link boards —
|
|
1512
|
-
the markup consumer sites have been hand-rolling per page. Includes an
|
|
1513
|
-
optional empty-state message.
|
|
1514
|
-
- **`_layouts/404.html` — the 404 page as a theme layout.** The full 404
|
|
1515
|
-
experience (including the unconfigured-site setup guide) now lives in the
|
|
1516
|
-
theme; a consumer's `/404.html` shrinks from a 224-line vendored copy to a
|
|
1517
|
-
4-line front-matter stub (`layout: "404"`). Setup mode is branded with
|
|
1518
|
-
`site.title` instead of a hardcoded theme welcome, and the stub page's body
|
|
1519
|
-
renders below the standard content for site-specific additions.
|
|
1520
|
-
- **`color_mode_lock` config.** Pin the site to one color mode: visitor
|
|
1521
|
-
preference and OS scheme are ignored, the light/dark/auto switcher is
|
|
1522
|
-
removed, and `core/color-mode-init.html` + `halfmoon.js` enforce the lock
|
|
1523
|
-
pre-paint. Replaces consumer JS workarounds that re-asserted a mode on every
|
|
1524
|
-
`matchMedia` change.
|
|
1525
|
-
- **PostHog privacy options** (`posthog.privacy.*`): `respect_gpc` (honor the
|
|
1526
|
-
Global Privacy Control signal alongside DNT, default on), `require_consent`
|
|
1527
|
-
(start opted out with memory-only persistence until the visitor accepts the
|
|
1528
|
-
cookie-consent "analytics" category), and `geoip_disable` (no IP→location
|
|
1529
|
-
resolution). Upstreams the deltas consumer sites were maintaining in a
|
|
1530
|
-
full fork of `analytics/posthog.html`.
|
|
1531
|
-
- **`news:` config surface for the news/section layouts.** `category_base`
|
|
1532
|
-
(e.g. `/categories/` instead of the hardcoded `/news/`), `index_url`,
|
|
1533
|
-
`hero: false`, `archives_url`, and a `newsletter` block (endpoint-or-mailto,
|
|
1534
|
-
or hidden entirely — the old markup shipped a form that submitted nowhere).
|
|
1535
|
-
|
|
1536
|
-
### Changed
|
|
1463
|
+
3. `CHANGELOG.md` is a published page (`/CHANGELOG/`), so its prose is parsed
|
|
1464
|
+
as Liquid. Two entries quoted Liquid tags without a `raw` guard; one of
|
|
1465
|
+
them genuinely executed `include_relative` on `_config.yml`, which in turn
|
|
1466
|
+
tripped over a literal `mermaid` tag written inside a config comment.
|
|
1467
|
+
Both entries are now guarded and the config comment no longer spells the
|
|
1468
|
+
tag out.
|
|
1537
1469
|
|
|
1538
|
-
- **
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
archive month links render only when an archives page exists. A data-less
|
|
1543
|
-
consumer now gets a fully working magazine homepage instead of empty chrome
|
|
1544
|
-
and 404 links.
|
|
1545
|
-
- **Zero-`_data` resilience across components.** The skin quick-select and
|
|
1546
|
-
theme customizer fall back to the compiled skin registry when
|
|
1547
|
-
`_data/theme_skins.yml` is absent; the page-feedback widget falls back to a
|
|
1548
|
-
generic four-type taxonomy when `_data/feedback_types.yml` is absent; the
|
|
1549
|
-
landing get-started band (theme install cards) renders only when the site
|
|
1550
|
-
ships a `landing.get_started` block — a data-less consumer no longer
|
|
1551
|
-
advertises the theme's own install methods.
|
|
1552
|
-
- **`home` layout accepts `hide_intro` as an alias of `hide_title`**, matching
|
|
1553
|
-
the flag other layouts use for "suppress the generated page header".
|
|
1554
|
-
- **`halfmoon.js` honors `color_mode_default`.** The switcher no longer
|
|
1555
|
-
overrides the configured default with the OS preference on first visit
|
|
1556
|
-
(previously the page could flip modes right after load).
|
|
1557
|
-
- The default skin fallback is now `air` everywhere (`root.html`,
|
|
1558
|
-
controls bar, customizer) — `dark` was never a compiled skin, so the old
|
|
1559
|
-
fallback selected a skin that doesn't exist.
|
|
1470
|
+
- **Production builds are now verified before merge.** `.github/workflows/pages.yml`
|
|
1471
|
+
builds (never deploys) on pull requests. No other job ran `jekyll build`
|
|
1472
|
+
against the production config, which is why all three faults above reached
|
|
1473
|
+
`main` with CI green.
|
|
1560
1474
|
|
|
1561
|
-
|
|
1475
|
+
- **GitHub Pages production deploy no longer fails on the translated config
|
|
1476
|
+
page.** The admin config utility `pages/_about/settings/config.md` embeds a
|
|
1477
|
+
raw `_config.yml` dump via {% raw %}`{% include_relative _config.yml %}`{% endraw %}, but the
|
|
1478
|
+
translation pipeline copied the page into `fr/about/settings/` without its
|
|
1479
|
+
sibling data file, so the production `github-pages` build died with
|
|
1480
|
+
`Could not locate the included file '_config.yml'`. The page is now excluded
|
|
1481
|
+
from translation (`translation.exclude` in `_config.yml`) — it has no
|
|
1482
|
+
prose to translate anyway — and the stale `fr/about/settings/config.md` plus
|
|
1483
|
+
its `_data/i18n/manifest.yml` entry are removed.
|
|
1484
|
+
- **Translation runs no longer break the `oneline` check.** `scripts/translate.rb`
|
|
1485
|
+
writes whatever the provider returns, and a provider is free to soft-wrap a
|
|
1486
|
+
translated paragraph across several lines — no prompt instruction reliably
|
|
1487
|
+
prevents it. Wrapped prose then landed in `fr/**`, turned
|
|
1488
|
+
`markdown-oneline.yml` red on the translation PR, and stayed red on `main`
|
|
1489
|
+
after it merged. Two of the currently committed translations were in exactly
|
|
1490
|
+
that state.
|
|
1491
|
+
- `translate.rb` now normalises every page it writes through
|
|
1492
|
+
`tools/unwrap-prose.py` — the same tool CI runs, so the rule has one source
|
|
1493
|
+
of truth instead of a reimplementation that could drift. Best-effort: a
|
|
1494
|
+
missing `python3` warns rather than failing an otherwise good run.
|
|
1495
|
+
- `.github/workflows/translate.yml` runs the same tool as a guaranteed
|
|
1496
|
+
backstop immediately before committing, then `--check`s its own work so a
|
|
1497
|
+
silent failure cannot just move the breakage to the PR's CI run.
|
|
1498
|
+
- The tool is resolved relative to `translate.rb` rather than `--root`;
|
|
1499
|
+
`--root` points at the content tree being translated, so the previous
|
|
1500
|
+
lookup missed the tool whenever the two differed.
|
|
1501
|
+
- Unwrapped the two affected files, so `oneline` passes on `main` again.
|
|
1502
|
+
- Regression test in `test/test_i18n.sh` backed by a new `stub-wrap`
|
|
1503
|
+
provider that soft-wraps at 40 columns. Asserting "output is unwrapped"
|
|
1504
|
+
against the plain stub would have passed whether or not normalisation ran.
|
|
1562
1505
|
|
|
1563
1506
|
- **`_data/theme-manifest.yml` was 13 minors stale.** It sat at `1.14.0` while
|
|
1564
1507
|
the theme shipped to `1.27.0`, so every SHA-256 in it was wrong and
|
|
@@ -1593,71 +1536,6 @@ feature docs with captured screenshots of both the broken widget and the giscus.
|
|
|
1593
1536
|
`:root` (set by `auto-hide-nav.js`), so stylesheets can align overlays with
|
|
1594
1537
|
the real header instead of hard-coding its pixel height.
|
|
1595
1538
|
|
|
1596
|
-
### Added
|
|
1597
|
-
|
|
1598
|
-
- **ABC board books (`book-abc` layout) — the "ABC & Language" series.** A new
|
|
1599
|
-
immersive, single-scroll toddler alphabet layout (`_layouts/book-abc.html`)
|
|
1600
|
-
driven entirely by an `alphabet:` front-matter list — one big letter, one
|
|
1601
|
-
word, one picture per card, with A–Z quick-jump anchors and a cover hero.
|
|
1602
|
-
The big letter is HTML typography (never baked into the art), and a card
|
|
1603
|
-
whose plate is still `planned` shows a tinted "illustration coming soon"
|
|
1604
|
-
placeholder so a book reads end-to-end before any art renders. New
|
|
1605
|
-
`_includes/components/abc-letter.html` renders each card; `_sass/components/_book.scss`
|
|
1606
|
-
gains `.abc-board` / `.abc-letter-*` styles plus a `.abc-style--<id>` skin per
|
|
1607
|
-
shared art-style id. `components/bookshelf.html` now lists both `book` and
|
|
1608
|
-
`book-abc` books, grouped into series shelves from `_data/series.yml`;
|
|
1609
|
-
`book-card.html` shows a letter count for ABC books. Ships a demo book
|
|
1610
|
-
(`pages/_books/abc-demo/`) + default series metadata (`_data/series.yml`).
|
|
1611
|
-
Regression test [`test/visual/features/book-abc.spec.js`](test/visual/features/book-abc.spec.js)
|
|
1612
|
-
and before/after evidence in
|
|
1613
|
-
[`test/visual/evidence/book-abc/`](test/visual/evidence/book-abc/). Docs:
|
|
1614
|
-
[`docs/features/abc-books.md`](docs/features/abc-books.md).
|
|
1615
|
-
- **`nav: pages` sidebar mode — auto-build the left tree from page URLs.** A new
|
|
1616
|
-
sidebar mode (`_includes/navigation/sidebar-pagetree.html`) derives a
|
|
1617
|
-
collapsible section tree purely from page permalinks under a `sidebar.base`
|
|
1618
|
-
prefix — no curated `_data/navigation/*.yml` file to write or keep in sync.
|
|
1619
|
-
Enable per page / collection / site with `sidebar: {nav: pages, base: /docs/,
|
|
1620
|
-
order_by: nav_order, title: …}`. It covers plain pages (`site.html_pages`) and
|
|
1621
|
-
collection documents (`site.documents`) alike, groups them by first path
|
|
1622
|
-
segment, humanizes section labels from the URL (never leaking a generic
|
|
1623
|
-
"Index" title), sorts each section by a numeric `order_by` (natural order),
|
|
1624
|
-
supports per-page `sidebar_label` / `sidebar_exclude`, and marks only the
|
|
1625
|
-
current page active with its section expanded server-side — pure Liquid, so
|
|
1626
|
-
it is GitHub Pages / `remote_theme` safe. Documented at
|
|
1627
|
-
`/docs/features/sidebar-page-tree/`.
|
|
1628
|
-
- **Claude Code OAuth in the AI installer** — the spec-driven installer
|
|
1629
|
-
(`scripts/bin/install`) is now multi-provider. `scripts/install/ai/client.sh`
|
|
1630
|
-
resolves a provider via `ZER0_AI_PROVIDER` (default `auto`), preferring the
|
|
1631
|
-
logged-in `claude` CLI (**Claude Code OAuth** — zero key handling), then the
|
|
1632
|
-
Anthropic Messages API (`CLAUDE_CODE_OAUTH_TOKEN` OAuth bearer or
|
|
1633
|
-
`ANTHROPIC_API_KEY`), then OpenAI. `install doctor` reports the active
|
|
1634
|
-
provider; `--ai-provider` / `--ai-model` / `ZER0_AI_MODEL` tune it; `--no-ai`
|
|
1635
|
-
/ `ZER0_NO_AI=1` disable it. User context is sanitized before every call.
|
|
1636
|
-
- **Config-file layer for the installer** — new `scripts/install/config.sh`
|
|
1637
|
-
discovers and merges `~/.config/zer0/install.yml`, `<target>/zer0.install.yml`,
|
|
1638
|
-
`<target>/.zer0/config.yml`, and `--config FILE` (precedence:
|
|
1639
|
-
defaults < profile < config < env < flags). Recognises site / github / theme /
|
|
1640
|
-
deploy / agents / tasks / ai keys; API keys stay environment-only.
|
|
1641
|
-
- **`install suggest`** subcommand — recommend a profile + deploy target
|
|
1642
|
-
(AI-assisted with rule-based fallback) — plus `--yes` as an alias for
|
|
1643
|
-
`--auto-accept`.
|
|
1644
|
-
- Installer regression matrix (`test/test_installer.sh`) now covers AI
|
|
1645
|
-
provider resolution, text extraction across provider shapes, the config-file
|
|
1646
|
-
layer + precedence, and the `doctor` AI check (all offline).
|
|
1647
|
-
|
|
1648
|
-
### Changed
|
|
1649
|
-
|
|
1650
|
-
- Installer spec default `ai.provider` is now `auto` (was `openai`); the AI
|
|
1651
|
-
wizard records the provider that actually served the run.
|
|
1652
|
-
- **CI workflows now honor `CLAUDE_CODE_OAUTH_TOKEN`** — `ui-audit.yml`,
|
|
1653
|
-
`ai-content-review.yml`, and `ci-self-repair.yml` previously gated their
|
|
1654
|
-
Claude Code agent tier on `ANTHROPIC_API_KEY` alone, silently ignoring a
|
|
1655
|
-
configured OAuth token. They now follow the same house convention as
|
|
1656
|
-
`claude.yml` / `issue-autopilot.yml`: `CLAUDE_CODE_OAUTH_TOKEN` preferred,
|
|
1657
|
-
`ANTHROPIC_API_KEY` used only when it's absent.
|
|
1658
|
-
|
|
1659
|
-
### Fixed
|
|
1660
|
-
|
|
1661
1539
|
- **Left-sidebar nav highlighted every item as "active".** `nav-tree.html`
|
|
1662
1540
|
used {% raw %}`{% assign is_active = page.url == item.url %}`{% endraw %}, but Liquid `assign`
|
|
1663
1541
|
does not evaluate `==` — it stored `page.url` (always truthy), so every link
|
|
@@ -1688,6 +1566,134 @@ feature docs with captured screenshots of both the broken widget and the giscus.
|
|
|
1688
1566
|
`_config.yml` template add `jekyll-include-cache` (required by the theme's
|
|
1689
1567
|
layouts).
|
|
1690
1568
|
|
|
1569
|
+
## [1.31.0](https://github.com/bamr87/zer0-mistakes/compare/v1.30.0...v1.31.0) (2026-10-07)
|
|
1570
|
+
|
|
1571
|
+
|
|
1572
|
+
### Features
|
|
1573
|
+
|
|
1574
|
+
* **navigation:** two clean navbar label tiers, merged chevron, centred grid ([#495](https://github.com/bamr87/zer0-mistakes/issues/495)) ([9ebb29a](https://github.com/bamr87/zer0-mistakes/commit/9ebb29a4662fbc4c62d3fdd8df9c282bdd181204))
|
|
1575
|
+
* **theme:** four consumer extension points for notes/knowledge-base builds ([#492](https://github.com/bamr87/zer0-mistakes/issues/492)) ([1e2b228](https://github.com/bamr87/zer0-mistakes/commit/1e2b2283303012b28b9e81209fb66d0344aa0597))
|
|
1576
|
+
|
|
1577
|
+
|
|
1578
|
+
### Bug Fixes
|
|
1579
|
+
|
|
1580
|
+
* **article:** eager-load the hero LCP image and reserve its box ([#498](https://github.com/bamr87/zer0-mistakes/issues/498)) ([529b84b](https://github.com/bamr87/zer0-mistakes/commit/529b84bd0f5ea8e79b7711187b52b2bb80c5b134)), closes [#485](https://github.com/bamr87/zer0-mistakes/issues/485)
|
|
1581
|
+
* **ci:** keep a LiveReload push from crashing the generic evidence generator ([#500](https://github.com/bamr87/zer0-mistakes/issues/500)) ([eb1b5ae](https://github.com/bamr87/zer0-mistakes/commit/eb1b5ae201ed0829e0c3fac05e629e55a6ea1040))
|
|
1582
|
+
* **ci:** Playwright 1.58 attachment names, docs front matter, test race ([#497](https://github.com/bamr87/zer0-mistakes/issues/497)) ([f1bdc7e](https://github.com/bamr87/zer0-mistakes/commit/f1bdc7ef22091f0506617b11a95e357c439cfa94))
|
|
1583
|
+
* **ci:** stop auto-merge guard failing on Dependabot Actions bumps ([#503](https://github.com/bamr87/zer0-mistakes/issues/503)) ([a998b2d](https://github.com/bamr87/zer0-mistakes/commit/a998b2dd9cf96bb1fd09ac3a95644908713afc37))
|
|
1584
|
+
* **features:** escape `<en-url>` in the translation card so the Features page renders ([#505](https://github.com/bamr87/zer0-mistakes/issues/505)) ([8e4345f](https://github.com/bamr87/zer0-mistakes/commit/8e4345f28dfc675b5efe95ba66ec72af613cbcf5))
|
|
1585
|
+
* **includes:** join preview paths without a leading slash under assets_prefix ([#509](https://github.com/bamr87/zer0-mistakes/issues/509)) ([406250c](https://github.com/bamr87/zer0-mistakes/commit/406250c2b5b94469cae9a0b6f93e8782cb8509f9))
|
|
1586
|
+
* **includes:** stop the draft chip shifting the Site Builder on first save ([#489](https://github.com/bamr87/zer0-mistakes/issues/489)) ([d472aa2](https://github.com/bamr87/zer0-mistakes/commit/d472aa267e164212cf8b844e701cfcdad08e4d8d))
|
|
1587
|
+
* **layouts:** one main landmark per page on post, notebook and note ([#487](https://github.com/bamr87/zer0-mistakes/issues/487)) ([78b0910](https://github.com/bamr87/zer0-mistakes/commit/78b0910fb2258591eab9ba13efb5ac037eee80c5))
|
|
1588
|
+
* **navigation:** stop Liquid whitespace-trim gluing navbar attributes ([#477](https://github.com/bamr87/zer0-mistakes/issues/477)) ([4349ea1](https://github.com/bamr87/zer0-mistakes/commit/4349ea17d690e5e6b8585f1d3a33b3ea4d3bf4fe))
|
|
1589
|
+
* **scripts:** default xAI preview renderer to grok-imagine-image-2.0 ([#499](https://github.com/bamr87/zer0-mistakes/issues/499)) ([95cebdb](https://github.com/bamr87/zer0-mistakes/commit/95cebdb535799544f05ed5929e528a074448ef63)), closes [#474](https://github.com/bamr87/zer0-mistakes/issues/474)
|
|
1590
|
+
* **tests:** make the Liquid nested-tag and gem-content checks able to fail ([#478](https://github.com/bamr87/zer0-mistakes/issues/478)) ([8510d08](https://github.com/bamr87/zer0-mistakes/commit/8510d0824f79823f66f765f12db9be9b67fff3ae))
|
|
1591
|
+
* **tokens:** let the active skin win over site theme_color for skin-owned tokens ([#502](https://github.com/bamr87/zer0-mistakes/issues/502)) ([af468e0](https://github.com/bamr87/zer0-mistakes/commit/af468e072543a448e7be80230f3d3a246b5e758e))
|
|
1592
|
+
* **ui:** make the cookie consent banner a compact bottom bar ([#510](https://github.com/bamr87/zer0-mistakes/issues/510)) ([2d7d0db](https://github.com/bamr87/zer0-mistakes/commit/2d7d0db7f9f6b1433b63d8be76103cce2fd7fb05))
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
### Performance Improvements
|
|
1596
|
+
|
|
1597
|
+
* **js:** lazy-load Mermaid and cytoscape, defer PostHog, stop nav reflows ([#508](https://github.com/bamr87/zer0-mistakes/issues/508)) ([702789c](https://github.com/bamr87/zer0-mistakes/commit/702789cecf93d8e9b9f7013168ca47f0294064eb))
|
|
1598
|
+
* **sitemap:** keep one page of the index in the DOM and build cards lazily ([#511](https://github.com/bamr87/zer0-mistakes/issues/511)) ([9e42fcb](https://github.com/bamr87/zer0-mistakes/commit/9e42fcbd9421a994fd22a347bbef95573ce340a9))
|
|
1599
|
+
|
|
1600
|
+
## [1.30.0](https://github.com/bamr87/zer0-mistakes/compare/v1.29.0...v1.30.0) (2026-09-12)
|
|
1601
|
+
|
|
1602
|
+
|
|
1603
|
+
### Features
|
|
1604
|
+
|
|
1605
|
+
* **ci:** produce visual evidence and baselines on PRs, not just verify them ([#462](https://github.com/bamr87/zer0-mistakes/issues/462)) ([a377fae](https://github.com/bamr87/zer0-mistakes/commit/a377fae6ea31a0bb015479dea6d1a7c41e141c3f))
|
|
1606
|
+
* **includes:** add background-image.html for CSS-painted cover art ([#451](https://github.com/bamr87/zer0-mistakes/issues/451)) ([9b15a67](https://github.com/bamr87/zer0-mistakes/commit/9b15a673f57b8f7f1f9dae9262191742d99d8080))
|
|
1607
|
+
* **includes:** Claude or Grok sessions in the Site Builder ([#473](https://github.com/bamr87/zer0-mistakes/issues/473)) ([e1c5753](https://github.com/bamr87/zer0-mistakes/commit/e1c57531fc23be8d071757cd1941e1ae15285da7))
|
|
1608
|
+
* **includes:** file the fleet issue contract from the feedback widget ([#472](https://github.com/bamr87/zer0-mistakes/issues/472)) ([24d4e2c](https://github.com/bamr87/zer0-mistakes/commit/24d4e2c6380541a894e9e671f0f0b0b859a29b05))
|
|
1609
|
+
* **includes:** make theme-color track the page surface, not the accent ([#447](https://github.com/bamr87/zer0-mistakes/issues/447)) ([f1fda85](https://github.com/bamr87/zer0-mistakes/commit/f1fda857bb0cf5bd64bebfc1215ba0a906f05e5c))
|
|
1610
|
+
* **includes:** themed Mermaid figures + toolbar ([#455](https://github.com/bamr87/zer0-mistakes/issues/455)) ([96776fa](https://github.com/bamr87/zer0-mistakes/commit/96776fa48bbe7b63058d1d246962019c745d7b93))
|
|
1611
|
+
* **scripts:** adopt the shared ai-runner kit for claude-run; consumers registry fixes; hub baseline ([#475](https://github.com/bamr87/zer0-mistakes/issues/475)) ([feb4133](https://github.com/bamr87/zer0-mistakes/commit/feb41332eb15d2c13fe0c0f6d15b61007e14daa3))
|
|
1612
|
+
|
|
1613
|
+
|
|
1614
|
+
### Bug Fixes
|
|
1615
|
+
|
|
1616
|
+
* **a11y:** decouple heading size from heading level in theme chrome ([#450](https://github.com/bamr87/zer0-mistakes/issues/450)) ([bb92eb5](https://github.com/bamr87/zer0-mistakes/commit/bb92eb583c955e76339a9c7ab98532b35e226b36))
|
|
1617
|
+
* **a11y:** give footer icon links an accessible name, announce search results ([#441](https://github.com/bamr87/zer0-mistakes/issues/441)) ([a1811e8](https://github.com/bamr87/zer0-mistakes/commit/a1811e81ac0c17b0836994be7c48eba51252bae7))
|
|
1618
|
+
* **a11y:** stop emitting sidebar/TOC controls on layouts that render no offcanvas ([#443](https://github.com/bamr87/zer0-mistakes/issues/443)) ([619322d](https://github.com/bamr87/zer0-mistakes/commit/619322d8fd7c6e2a700ba154e065bf65caf67461))
|
|
1619
|
+
* **ci:** run the autogen lane's tooling from the base branch, not the PR ([#464](https://github.com/bamr87/zer0-mistakes/issues/464)) ([8473050](https://github.com/bamr87/zer0-mistakes/commit/8473050be2b4ddfd994c7bea8a8c35e37a66b7f8))
|
|
1620
|
+
* **ci:** stop the UI audit reporting a measurement blackout as a clean run ([#471](https://github.com/bamr87/zer0-mistakes/issues/471)) ([ab92619](https://github.com/bamr87/zer0-mistakes/commit/ab9261946e088417dabe4291590da1c7a964d4fa))
|
|
1621
|
+
* **content:** raw-protect Liquid that is written as documentation ([#446](https://github.com/bamr87/zer0-mistakes/issues/446)) ([6123c1f](https://github.com/bamr87/zer0-mistakes/commit/6123c1f1e6ffd167376d4ef421b0a9f78af3985e))
|
|
1622
|
+
* **includes:** declare charset inside the 1024-byte window, make the feed discoverable ([#440](https://github.com/bamr87/zer0-mistakes/issues/440)) ([4025205](https://github.com/bamr87/zer0-mistakes/commit/40252050ec21c70aa1d84820fdcde6d564e03478)), closes [#372](https://github.com/bamr87/zer0-mistakes/issues/372) [#371](https://github.com/bamr87/zer0-mistakes/issues/371)
|
|
1623
|
+
* **includes:** expose skin-button selected state via aria-pressed ([#469](https://github.com/bamr87/zer0-mistakes/issues/469)) ([6579b16](https://github.com/bamr87/zer0-mistakes/commit/6579b1621a5eff147e224977633728aadc960505)), closes [#467](https://github.com/bamr87/zer0-mistakes/issues/467)
|
|
1624
|
+
* **install:** stop seeding the theme's own navigation into consumers ([#449](https://github.com/bamr87/zer0-mistakes/issues/449)) ([232857c](https://github.com/bamr87/zer0-mistakes/commit/232857c66d7c3abccb166b5151a7f80a74dd17ca))
|
|
1625
|
+
* **navigation:** scroll spy bolds the section actually being read ([#456](https://github.com/bamr87/zer0-mistakes/issues/456)) ([5ff38bf](https://github.com/bamr87/zer0-mistakes/commit/5ff38bf98faf96cdc3bf63ea3f0e7b10e21f3aab))
|
|
1626
|
+
* **sass:** stop navbar controls flickering under a stationary pointer ([#453](https://github.com/bamr87/zer0-mistakes/issues/453)) ([fc84b9a](https://github.com/bamr87/zer0-mistakes/commit/fc84b9a4c714f8e04b8a0f940bed9e3795c144bc)), closes [#404](https://github.com/bamr87/zer0-mistakes/issues/404)
|
|
1627
|
+
* **scripts:** restore nested translation placeholders instead of leaking them ([#452](https://github.com/bamr87/zer0-mistakes/issues/452)) ([00cab73](https://github.com/bamr87/zer0-mistakes/commit/00cab73d915f4e116040ef6ca4c0381669ae4eb2))
|
|
1628
|
+
|
|
1629
|
+
|
|
1630
|
+
### Performance Improvements
|
|
1631
|
+
|
|
1632
|
+
* **ci:** run the critical PR gate on 3 workers instead of 1 ([#481](https://github.com/bamr87/zer0-mistakes/issues/481)) ([b3fcbc7](https://github.com/bamr87/zer0-mistakes/commit/b3fcbc76a1af2a3a5e43eb28fbff7b3057751de6))
|
|
1633
|
+
* **includes:** strip developer doc banners from delivered HTML ([#445](https://github.com/bamr87/zer0-mistakes/issues/445)) ([89b10f1](https://github.com/bamr87/zer0-mistakes/commit/89b10f1ff361c919fd631d0e7e664ed6d7c28a14))
|
|
1634
|
+
|
|
1635
|
+
## [1.29.0](https://github.com/bamr87/zer0-mistakes/compare/v1.28.0...v1.29.0) (2026-09-01)
|
|
1636
|
+
|
|
1637
|
+
|
|
1638
|
+
### Features
|
|
1639
|
+
|
|
1640
|
+
* **analytics:** track and display per-page view counts ([#413](https://github.com/bamr87/zer0-mistakes/issues/413)) ([e488c4c](https://github.com/bamr87/zer0-mistakes/commit/e488c4c3101da78e98eecbf8299ce7c8705ed281))
|
|
1641
|
+
* **design:** fill Fab, PostCard, Skeleton + motion/layers gaps in the design-system mirror ([#391](https://github.com/bamr87/zer0-mistakes/issues/391)) ([3b49741](https://github.com/bamr87/zer0-mistakes/commit/3b497417564b4c5e3d71eaa113cb136d2cdaf15c))
|
|
1642
|
+
* **includes:** icon-only language trigger and a compact, positive menu ([#431](https://github.com/bamr87/zer0-mistakes/issues/431)) ([353bfa5](https://github.com/bamr87/zer0-mistakes/commit/353bfa5f3a8dd949ca6e513213a155d648218642)), closes [#406](https://github.com/bamr87/zer0-mistakes/issues/406)
|
|
1643
|
+
* **includes:** live preview, vertical stepper and draft persistence in the setup wizard ([#432](https://github.com/bamr87/zer0-mistakes/issues/432)) ([73bdc55](https://github.com/bamr87/zer0-mistakes/commit/73bdc5547350c448e1617ec6cf5b9f49b10d65fb)), closes [#408](https://github.com/bamr87/zer0-mistakes/issues/408)
|
|
1644
|
+
* **layouts:** add cookbook collection with recipe scaling and unit conversion ([#414](https://github.com/bamr87/zer0-mistakes/issues/414)) ([bb8eefa](https://github.com/bamr87/zer0-mistakes/commit/bb8eefa2beea0104fec28d173a1e57f369acada8))
|
|
1645
|
+
* **pages:** publish the design system and page canvas on the live site ([#392](https://github.com/bamr87/zer0-mistakes/issues/392)) ([6cf73cd](https://github.com/bamr87/zer0-mistakes/commit/6cf73cdf2cca9ec02394b6ae1ba7e39c19969134))
|
|
1646
|
+
* **sass:** align design tokens with the Claude Design system ([#389](https://github.com/bamr87/zer0-mistakes/issues/389)) ([7fc2fe0](https://github.com/bamr87/zer0-mistakes/commit/7fc2fe02683d652c0326536158bd48b3690df51f))
|
|
1647
|
+
|
|
1648
|
+
|
|
1649
|
+
### Bug Fixes
|
|
1650
|
+
|
|
1651
|
+
* **a11y:** dialog titles use a bare <h5>, skipping heading levels ([#387](https://github.com/bamr87/zer0-mistakes/issues/387)) ([98fd6f9](https://github.com/bamr87/zer0-mistakes/commit/98fd6f9e63dfb75c58efc3b15a642fb3e4c4095b))
|
|
1652
|
+
* **ci:** fail the content review when it did not actually run ([#424](https://github.com/bamr87/zer0-mistakes/issues/424)) ([f048cb2](https://github.com/bamr87/zer0-mistakes/commit/f048cb22e565b3122d6682c026e13521b6fe52d9)), closes [#418](https://github.com/bamr87/zer0-mistakes/issues/418)
|
|
1653
|
+
* **ci:** fail the Pages build on Liquid errors, unmangle two live pages ([#439](https://github.com/bamr87/zer0-mistakes/issues/439)) ([afd2ec8](https://github.com/bamr87/zer0-mistakes/commit/afd2ec83879a793d77dfac21b41d74d5204126c4))
|
|
1654
|
+
* **ci:** make the pixel gate see the data files that move pixels ([#425](https://github.com/bamr87/zer0-mistakes/issues/425)) ([02ea639](https://github.com/bamr87/zer0-mistakes/commit/02ea639b3152900682ca298bd172925133d10dea)), closes [#417](https://github.com/bamr87/zer0-mistakes/issues/417)
|
|
1655
|
+
* **ci:** stop discarding good translations when one page fails ([#388](https://github.com/bamr87/zer0-mistakes/issues/388)) ([19cea46](https://github.com/bamr87/zer0-mistakes/commit/19cea462a7822d6db536fc9c23218abd4a13d830))
|
|
1656
|
+
* **ci:** wait past the cold bundle install for Jekyll in the snapshot gate ([#426](https://github.com/bamr87/zer0-mistakes/issues/426)) ([de1d1ca](https://github.com/bamr87/zer0-mistakes/commit/de1d1ca426ce7a25d5a8548c4a696c0002877200))
|
|
1657
|
+
* **cookie-consent:** text-dark on bg-body made privacy rights invisible in dark mode ([#386](https://github.com/bamr87/zer0-mistakes/issues/386)) ([9bde7df](https://github.com/bamr87/zer0-mistakes/commit/9bde7dfa13f426908e00e53f8e4013a049fd928d))
|
|
1658
|
+
* **giscus:** comments were broken sitewide — add an end-to-end health check and correct the docs ([#378](https://github.com/bamr87/zer0-mistakes/issues/378)) ([45e222c](https://github.com/bamr87/zer0-mistakes/commit/45e222c3c2c5b7c507af4df2f5f0b48bc783801e))
|
|
1659
|
+
* **includes:** footer Info/Cookie Preferences are buttons, not anchors ([#427](https://github.com/bamr87/zer0-mistakes/issues/427)) ([f9041b9](https://github.com/bamr87/zer0-mistakes/commit/f9041b98b8a267be59f560724821fd941090f52d)), closes [#320](https://github.com/bamr87/zer0-mistakes/issues/320)
|
|
1660
|
+
* **layouts:** match section topic filters on whole tags, not substrings ([#420](https://github.com/bamr87/zer0-mistakes/issues/420)) ([338ad1d](https://github.com/bamr87/zer0-mistakes/commit/338ad1ddfb71c8d1dd9c48b36fb4634daf93f2de))
|
|
1661
|
+
* **layouts:** move keyboard focus to the skip-link target (tabindex="-1") ([#395](https://github.com/bamr87/zer0-mistakes/issues/395)) ([f5db650](https://github.com/bamr87/zer0-mistakes/commit/f5db65048e48ca71eedebc04d02d051e0b3152a6)), closes [#278](https://github.com/bamr87/zer0-mistakes/issues/278)
|
|
1662
|
+
* **layouts:** stop emitting dead sub-topic anchors in section sidebars ([#402](https://github.com/bamr87/zer0-mistakes/issues/402)) ([f50e790](https://github.com/bamr87/zer0-mistakes/commit/f50e790c4bfd56fefa4a74d7876de90c9776c689))
|
|
1663
|
+
* **layouts:** upgrade the no-js class to "js" so the hook works ([#428](https://github.com/bamr87/zer0-mistakes/issues/428)) ([a2d31f5](https://github.com/bamr87/zer0-mistakes/commit/a2d31f5533a4fb4793042e32326c1a78c9954268)), closes [#319](https://github.com/bamr87/zer0-mistakes/issues/319)
|
|
1664
|
+
* **navigation:** fit all nav items, full-bleed bar, language into Settings ([#423](https://github.com/bamr87/zer0-mistakes/issues/423)) ([689006e](https://github.com/bamr87/zer0-mistakes/commit/689006e7654e900a4509c30539fcf12bd7f397c6))
|
|
1665
|
+
* **scripts:** correct consumer auditor, plugin contract, and JSON-LD scope ([#400](https://github.com/bamr87/zer0-mistakes/issues/400)) ([b466cad](https://github.com/bamr87/zer0-mistakes/commit/b466cad526501e7e7a0eef5f24a12c5bbd181dc7))
|
|
1666
|
+
* **scripts:** recover from a rejected Anthropic credential, and link the cookbook ([#419](https://github.com/bamr87/zer0-mistakes/issues/419)) ([fac6bee](https://github.com/bamr87/zer0-mistakes/commit/fac6beeb7af7dcae96f727bf0cf581b080e95f15))
|
|
1667
|
+
* **ui-audit:** serve without --detach so the sweep can capture, and fail loudly when it cannot ([#434](https://github.com/bamr87/zer0-mistakes/issues/434)) ([fac6415](https://github.com/bamr87/zer0-mistakes/commit/fac641574c951b2887d94f8b39561fb8b6f8fe8c)), closes [#321](https://github.com/bamr87/zer0-mistakes/issues/321)
|
|
1668
|
+
|
|
1669
|
+
## [1.28.0](https://github.com/bamr87/zer0-mistakes/compare/v1.27.0...v1.28.0) (2026-08-09)
|
|
1670
|
+
|
|
1671
|
+
|
|
1672
|
+
### Features
|
|
1673
|
+
|
|
1674
|
+
* **books:** children's picture-book collection with immersive layouts and components ([#328](https://github.com/bamr87/zer0-mistakes/issues/328)) ([e059d1a](https://github.com/bamr87/zer0-mistakes/commit/e059d1afdc95073c5ce5bf9d1516b362979ad402))
|
|
1675
|
+
* **ci:** deploy the site via Actions so examples reach the live domain ([#353](https://github.com/bamr87/zer0-mistakes/issues/353)) ([959243c](https://github.com/bamr87/zer0-mistakes/commit/959243c0e8e504fe5d8dba44b89016b413bc88da))
|
|
1676
|
+
* **docs:** theme-canary reporting contract for downstream theme-scouts (FF-0019) ([#358](https://github.com/bamr87/zer0-mistakes/issues/358)) ([c1c1b30](https://github.com/bamr87/zer0-mistakes/commit/c1c1b309c5504b014602982fc96ec80c3f8f70de))
|
|
1677
|
+
* **examples:** add serialized reading-blog example site ([#339](https://github.com/bamr87/zer0-mistakes/issues/339)) ([aca0b53](https://github.com/bamr87/zer0-mistakes/commit/aca0b53b88067bda80fb299f9d5148ccb185d618))
|
|
1678
|
+
* **includes:** config-driven favicon, GTM gating, og:image fallback fix, sidebar nav aliases ([#327](https://github.com/bamr87/zer0-mistakes/issues/327)) ([fe8aacc](https://github.com/bamr87/zer0-mistakes/commit/fe8aacc234003f9f170fcb3b8b29c60ac18ed94b))
|
|
1679
|
+
* **install:** Claude Code OAuth + multi-provider AI + config-file layer ([#330](https://github.com/bamr87/zer0-mistakes/issues/330)) ([fde414c](https://github.com/bamr87/zer0-mistakes/commit/fde414cce5286f90de1ad02ca6ca40d634be5611))
|
|
1680
|
+
* **layouts:** book-abc board-book layout + ABC art-style skins ([#336](https://github.com/bamr87/zer0-mistakes/issues/336)) ([d88038e](https://github.com/bamr87/zer0-mistakes/commit/d88038e806e0d1a492e5d12b4e10e55fd240d692))
|
|
1681
|
+
* **navigation:** nav: pages sidebar mode — auto-build the tree from page URLs ([#333](https://github.com/bamr87/zer0-mistakes/issues/333)) ([c0c627d](https://github.com/bamr87/zer0-mistakes/commit/c0c627d5f50051e8f5eb4f0d6681244acaaa8d85))
|
|
1682
|
+
* **obsidian:** revamp graph frontend with Obsidian-style controls ([#366](https://github.com/bamr87/zer0-mistakes/issues/366)) ([7143d9c](https://github.com/bamr87/zer0-mistakes/commit/7143d9cd137408ad82981c9f9835204bab3a3db5))
|
|
1683
|
+
* **theme:** consumer-adoption hardening — mobile overlay fixes, zero-data resilience, extension hooks ([#338](https://github.com/bamr87/zer0-mistakes/issues/338)) ([84bcce1](https://github.com/bamr87/zer0-mistakes/commit/84bcce15e66b0bc312f513cef4a9dd11f972a049))
|
|
1684
|
+
|
|
1685
|
+
|
|
1686
|
+
### Bug Fixes
|
|
1687
|
+
|
|
1688
|
+
* **books:** pin abc-demo permalink so its cover lands at /books/abc-demo/ ([#345](https://github.com/bamr87/zer0-mistakes/issues/345)) ([943f463](https://github.com/bamr87/zer0-mistakes/commit/943f463c73081e7cc3d914c28a2ec2eea3d1b5ae))
|
|
1689
|
+
* **ci:** give the Dependabot label job an explicit GH_REPO ([#370](https://github.com/bamr87/zer0-mistakes/issues/370)) ([808b20e](https://github.com/bamr87/zer0-mistakes/commit/808b20ebbdcd5b0bc139b90947297cec6d226787))
|
|
1690
|
+
* **ci:** prefer CLAUDE_CODE_OAUTH_TOKEN over ANTHROPIC_API_KEY in all AI workflows ([#334](https://github.com/bamr87/zer0-mistakes/issues/334)) ([043848e](https://github.com/bamr87/zer0-mistakes/commit/043848eb84222240efc121e8112ddc12ab959a64))
|
|
1691
|
+
* **ci:** unbreak the production Pages build, frozen since 2026-08-05 ([#356](https://github.com/bamr87/zer0-mistakes/issues/356)) ([05465cf](https://github.com/bamr87/zer0-mistakes/commit/05465cfd5480a6bdfb0d164d56a892f2825ec1cf))
|
|
1692
|
+
* **i18n:** exclude admin config page from translation to unbreak Pages deploy ([#349](https://github.com/bamr87/zer0-mistakes/issues/349)) ([3f4890c](https://github.com/bamr87/zer0-mistakes/commit/3f4890cee3dd59b7f1cbc6ec235a863017b075fb))
|
|
1693
|
+
* **i18n:** normalise generated prose so translation runs keep CI green ([#342](https://github.com/bamr87/zer0-mistakes/issues/342)) ([70a7234](https://github.com/bamr87/zer0-mistakes/commit/70a723425b8cc6a77e1b845b212a8a7d127a7779))
|
|
1694
|
+
* **navigation:** mark only the current page active in the sidebar nav-tree ([#331](https://github.com/bamr87/zer0-mistakes/issues/331)) ([3f1b723](https://github.com/bamr87/zer0-mistakes/commit/3f1b723169258993d4530dd5817740e62734ccd4))
|
|
1695
|
+
* **sass:** restore mobile navigation in the example, collapsed to a 60px sliver ([#363](https://github.com/bamr87/zer0-mistakes/issues/363)) ([8c7d87a](https://github.com/bamr87/zer0-mistakes/commit/8c7d87af4fd476f06c16ce58ca4d4cd0e2c4169d))
|
|
1696
|
+
|
|
1691
1697
|
## [1.27.0](https://github.com/bamr87/zer0-mistakes/compare/v1.26.0...v1.27.0) (2026-07-22)
|
|
1692
1698
|
|
|
1693
1699
|
|