jekyll-theme-zer0 1.29.0 → 1.31.0

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.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +886 -2
  3. data/_data/README.md +2 -0
  4. data/_data/ai.yml +5 -3
  5. data/_data/ai_pricing.yml +36 -0
  6. data/_data/backlog.yml +196 -22
  7. data/_data/consumers.yml +147 -5
  8. data/_data/features.yml +147 -21
  9. data/_data/feedback_types.yml +17 -12
  10. data/_data/landing.yml +5 -2
  11. data/_data/navigation/quickstart.yml +4 -0
  12. data/_data/site_builder.yml +874 -0
  13. data/_data/theme-manifest.yml +132 -122
  14. data/_data/ui-text.yml +19 -0
  15. data/_includes/README.md +11 -1
  16. data/_includes/analytics/posthog.html +30 -11
  17. data/_includes/components/README.md +1 -1
  18. data/_includes/components/admin-links.html +2 -2
  19. data/_includes/components/admin-tabs.html +2 -2
  20. data/_includes/components/ai-chat.html +14 -11
  21. data/_includes/components/analytics-dashboard.html +8 -8
  22. data/_includes/components/author-bio.html +1 -1
  23. data/_includes/components/author-card.html +10 -2
  24. data/_includes/components/author-eeat.html +4 -4
  25. data/_includes/components/background-customizer.html +8 -8
  26. data/_includes/components/background-image.html +120 -0
  27. data/_includes/components/background-settings.html +28 -15
  28. data/_includes/components/collection-manager.html +5 -5
  29. data/_includes/components/component-showcase.html +13 -13
  30. data/_includes/components/config-editor.html +12 -12
  31. data/_includes/components/config-viewer.html +8 -8
  32. data/_includes/components/cookie-consent.html +41 -41
  33. data/_includes/components/cta-button.html +7 -2
  34. data/_includes/components/dev-shortcuts.html +7 -7
  35. data/_includes/components/env-dashboard.html +8 -8
  36. data/_includes/components/env-switcher.html +9 -9
  37. data/_includes/components/feature-card.html +2 -2
  38. data/_includes/components/halfmoon.html +2 -2
  39. data/_includes/components/info-section.html +36 -36
  40. data/_includes/components/js-cdn.html +15 -15
  41. data/_includes/components/language-toggle.html +4 -4
  42. data/_includes/components/mermaid.html +79 -435
  43. data/_includes/components/nanobar.html +5 -5
  44. data/_includes/components/nav-editor.html +2 -2
  45. data/_includes/components/nav-export.html +2 -2
  46. data/_includes/components/nav-overview.html +2 -2
  47. data/_includes/components/page-feedback.html +45 -30
  48. data/_includes/components/page-views-init.html +1 -1
  49. data/_includes/components/post-card.html +22 -22
  50. data/_includes/components/post-type-badge.html +2 -2
  51. data/_includes/components/powered-by.html +2 -2
  52. data/_includes/components/preview-image.html +28 -3
  53. data/_includes/components/quick-index.html +2 -2
  54. data/_includes/components/search-modal.html +27 -2
  55. data/_includes/components/searchbar.html +2 -2
  56. data/_includes/components/svg-background.html +2 -2
  57. data/_includes/components/theme-customizer.html +2 -2
  58. data/_includes/components/theme-info.html +6 -6
  59. data/_includes/components/theme-preview-gallery.html +23 -23
  60. data/_includes/content/giscus.html +2 -2
  61. data/_includes/content/intro.html +15 -8
  62. data/_includes/content/jsonld-faq.html +2 -2
  63. data/_includes/content/jsonld-software.html +2 -2
  64. data/_includes/content/seo.html +12 -4
  65. data/_includes/content/sitemap.html +247 -290
  66. data/_includes/content/toc.html +183 -183
  67. data/_includes/core/branding.html +13 -20
  68. data/_includes/core/console-capture.html +32 -74
  69. data/_includes/core/favicon.html +49 -7
  70. data/_includes/core/footer-fabs.html +17 -3
  71. data/_includes/core/footer.html +31 -18
  72. data/_includes/core/head.html +128 -92
  73. data/_includes/core/header.html +85 -54
  74. data/_includes/core/tokens-inline.html +16 -1
  75. data/_includes/docs/bootstrap-docs.html +8 -8
  76. data/_includes/landing/landing-install-cards.html +2 -2
  77. data/_includes/landing/landing-quick-links.html +1 -1
  78. data/_includes/navigation/admin-nav.html +2 -2
  79. data/_includes/navigation/nav-tree.html +8 -8
  80. data/_includes/navigation/navbar.html +21 -18
  81. data/_includes/navigation/section-sidebar.html +16 -16
  82. data/_includes/navigation/sidebar-config.html +36 -2
  83. data/_includes/navigation/sidebar-left.html +15 -15
  84. data/_includes/navigation/sidebar-right.html +6 -6
  85. data/_includes/obsidian/full-graph.html +2 -2
  86. data/_includes/setup/claude-session.html +72 -0
  87. data/_includes/setup/prereq-checklist.html +90 -0
  88. data/_includes/setup/wizard.html +910 -291
  89. data/_includes/stats/stats-categories.html +8 -8
  90. data/_includes/stats/stats-header.html +14 -14
  91. data/_includes/stats/stats-metrics.html +12 -12
  92. data/_includes/stats/stats-no-data.html +12 -12
  93. data/_includes/stats/stats-overview.html +6 -6
  94. data/_includes/stats/stats-tags.html +8 -8
  95. data/_layouts/404.html +38 -24
  96. data/_layouts/admin.html +22 -22
  97. data/_layouts/article.html +54 -37
  98. data/_layouts/author.html +20 -20
  99. data/_layouts/authors.html +2 -2
  100. data/_layouts/book-abc.html +12 -12
  101. data/_layouts/book-story.html +15 -15
  102. data/_layouts/book.html +12 -12
  103. data/_layouts/collection.html +33 -33
  104. data/_layouts/cookbook.html +12 -12
  105. data/_layouts/default.html +27 -24
  106. data/_layouts/home.html +36 -24
  107. data/_layouts/index.html +10 -10
  108. data/_layouts/landing.html +17 -17
  109. data/_layouts/news.html +44 -44
  110. data/_layouts/note.html +40 -39
  111. data/_layouts/notebook.html +36 -35
  112. data/_layouts/recipe.html +24 -24
  113. data/_layouts/root.html +95 -55
  114. data/_layouts/section.html +23 -23
  115. data/_layouts/setup.html +3 -3
  116. data/_layouts/sitemap-collection.html +49 -49
  117. data/_layouts/stats.html +40 -40
  118. data/_layouts/tag.html +12 -12
  119. data/_layouts/welcome.html +21 -21
  120. data/_sass/components/_cookie-banner.scss +48 -0
  121. data/_sass/components/_mermaid.scss +375 -0
  122. data/_sass/components/_setup-wizard.scss +588 -41
  123. data/_sass/components/_ui-enhancements.scss +11 -0
  124. data/_sass/core/_navbar.scss +147 -100
  125. data/_sass/core/_sidebar-extras.scss +2 -14
  126. data/_sass/core/code-copy.scss +27 -8
  127. data/_sass/layouts/_navbar-extras.scss +14 -4
  128. data/assets/css/extension-points-demo.css +27 -0
  129. data/assets/css/main.scss +1 -0
  130. data/assets/data/wiki-index.json +19 -0
  131. data/assets/js/ai-chat.js +47 -5
  132. data/assets/js/auto-hide-nav.js +53 -13
  133. data/assets/js/code-copy.js +72 -1
  134. data/assets/js/extension-points-demo.js +48 -0
  135. data/assets/js/fleet-feedback-capture.js +124 -0
  136. data/assets/js/fleet-feedback.js +853 -0
  137. data/assets/js/mermaid-diagrams.js +1373 -0
  138. data/assets/js/modules/navigation/config.js +9 -6
  139. data/assets/js/modules/navigation/scroll-spy.js +315 -80
  140. data/assets/js/modules/theme/appearance.js +8 -2
  141. data/assets/js/obsidian-local-graph.js +27 -5
  142. data/assets/js/obsidian-wiki-links.js +8 -3
  143. data/assets/js/page-feedback.js +125 -192
  144. data/assets/js/search-modal.js +26 -0
  145. data/assets/js/setup-wizard.js +2119 -363
  146. data/assets/js/site-builder.js +1834 -0
  147. data/assets/js/ui-enhancements.js +11 -3
  148. data/scripts/README.md +15 -0
  149. data/scripts/ai/README.md +38 -0
  150. data/scripts/ai/api_call.rb +124 -0
  151. data/scripts/ai/usage.rb +314 -0
  152. data/scripts/ai/usage_report.rb +225 -0
  153. data/scripts/ci/test_visual_evidence_autogen.py +403 -0
  154. data/scripts/ci/visual_evidence_autogen.py +1070 -0
  155. data/scripts/content-review.rb +20 -1
  156. data/scripts/features/install-preview-generator +1 -1
  157. data/scripts/lib/README.md +12 -0
  158. data/scripts/lib/preview_generator.py +2 -2
  159. data/scripts/test/integration/mermaid +22 -8
  160. data/scripts/test/lib/run_tests.sh +1 -0
  161. data/scripts/test/lib/test_visual_evidence_autogen.sh +24 -0
  162. data/scripts/translate.rb +23 -1
  163. metadata +21 -2
data/_data/README.md CHANGED
@@ -7,6 +7,8 @@ This directory contains YAML data files that power the Zer0-Mistakes Jekyll them
7
7
  | File | Purpose | Auto-Generated |
8
8
  |------|---------|----------------|
9
9
  | `navigation/` | Site navigation menus | No |
10
+ | `ai.yml` | The one place the AI model is configured (read by the hub's `bamr87/bamr87/.github/actions/claude-run@main` runner, consumed by reference) | No |
11
+ | `ai_pricing.yml` | API list prices used to *estimate* AI spend for calls that report tokens but no cost (part of the shared `ai-runner` kit) | No |
10
12
  | `authors.yml` | Author profile information | No |
11
13
  | `content_statistics.yml` | Site content analytics | **Yes** |
12
14
  | `roadmap.yml` | Single source of truth for the project roadmap (drives the README mermaid diagram and the `/roadmap/` Jekyll page) | No |
data/_data/ai.yml CHANGED
@@ -1,9 +1,11 @@
1
1
  # =============================================================================
2
2
  # _data/ai.yml — one place the AI model is configured for zer0-mistakes agents
3
3
  # -----------------------------------------------------------------------------
4
- # Read by .github/actions/claude-run (the issue-autopilot's AI step). Change the
5
- # model here and every autopilot agent call uses it. Auth is NOT here — it comes
6
- # from the CLAUDE_CODE_OAUTH_TOKEN (preferred) or ANTHROPIC_API_KEY secret.
4
+ # Read by the fleet's ai-runner kit — bamr87/bamr87/.github/actions/claude-run
5
+ # (consumed by reference; the issue-autopilot's AI step). Change the model
6
+ # here and every agent call uses it; AI_MODEL (or the action's `model` input)
7
+ # overrides it for one run. Auth is NOT here — it comes from the
8
+ # CLAUDE_CODE_OAUTH_TOKEN (preferred) or ANTHROPIC_API_KEY secret.
7
9
  # =============================================================================
8
10
  provider: anthropic
9
11
  model: claude-opus-4-8
@@ -0,0 +1,36 @@
1
+ # =============================================================================
2
+ # ai_pricing.yml — API list prices used to ESTIMATE AI spend (per million tokens)
3
+ # -----------------------------------------------------------------------------
4
+ # The telemetry layer (scripts/ai/usage.rb) prefers the cost the Claude Code CLI
5
+ # itself reports (`total_cost_usd`) — that number is authoritative and this file
6
+ # is never consulted for it. This table exists for the paths that report tokens
7
+ # but no dollars: the raw Claude API fallback (scripts/ai/api_call.rb) and any
8
+ # execution log that predates cost reporting. Those records get cost_source:
9
+ # "estimated", computed as
10
+ #
11
+ # input×in + output×out + cache_read×(0.1×in)
12
+ # + cache_write_5m×(1.25×in) + cache_write_1h×(2×in)
13
+ #
14
+ # which reproduces the CLI's own arithmetic to the cent (validated 2026-07-14
15
+ # against a live run). Prices are USD per MTok at standard API list rates —
16
+ # subscription (OAuth) runs have no marginal dollar cost, so every published
17
+ # figure is labeled "API-equivalent". Source: platform.claude.com/docs/en/pricing
18
+ # (cached 2026-07-14). Update this file when Anthropic changes list prices;
19
+ # estimates are marked as such everywhere they surface.
20
+ # =============================================================================
21
+ multipliers:
22
+ cache_read: 0.1 # × input price
23
+ cache_write_5m: 1.25 # × input price (5-minute TTL — the CLI default)
24
+ cache_write_1h: 2.0 # × input price (1-hour TTL)
25
+
26
+ # Matched by longest model-id prefix, so dated snapshots (claude-haiku-4-5-20251001)
27
+ # resolve to their family row. `default` catches unknown models (opus-tier, so an
28
+ # unknown model over- rather than under-estimates).
29
+ models:
30
+ claude-opus-4-8: { input: 5.00, output: 25.00 }
31
+ claude-opus-4-7: { input: 5.00, output: 25.00 }
32
+ claude-opus-4-6: { input: 5.00, output: 25.00 }
33
+ claude-sonnet-5: { input: 3.00, output: 15.00 }
34
+ claude-sonnet-4-6: { input: 3.00, output: 15.00 }
35
+ claude-haiku-4-5: { input: 1.00, output: 5.00 }
36
+ default: { input: 5.00, output: 25.00 }
data/_data/backlog.yml CHANGED
@@ -62,8 +62,8 @@
62
62
 
63
63
  meta:
64
64
  title: "zer0-mistakes Backlog"
65
- updated: 2026-08-18
66
- next_id: 46
65
+ updated: 2026-09-05
66
+ next_id: 52
67
67
 
68
68
  tasks:
69
69
  # --- Housekeeping (seeded so the loop has work on day one) ------------------
@@ -866,7 +866,7 @@ tasks:
866
866
 
867
867
  - id: T-033
868
868
  title: "Retire legacy test_installation.sh after equivalence audit against the installer harness"
869
- status: open
869
+ status: done
870
870
  priority: P2
871
871
  area: tests
872
872
  risk: standard
@@ -880,6 +880,10 @@ tasks:
880
880
  uncovered into test_install_*.sh, then delete the legacy suite and remove the
881
881
  `installation` routing from test_runner.sh, ci.yml, and nightly-extended.yml.
882
882
  Until then it runs nightly and on install-path PRs only (2026-07 CI tiering).
883
+ Done 2026-10-02: the suite is deleted, its scenarios live in
884
+ test_install_legacy_flags.sh (marked "Ported from retired
885
+ test_installation.sh"), test_runner.sh routes no `installation` suite, and
886
+ the CI/nightly suite lists no longer name it.
883
887
  acceptance:
884
888
  - "Every test_installation.sh scenario is mapped to a harness equivalent or ported."
885
889
  - "test_installation.sh deleted; test_runner.sh no longer routes an `installation` suite."
@@ -887,7 +891,7 @@ tasks:
887
891
  - "Nightly extended run green after removal."
888
892
  links: { issue: null, pr: null, roadmap: null }
889
893
  created: 2026-07-06
890
- updated: 2026-07-06
894
+ updated: 2026-10-02
891
895
  - id: T-034
892
896
  title: "Remove the dead preview_image_generator.rb Jekyll plugin and its test surface"
893
897
  status: done
@@ -951,7 +955,7 @@ tasks:
951
955
 
952
956
  - id: T-036
953
957
  title: "Remove hover transforms that cause pointer-edge flicker in the navbar"
954
- status: open
958
+ status: done
955
959
  priority: P1
956
960
  area: feat
957
961
  risk: standard
@@ -968,17 +972,38 @@ tasks:
968
972
  _sass/components/_ui-enhancements.scss and card hover styles for the same
969
973
  pattern.
970
974
  acceptance:
971
- - "No transform in any :hover rule under _sass/ (grep for translateY/scale in hover context returns nothing)."
972
- - "Pointer parked on the top edge of any nav item or utility button does not flicker."
975
+ # Scoped to the navbar per the issue's Option A. Criterion 1 was
976
+ # originally "no transform in any :hover rule under _sass/" — that is 42
977
+ # rules across ~15 files (card lifts, book tilts, recipe hovers) and a
978
+ # visual redesign of a published theme, not this defect. It also flagged
979
+ # `transform: none`, which is the CORRECTIVE pattern this repo already
980
+ # uses in _post-navigation.scss and the prefers-reduced-motion blocks.
981
+ # A theme-wide motion policy belongs in its own task.
982
+ # Stated as the COMPUTED value, not "no matching rule": these controls
983
+ # are `.btn`s and _ui-enhancements.scss's theme-wide
984
+ # `.btn:hover { translateY(-2px) }` still matches them and always will.
985
+ # It is overridden by `transform: none`, not deleted, so a rule-existence
986
+ # check would be permanently red. That inherited lift is why deleting the
987
+ # navbar's own translateY was not sufficient on its own.
988
+ - "getComputedStyle(control).transform is `none` while hovered, for every navbar control."
989
+ # Direction corrected: translateY(-1px) moves the element UP, so the row
990
+ # it stops covering is the BOTTOM one. A test parked on the top edge
991
+ # passes without exercising the bug.
992
+ - "Pointer parked on the bottom edge of any nav item or utility button does not flicker."
993
+ # Note: `#bdNavbar .nav-link:hover`, named in the summary as the primary
994
+ # cause, was dead code — its lift sits inside a container query that never
995
+ # matches at desktop widths (measured 1040/1140/1200/1280px on the built
996
+ # site, `none` at every one, on main too). The observable flicker was on
997
+ # the utility buttons and the FABs.
973
998
  - "regression test added"
974
999
  - "before/after evidence committed"
975
- links: { issue: null, pr: null, roadmap: null }
1000
+ links: { issue: 404, pr: null, roadmap: null }
976
1001
  created: 2026-08-18
977
- updated: 2026-08-18
1002
+ updated: 2026-09-03
978
1003
 
979
1004
  - id: T-037
980
1005
  title: "Navbar width recovery: two clean label tiers, merged chevron, centered grid, no subtitle"
981
- status: open
1006
+ status: done
982
1007
  priority: P2
983
1008
  area: feat
984
1009
  risk: standard
@@ -997,19 +1022,38 @@ tasks:
997
1022
  the navbar subtitle (_includes/core/branding.html — home hero only).
998
1023
  Clarify the three toggles: labeled "Menu" text button below lg, gear moves
999
1024
  into the unified drawer on mobile so only two toggles coexist.
1025
+ Done 2026-09-23: collapsed the three container-query tiers to two (icon+label
1026
+ >=51rem, icon-only below — the old 41-50.99rem bare-label tier and its
1027
+ text-overflow: ellipsis safety net are gone), merged the dropdown chevron
1028
+ into the parent link's hover row, gave the desktop grid's side tracks a
1029
+ shared floor (--zer0-navbar-side-min), moved site.subtitle to the home hero,
1030
+ and labeled the mobile menu toggle "Menu" (with aria-label mirroring the
1031
+ visible text for WCAG 2.5.3). `grid-template-columns: 1fr auto 1fr` as
1032
+ literally proposed breaks the container queries (track 2 must stay a
1033
+ definite 1fr for `.bd-navbar-nav-viewport`'s `width: 100%` to resolve) —
1034
+ used a shared side-track minimum instead; documented in-source. A prior
1035
+ attempt (#454) reached the same design but was closed as stale — its author
1036
+ had no Docker/Jekyll to run the Playwright suite or regenerate evidence.
1037
+ This finishes it against a real local build (bundle + jekyll build +
1038
+ Playwright), and additionally caught and fixed a collision the earlier
1039
+ attempt's tooling couldn't check: the new visible "Menu" text reused the
1040
+ already-defined `ui.menu_label` ("Toggle menu"), which would have shipped
1041
+ wrong text — added a dedicated `ui.nav_menu_toggle_label` key instead.
1042
+ 49/49 Playwright checks pass (37 existing navbar.spec.js + 12 new
1043
+ navbar-tiers.spec.js).
1000
1044
  acceptance:
1001
1045
  - "At 1024px and 1280px with 5 nav items every label is fully visible or the whole row is icon-only — no ellipses anywhere."
1002
1046
  - "Dropdown chevron shares the parent row's hover zone; no dead zone between link and chevron."
1003
1047
  - "Navbar carries logo + title only; subtitle appears on the home hero."
1004
1048
  - "regression test added"
1005
1049
  - "before/after evidence committed"
1006
- links: { issue: null, pr: null, roadmap: null }
1050
+ links: { issue: 405, pr: 495, roadmap: null }
1007
1051
  created: 2026-08-18
1008
1052
  updated: 2026-08-18
1009
1053
 
1010
1054
  - id: T-038
1011
1055
  title: "Language switcher: icon-only trigger and a compact, positive menu"
1012
- status: open
1056
+ status: done
1013
1057
  priority: P2
1014
1058
  area: feat
1015
1059
  risk: standard
@@ -1029,10 +1073,9 @@ tasks:
1029
1073
  - "Trigger is icon-only at all widths with an accessible name."
1030
1074
  - "regression test added"
1031
1075
  - "before/after evidence committed"
1032
- links: { issue: null, pr: null, roadmap: null }
1076
+ links: { issue: 406, pr: 431, roadmap: null }
1033
1077
  created: 2026-08-18
1034
- updated: 2026-08-18
1035
-
1078
+ updated: 2026-09-01
1036
1079
  - id: T-039
1037
1080
  title: "Eliminate page-transition layout shift (fixed-nav offset, scrollbar gutter, server-rendered slots)"
1038
1081
  status: open
@@ -1064,7 +1107,7 @@ tasks:
1064
1107
 
1065
1108
  - id: T-040
1066
1109
  title: "Setup wizard: live YAML preview, vertical stepper, draft persistence, stable panel height, inline validation"
1067
- status: open
1110
+ status: done
1068
1111
  priority: P2
1069
1112
  area: feat
1070
1113
  risk: standard
@@ -1087,10 +1130,9 @@ tasks:
1087
1130
  - "Reload mid-wizard restores the draft; invalid email/URL flagged on blur."
1088
1131
  - "regression test added"
1089
1132
  - "before/after evidence committed"
1090
- links: { issue: null, pr: null, roadmap: null }
1133
+ links: { issue: 408, pr: 432, roadmap: null }
1091
1134
  created: 2026-08-18
1092
- updated: 2026-08-18
1093
-
1135
+ updated: 2026-09-01
1094
1136
  - id: T-041
1095
1137
  title: "Admin layout: actions reachable on mobile, grouped sidebar, shared sticky offset, single heading"
1096
1138
  status: open
@@ -1216,7 +1258,7 @@ tasks:
1216
1258
 
1217
1259
  - id: T-045
1218
1260
  title: "Homepage snapshot baselines were regenerated without the 1967px drift being diagnosed"
1219
- status: open
1261
+ status: done
1220
1262
  priority: P2
1221
1263
  area: tests
1222
1264
  risk: low
@@ -1267,6 +1309,138 @@ tasks:
1267
1309
  - "Any genuinely time- or build-varying content inside the snapshot region is masked or stubbed, so the tier cannot drift again."
1268
1310
  - "No baseline PNG is regenerated as part of this work; any diff is diagnosed in the PR before it is blessed."
1269
1311
  - "The y626 band is explained, or recorded as unrecoverable with the reason. (Recorded: artifacts past 14-day retention.)"
1270
- links: { issue: 417, pr: null, roadmap: null }
1312
+ links: { issue: 417, pr: 425, roadmap: null }
1271
1313
  created: 2026-08-23
1272
- updated: 2026-08-25
1314
+ updated: 2026-09-01
1315
+
1316
+ - id: T-046
1317
+ title: "Retire the now-dead gotoBeforeScrollSpy fixture and cover the mobile offcanvas TOC spy"
1318
+ status: open
1319
+ priority: P3
1320
+ area: tests
1321
+ risk: low
1322
+ effort: S
1323
+ source: issue
1324
+ route: test-author
1325
+ summary: >-
1326
+ Discovered while fixing the TOC scroll spy: test/visual/fixtures.js
1327
+ exports gotoBeforeScrollSpy(), which strips data-bs-spy/data-bs-target
1328
+ from <body> before Bootstrap auto-initializes so its native ScrollSpy
1329
+ cannot clear server-rendered .active classes off admin sidebar links.
1330
+ That attribute no longer exists — _layouts/root.html dropped it (and
1331
+ _layouts/default.html dropped the second copy on .bd-main) so the theme's
1332
+ own scroll-spy.js is the single owner of .active on TOC links — which
1333
+ makes the fixture a no-op that still reads as load-bearing. Replace its
1334
+ call sites in test/visual/features/admin.spec.js with the plain
1335
+ waitForJekyll/gotoOrSkip helpers and delete it, keeping the admin
1336
+ active-link assertions that motivated it. While there, add the coverage
1337
+ test/visual/features/scroll-spy.spec.js deliberately left out: the mobile
1338
+ offcanvas TOC, where .offcanvas-body rather than .bd-toc is the scroll
1339
+ container the spy keeps the active link visible in.
1340
+ acceptance:
1341
+ - "gotoBeforeScrollSpy is removed from test/visual/fixtures.js and from its call sites; no spec references it."
1342
+ - "The admin specs that used it still pass, asserting the same server-rendered active nav links."
1343
+ - "A spec exercises the TOC scroll spy below the lg breakpoint with the offcanvas TOC open, asserting the active entry tracks scrolling and stays visible inside .offcanvas-body."
1344
+ - "npm run test:smoke is green."
1345
+ links: { issue: null, pr: null, roadmap: null }
1346
+ created: 2026-09-05
1347
+ updated: 2026-09-05
1348
+
1349
+ - id: T-047
1350
+ title: "pages/_docs/features/toc.md documents a TOC API the theme does not implement"
1351
+ status: open
1352
+ priority: P3
1353
+ area: docs
1354
+ risk: low
1355
+ effort: S
1356
+ source: issue
1357
+ route: content-reviewer
1358
+ summary: >-
1359
+ Discovered while correcting the scroll-spy sections of
1360
+ pages/_docs/features/toc.md: the page's Implementation and Configuration
1361
+ halves describe a table of contents this theme does not have. "TOC
1362
+ Generation" shows a Kramdown `{{ content | toc_only }}` snippet and a
1363
+ hand-rolled `page.content | split: '<h'` extractor, neither of which the
1364
+ theme uses — the real TOC comes from _includes/content/toc.html (the
1365
+ allejo/jekyll-toc parser) invoked by _includes/navigation/sidebar-right.html.
1366
+ "Enable TOC" documents front-matter keys that nothing reads; the
1367
+ `toc.min_level` / `toc.max_level` pair in the same section was already
1368
+ corrected (grep confirms no include, layout, plugin or _config.yml
1369
+ references either key). A reader following this page cannot reproduce the
1370
+ theme's behaviour. Rewrite the two sections against the actual include,
1371
+ its parameters, and the front-matter keys that really gate the panel.
1372
+ acceptance:
1373
+ - "Every Liquid snippet in toc.md matches an include the theme actually ships, verified by path."
1374
+ - "Front-matter keys documented on the page are read somewhere in _includes, _layouts, _plugins or _config.yml."
1375
+ - "scripts/content-review.rb still scores the page in the green band."
1376
+ - "Jekyll build with the layered dev configs is green and the page's anchors keep resolving."
1377
+
1378
+ - id: T-048
1379
+ title: "Site-level theme_color re-pins --zer0-color-primary over the active skin"
1380
+ status: done
1381
+ priority: P2
1382
+ area: feat
1383
+ risk: low
1384
+ effort: S
1385
+ source: issue
1386
+ summary: "Done 2026-10-02 (#459): the skin wins. tokens-inline.html emits theme_color main/blue/purple only when no palette skin is active, the precedence is documented in docs/ui/design-tokens.md, and appearance.spec.js asserts it. Discovered while making Mermaid diagrams follow the skin (ZER0-013 rework): the skin mixin (_sass/theme/_skins.scss) writes both --bs-primary and --zer0-color-primary under [data-theme-skin], but _includes/core/tokens-inline.html emits `:root { --zer0-color-primary: <theme_color.main> }` AFTER main.css, and :root ties [data-theme-skin] on specificity, so the later inline rule wins. Result on this site: buttons/links follow the skin (#6fa8dc on air, #8338ec on neon) while every custom component that reads --zer0-color-primary (callouts, code-block accent border, focus rings) stays on the config #007bff regardless of skin. Mermaid works around it by reading --bs-primary first; the token layer should agree with itself instead."
1387
+ acceptance:
1388
+ - "With theme_color.main set, switching skin changes --zer0-color-primary as well as --bs-primary (probe getComputedStyle on <html>)."
1389
+ - "Decide and document the precedence: skin over site theme_color (recommended) or the reverse — one rule, applied to every --zer0-color-* the mixin sets."
1390
+ - "A smoke test asserts --zer0-color-primary === --bs-primary after setSkin('neon')."
1391
+ - "before/after evidence committed"
1392
+ links: { issue: null, pr: null, roadmap: null }
1393
+ created: 2026-09-05
1394
+ updated: 2026-10-02
1395
+
1396
+ - id: T-049
1397
+ title: "test_core.sh: Liquid nested-tag check and gem-content check can never fail"
1398
+ status: open
1399
+ priority: P3
1400
+ area: tests
1401
+ risk: low
1402
+ effort: S
1403
+ source: audit
1404
+ summary: "Found while reviewing CI logs for PR #455: test/test_core.sh prints '[ERROR] Nested Liquid output tags found in _includes/navigation/sidebar-pagetree.html' on every run and still reports the Liquid validation as passed. Two defects: (1) the check is `grep -q \"{{.*{{\"`, which flags any line with two output tags — sidebar-pagetree.html:65 is `{{ _base }}{{ _section }}` inside a capture, valid Liquid — and the `return 1` sits inside a `find | while read` pipeline subshell, so it can never fail the function; (2) the gem-content check runs `tar -tzf` on the .gem, but a gem is an uncompressed tar (metadata.gz, data.tar.gz, checksums.yaml.gz), so gzip prints 'stdin: not in gzip format' four times and both branches always fall through to the 'Gem may not contain…' warnings without inspecting anything."
1405
+ acceptance:
1406
+ - "The nested-tag check only flags a genuinely nested output tag (e.g. `{{ a {{ b }} }}`), not two sibling tags on one line, and a positive match fails the test (no subshell swallowing the return)."
1407
+ - "The gem-content check lists data.tar.gz inside the .gem (`tar -xOf … data.tar.gz | tar -tzf -`) and asserts _layouts/ and assets/ are present; a gem missing them fails the test."
1408
+ - "./test/test_core.sh runs clean: no '[ERROR]' line on a passing run and no gzip/tar noise."
1409
+ links: { issue: null, pr: null, roadmap: null }
1410
+ created: 2026-09-05
1411
+ updated: 2026-09-05
1412
+
1413
+ - id: T-050
1414
+ title: "Visual Snapshots tier: LiveReload reloads the page mid-test because npm ci lands after Jekyll starts watching"
1415
+ status: open
1416
+ priority: P2
1417
+ area: tests
1418
+ risk: low
1419
+ effort: S
1420
+ source: audit
1421
+ summary: "The snapshots project shows a retried test on most CI runs — '[snapshots] › appearance-snapshot.spec.js › skin: <random> › homepage visual snapshot' fails with 'page.evaluate: Execution context was destroyed, most likely because of a navigation' and passes on retry (aqua on PR #455, mint on main 5ff38bf). Nothing on the homepage navigates; the likely trigger is Jekyll's LiveReload. test/update-snapshots.sh runs `docker compose up -d` (jekyll serve --watch --livereload, repo bind-mounted at /site) and only then starts the Playwright container, which runs `npm ci` into the same bind mount. jekyll-watch 2.2.1 registers an ignore pattern only for exclude paths that EXIST when serve starts (`next unless absolute_path.exist?` in listen_ignore_paths), and a fresh CI checkout has no node_modules/, so the thousands of files npm ci writes fire the watcher, the site regenerates, and LiveReload pushes a reload to every open page over localhost:35729 (reachable: the Playwright container uses --network host). Whichever skin is mid-step when the regeneration finishes fails; Playwright's CI retry (retries: 1) masks it, at the cost of one retry per run and a false 'flaky' signal that would hide a real regression."
1422
+ acceptance:
1423
+ - "Jekyll in the snapshot stack cannot reload the browser during a run: either node_modules/ exists before `docker compose up` (run `npm ci` first, or `mkdir -p node_modules`) or the test stack serves without --livereload (compose override or a JEKYLL_LIVERELOAD toggle)."
1424
+ - "Confirmed with the Playwright trace or `docker compose logs jekyll` showing no 'Regenerating' during a run."
1425
+ - "Ten consecutive CI runs of the snapshots project report 0 flaky tests."
1426
+ - "Root cause noted in the header of test/update-snapshots.sh so the ordering is not undone."
1427
+ links: { issue: null, pr: null, roadmap: null }
1428
+ created: 2026-09-05
1429
+ updated: 2026-09-05
1430
+
1431
+ - id: T-051
1432
+ title: "Preview-image engine: the xAI default model grok-2-image is retired — default to grok-imagine-image-2.0"
1433
+ status: open
1434
+ priority: P2
1435
+ area: infra
1436
+ risk: low
1437
+ effort: S
1438
+ source: issue
1439
+ summary: "Discovered while adding the xAI provider to the chat proxy and Site Builder (ZER0-087): scripts/lib/preview_generator.py's XAIProvider.default_model() still returns 'grok-2-image', which xAI has retired in favour of the Grok Imagine family (grok-imagine-image-2.0, per docs.x.ai release notes). A site with preview_images.provider: xai and no explicit model gets an upstream error. The Site Builder now writes preview_images.model explicitly for generated sites, so only the engine default (and the .env.example comment for IMAGE_MODEL) is stale. scripts/lib/ is CODEOWNERS-owned, so this is a human-review change."
1440
+ acceptance:
1441
+ - "XAIProvider.default_model() returns grok-imagine-image-2.0 and the provider table comment in the engine header matches."
1442
+ - "The image request keeps working with the current xAI response shape (data[0].url or b64_json)."
1443
+ - "scripts/lib/README.md / .env.example mention the new default."
1444
+ links: { issue: null, pr: null, roadmap: null }
1445
+ created: 2026-09-07
1446
+ updated: 2026-09-07
data/_data/consumers.yml CHANGED
@@ -44,6 +44,28 @@
44
44
  # version; tracked so a bump doesn't miss the config that
45
45
  # activates it
46
46
  # path_gem local path gem, unversioned (development only)
47
+ # gem_unconstrained `gem 'jekyll-theme-zer0'` with no version — resolves
48
+ # whatever RubyGems has at `bundle update` time; tracked
49
+ # only (like resolved_lockfile), never reports drift
50
+ #
51
+ # ------------------------------------------------------------------------------
52
+ # Stack fields (optional; informational — scripts/bin/propagate ignores them)
53
+ # ------------------------------------------------------------------------------
54
+ # How far each consumer is aligned with the zer0 stack (one theme, one image
55
+ # engine, one CMS — templates/consumer/README.md § The zer0 stack). A dated
56
+ # snapshot of each consumer's default branch, not a live reading: refresh it
57
+ # from `zer0-cms doctor <checkout>` (bamr87/zer0-CMS), never from memory.
58
+ #
59
+ # stack:
60
+ # checked date the default branch was read
61
+ # image_gem Gemfile requires zer0-image-generator
62
+ # preview_images _config.yml has a preview_images: block
63
+ # vendored_generator copies of the image engine the gem replaces
64
+ # (_plugins/preview_*.rb forks, scripts/lib/
65
+ # preview_generator.py, scripts/generate-preview-images.sh);
66
+ # a deliberate local generator is NOT listed
67
+ # zer0_json a zer0.json (zer0-CMS project file) is committed
68
+ # doctor .github/workflows/zer0-doctor.yml caller is committed
47
69
  # ==============================================================================
48
70
 
49
71
  version: 1
@@ -74,6 +96,16 @@ consumers:
74
96
  hook, enabled by `user_overrides: true`, not a shadow — and no fix
75
97
  numbered #338 could be substantiated in that repo. Keep this field
76
98
  derived from audit-consumer output, not hand-maintained estimates.
99
+ stack:
100
+ checked: "2026-09-14"
101
+ image_gem: true
102
+ preview_images: true
103
+ vendored_generator:
104
+ - _plugins/preview_image_generator.rb
105
+ - _plugins/preview_generator.rb
106
+ - scripts/lib/preview_generator.py
107
+ zer0_json: false
108
+ doctor: false
77
109
  pins:
78
110
  - file: _config.yml
79
111
  kind: remote_theme
@@ -87,6 +119,14 @@ consumers:
87
119
  risk: >-
88
120
  Unpinned, same exposure as it-journey. Small override surface (2 includes).
89
121
  Recommend pinning and joining the fan-out.
122
+ stack:
123
+ checked: "2026-09-14"
124
+ image_gem: true
125
+ preview_images: true
126
+ vendored_generator:
127
+ - scripts/generate-preview-images.sh
128
+ zer0_json: false
129
+ doctor: false
90
130
  pins:
91
131
  - file: _config.yml
92
132
  kind: remote_theme
@@ -103,6 +143,15 @@ consumers:
103
143
  Gemfile.azure + _config.azure.yml, and local dev mounts a path gem. A bump
104
144
  must move the remote_theme tag and the gem constraint together or the two
105
145
  production stacks render different theme versions.
146
+ stack:
147
+ checked: "2026-09-14"
148
+ image_gem: false
149
+ preview_images: true
150
+ vendored_generator:
151
+ - _plugins/preview_image_generator.rb
152
+ - scripts/generate-preview-images.sh
153
+ zer0_json: true
154
+ doctor: false
106
155
  pins:
107
156
  - file: _config.yml
108
157
  kind: remote_theme
@@ -117,6 +166,48 @@ consumers:
117
166
  kind: path_gem
118
167
  note: line 40 — dev checkout via ZER0_MISTAKES_PATH; never bumped
119
168
 
169
+ # ---------------------------------------------------------------------------
170
+ - repo: amr-bash/bash-365.com
171
+ mode: remote_theme_floating
172
+ site: https://bash-365.com
173
+ dispatch: false
174
+ note: >-
175
+ BASH Consulting's site, forked from bamr87/bashconsultants (which stays
176
+ registered above) and carrying the same three-stack shape: GitHub Pages
177
+ via remote_theme, Azure Static Web Apps via Gemfile.azure +
178
+ _config.azure.yml, local dev via a path gem. Unlike its parent, nothing
179
+ here carries a version any more — remote_theme is untagged and
180
+ Gemfile.azure names the gem with no constraint — so there is no pin for a
181
+ bump PR to rewrite. Declares its intentional forks in .theme-overrides.yml.
182
+ risk: >-
183
+ Unpinned on Pages; the Azure stack advances only when someone runs
184
+ `bundle update jekyll-theme-zer0`, so the two production stacks can
185
+ render different theme versions with nothing here to notice. Recommend
186
+ pinning remote_theme and constraining Gemfile.azure together and joining
187
+ the fan-out.
188
+ stack:
189
+ checked: "2026-09-14"
190
+ image_gem: false
191
+ preview_images: true
192
+ vendored_generator:
193
+ - _plugins/preview_image_generator.rb
194
+ - scripts/generate-preview-images.sh
195
+ zer0_json: true
196
+ doctor: false
197
+ pins:
198
+ - file: _config.yml
199
+ kind: remote_theme
200
+ note: line 33, no tag — floats main
201
+ - file: Gemfile.azure
202
+ kind: gem_unconstrained
203
+ note: line 10 — no version; `bundle update jekyll-theme-zer0` advances it
204
+ - file: _config.azure.yml
205
+ kind: theme_name
206
+ note: line 3 — activates the gem; no version of its own
207
+ - file: Gemfile
208
+ kind: path_gem
209
+ note: line 59 — dev checkout via ZER0_MISTAKES_PATH; never bumped
210
+
120
211
  # ---------------------------------------------------------------------------
121
212
  - repo: year-of-ai/year-of-ai.github.io
122
213
  mode: remote_theme_pinned
@@ -129,6 +220,14 @@ consumers:
129
220
  so one bump here re-rolls the whole org (12 sites). The hub's own
130
221
  _config.yml and hub.yml must move together — they are read by different
131
222
  code paths and drift silently otherwise.
223
+ stack:
224
+ checked: "2026-09-14"
225
+ image_gem: true
226
+ preview_images: true
227
+ vendored_generator:
228
+ - scripts/generate-preview-images.sh
229
+ zer0_json: false
230
+ doctor: false
132
231
  pins:
133
232
  - file: _config.yml
134
233
  kind: remote_theme
@@ -139,20 +238,35 @@ consumers:
139
238
 
140
239
  # ---------------------------------------------------------------------------
141
240
  - repo: ai-world-view/ai-world-view.github.io
142
- mode: remote_theme_pinned
241
+ mode: remote_theme_floating
143
242
  site: https://ai-world-view.github.io
144
- dispatch: true
243
+ dispatch: false
145
244
  fans_out_to_members: true
146
245
  note: >-
147
246
  Same two-file hub shape as year-of-ai; members join by auto_discover, so
148
- the member count grows without this file changing.
247
+ the member count grows without this file changing. Was registered as
248
+ remote_theme_pinned until the 2026-09 fleet harmonization, but both its
249
+ _config.yml remote_theme and its hub.yml theme_repo carry NO tag — the
250
+ hub and every member it stamps float on this theme's main.
251
+ risk: >-
252
+ Unpinned, and an org hub: a theme break here reaches every auto-discovered
253
+ member site at once. Recommend pinning both files together and joining
254
+ the fan-out (dispatch: true) like year-of-ai.
255
+ stack:
256
+ checked: "2026-09-14"
257
+ image_gem: true
258
+ preview_images: true
259
+ vendored_generator:
260
+ - scripts/generate-preview-images.sh
261
+ zer0_json: false
262
+ doctor: false
149
263
  pins:
150
264
  - file: _config.yml
151
265
  kind: remote_theme
152
- note: line 35
266
+ note: line 36, no tag — floats main
153
267
  - file: _data/hub.yml
154
268
  kind: hub_registry
155
- note: "line 39 (pages.theme_repo) — re-roll members after bumping"
269
+ note: "line 39 (pages.theme_repo), no tag — members float too"
156
270
 
157
271
  # ---------------------------------------------------------------------------
158
272
  # The four entries below were missing entirely until the 2026-08 fleet audit.
@@ -177,6 +291,13 @@ consumers:
177
291
  Gemfile.lock resolved 1.25.0 while the Gemfile constraint (~> 1.25)
178
292
  already permitted 1.28.0 — stale purely because nothing was nudging it.
179
293
  Keeps two deliberate include forks, declared in its .theme-overrides.yml.
294
+ stack:
295
+ checked: "2026-09-14"
296
+ image_gem: true
297
+ preview_images: true
298
+ vendored_generator: []
299
+ zer0_json: false
300
+ doctor: false
180
301
  pins:
181
302
  - file: Gemfile
182
303
  kind: gem_constraint
@@ -203,6 +324,13 @@ consumers:
203
324
  Unpinned, and with no local preview path a contributor cannot see a theme
204
325
  break before pushing. Keeps three deliberate overrides, declared in its
205
326
  .theme-overrides.yml.
327
+ stack:
328
+ checked: "2026-09-14"
329
+ image_gem: false
330
+ preview_images: false
331
+ vendored_generator: []
332
+ zer0_json: false
333
+ doctor: false
206
334
  pins:
207
335
  - file: _config.yml
208
336
  kind: remote_theme
@@ -221,6 +349,13 @@ consumers:
221
349
  risk: >-
222
350
  Unpinned, and its only build runs on push to main (jekyll-gh-pages.yml),
223
351
  so a break ships before anyone sees it.
352
+ stack:
353
+ checked: "2026-09-14"
354
+ image_gem: false
355
+ preview_images: false
356
+ vendored_generator: []
357
+ zer0_json: false
358
+ doctor: false
224
359
  pins:
225
360
  - file: _config.yml
226
361
  kind: remote_theme
@@ -246,6 +381,13 @@ consumers:
246
381
  "unreachable" rather than reading its pin — drift reporting needs a token
247
382
  here even though it is read-only. CI already supplies one; a bare local
248
383
  run will not.
384
+ stack:
385
+ checked: "2026-09-14"
386
+ image_gem: false
387
+ preview_images: false
388
+ vendored_generator: []
389
+ zer0_json: false
390
+ doctor: false
249
391
  pins:
250
392
  - file: _config.yml
251
393
  kind: remote_theme