hyperweave 0.3.6__tar.gz → 0.3.7__tar.gz

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 (425) hide show
  1. {hyperweave-0.3.6 → hyperweave-0.3.7}/CHANGELOG.md +21 -0
  2. {hyperweave-0.3.6 → hyperweave-0.3.7}/PKG-INFO +33 -18
  3. {hyperweave-0.3.6 → hyperweave-0.3.7}/README.md +30 -17
  4. {hyperweave-0.3.6 → hyperweave-0.3.7}/pyproject.toml +7 -2
  5. {hyperweave-0.3.6 → hyperweave-0.3.7}/scripts/generate_proofset.py +12 -0
  6. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/_version.py +2 -2
  7. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/assembler.py +39 -53
  8. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/context.py +177 -24
  9. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/validate_paradigms.py +99 -0
  10. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/config/loader.py +46 -0
  11. hyperweave-0.3.7/src/hyperweave/data/font-embedding.yaml +75 -0
  12. hyperweave-0.3.7/src/hyperweave/render/fonts.py +126 -0
  13. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_chart_frame.py +5 -3
  14. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_font_gating.py +68 -8
  15. hyperweave-0.3.7/tests/test_font_subsetting.py +240 -0
  16. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_paradigm_cellular.py +43 -14
  17. hyperweave-0.3.6/src/hyperweave/render/fonts.py +0 -48
  18. {hyperweave-0.3.6 → hyperweave-0.3.7}/.dockerignore +0 -0
  19. {hyperweave-0.3.6 → hyperweave-0.3.7}/.github/workflows/ci.yml +0 -0
  20. {hyperweave-0.3.6 → hyperweave-0.3.7}/.github/workflows/deploy.yml +0 -0
  21. {hyperweave-0.3.6 → hyperweave-0.3.7}/.github/workflows/publish.yml +0 -0
  22. {hyperweave-0.3.6 → hyperweave-0.3.7}/.gitignore +0 -0
  23. {hyperweave-0.3.6 → hyperweave-0.3.7}/.pre-commit-config.yaml +0 -0
  24. {hyperweave-0.3.6 → hyperweave-0.3.7}/Dockerfile +0 -0
  25. {hyperweave-0.3.6 → hyperweave-0.3.7}/LICENSE +0 -0
  26. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/buttons/button-liquid.svg +0 -0
  27. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/cards/card-butterfly.svg +0 -0
  28. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/cards/card-python.svg +0 -0
  29. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/cards/card-sunflower.svg +0 -0
  30. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/cards/card-waves.svg +0 -0
  31. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/badge_critical.svg +0 -0
  32. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/badge_passing.svg +0 -0
  33. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/badge_warning.svg +0 -0
  34. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/banner.svg +0 -0
  35. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/icons/discord.svg +0 -0
  36. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/icons/notion.svg +0 -0
  37. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/icons/reddit.svg +0 -0
  38. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/icons/spotify.svg +0 -0
  39. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/icons/youtube.svg +0 -0
  40. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/marquee_counter.svg +0 -0
  41. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/marquee_horizontal.svg +0 -0
  42. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/marquee_vertical.svg +0 -0
  43. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/profile-cards/chart_stars_full.svg +0 -0
  44. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/profile-cards/stats.svg +0 -0
  45. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/brutalist-emerald/strip.svg +0 -0
  46. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/badge_critical.svg +0 -0
  47. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/badge_passing.svg +0 -0
  48. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/badge_warning.svg +0 -0
  49. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/banner.svg +0 -0
  50. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/icons/bluesky.svg +0 -0
  51. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/icons/github.svg +0 -0
  52. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/icons/instagram.svg +0 -0
  53. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/icons/mastodon.svg +0 -0
  54. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/icons/x.svg +0 -0
  55. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/marquee_counter.svg +0 -0
  56. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/marquee_horizontal.svg +0 -0
  57. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/marquee_vertical.svg +0 -0
  58. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/profile-cards/chart_stars_full.svg +0 -0
  59. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/profile-cards/stats.svg +0 -0
  60. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/chrome-horizon/strip.svg +0 -0
  61. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/telemetry/master_card.svg +0 -0
  62. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/telemetry/receipt.svg +0 -0
  63. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/telemetry/receipt_claude-code_medium.svg +0 -0
  64. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/telemetry/receipt_codex_large.svg +0 -0
  65. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/telemetry/receipt_voltage_xlarge.svg +0 -0
  66. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/telemetry/rhythm_strip.svg +0 -0
  67. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/examples/telemetry/rhythm_strip_voltage_xlarge.svg +0 -0
  68. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/footers/inneraura-footer-liquid.svg +0 -0
  69. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/footers/inneraura-footer-purple.svg +0 -0
  70. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/footers/inneraura-footer.svg +0 -0
  71. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/hyperweave-banner.svg +0 -0
  72. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/icons/cobalt-sapphire-discord.svg +0 -0
  73. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/icons/cobalt-sapphire-docs.svg +0 -0
  74. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/icons/cobalt-sapphire-github.svg +0 -0
  75. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/icons/cobalt-sapphire-instagram.svg +0 -0
  76. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/icons/cobalt-sapphire-linkedin.svg +0 -0
  77. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/icons/cobalt-sapphire-tiktok.svg +0 -0
  78. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/icons/cobalt-sapphire-x.svg +0 -0
  79. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/icons/cobalt-sapphire-youtube.svg +0 -0
  80. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/marquees/badge-showcase-triple.svg +0 -0
  81. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/marquees/genome-marquee-triple.svg +0 -0
  82. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/marquees/sample-badges.svg +0 -0
  83. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/mintlify-assets/404.svg +0 -0
  84. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/mintlify-assets/callout-icons.svg +0 -0
  85. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/mintlify-assets/divider.svg +0 -0
  86. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/mintlify-assets/favicon.svg +0 -0
  87. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/mintlify-assets/hero-banner.svg +0 -0
  88. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/mintlify-assets/hyperweave-banner-v2.svg +0 -0
  89. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/mintlify-assets/hyperweave-navbar-logo.svg +0 -0
  90. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/mintlify-assets/loader.svg +0 -0
  91. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/mintlify-assets/og-image.svg +0 -0
  92. {hyperweave-0.3.6 → hyperweave-0.3.7}/assets/timelines/hyperweave-roadmap.svg +0 -0
  93. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/assets/favicon.svg +0 -0
  94. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/assets/hyperweave-banner.svg +0 -0
  95. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/assets/hyperweave-navbar-logo.svg +0 -0
  96. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/assets/og-image.svg +0 -0
  97. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/explanation/architecture.mdx +0 -0
  98. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/explanation/camo-compatibility.mdx +0 -0
  99. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/explanation/cim-compliance.mdx +0 -0
  100. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/explanation/genome-profile-system.mdx +0 -0
  101. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/explanation/metadata-tiers.mdx +0 -0
  102. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/how-to/add-motion-to-badges.mdx +0 -0
  103. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/how-to/create-session-receipts.mdx +0 -0
  104. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/how-to/set-up-claude-code-hooks.mdx +0 -0
  105. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/how-to/use-live-data-badges.mdx +0 -0
  106. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/introduction.mdx +0 -0
  107. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/mint.json +0 -0
  108. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/quickstart.mdx +0 -0
  109. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/reference/cli.mdx +0 -0
  110. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/reference/compose-spec.mdx +0 -0
  111. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/reference/genomes.mdx +0 -0
  112. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/reference/http-api.mdx +0 -0
  113. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/reference/mcp-tools.mdx +0 -0
  114. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/reference/motions.mdx +0 -0
  115. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/reference/telemetry-contract.mdx +0 -0
  116. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/spec/hyperweave-protocol.mdx +0 -0
  117. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/tutorials/build-an-artifact-kit.mdx +0 -0
  118. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/tutorials/compose-your-first-badge.mdx +0 -0
  119. {hyperweave-0.3.6 → hyperweave-0.3.7}/docs/tutorials/install-session-telemetry.mdx +0 -0
  120. {hyperweave-0.3.6 → hyperweave-0.3.7}/fly.toml +0 -0
  121. {hyperweave-0.3.6 → hyperweave-0.3.7}/hooks/install.py +0 -0
  122. {hyperweave-0.3.6 → hyperweave-0.3.7}/hooks/session_end.sh +0 -0
  123. {hyperweave-0.3.6 → hyperweave-0.3.7}/justfile +0 -0
  124. {hyperweave-0.3.6 → hyperweave-0.3.7}/scripts/extract_font_metrics.py +0 -0
  125. {hyperweave-0.3.6 → hyperweave-0.3.7}/scripts/extract_glyphs.py +0 -0
  126. {hyperweave-0.3.6 → hyperweave-0.3.7}/scripts/probe_live_stats.py +0 -0
  127. {hyperweave-0.3.6 → hyperweave-0.3.7}/scripts/probe_star_history.py +0 -0
  128. {hyperweave-0.3.6 → hyperweave-0.3.7}/scripts/stress_test.py +0 -0
  129. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/__init__.py +0 -0
  130. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/__main__.py +0 -0
  131. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/cli.py +0 -0
  132. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/__init__.py +0 -0
  133. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/bar_chart.py +0 -0
  134. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/engine.py +0 -0
  135. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/lanes.py +0 -0
  136. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/layout.py +0 -0
  137. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/palette.py +0 -0
  138. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/reasoning.py +0 -0
  139. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/resolver.py +0 -0
  140. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/resolvers/__init__.py +0 -0
  141. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/resolvers/chart.py +0 -0
  142. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/resolvers/stats.py +0 -0
  143. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/rhythm.py +0 -0
  144. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/rhythm_strip.py +0 -0
  145. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/compose/treemap.py +0 -0
  146. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/config/__init__.py +0 -0
  147. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/config/genome_validator.py +0 -0
  148. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/config/registry.py +0 -0
  149. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/config/settings.py +0 -0
  150. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/connectors/__init__.py +0 -0
  151. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/connectors/arxiv.py +0 -0
  152. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/connectors/base.py +0 -0
  153. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/connectors/cache.py +0 -0
  154. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/connectors/github.py +0 -0
  155. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/connectors/rest.py +0 -0
  156. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/__init__.py +0 -0
  157. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/cell_layout.py +0 -0
  158. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/color.py +0 -0
  159. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/contracts.py +0 -0
  160. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/enums.py +0 -0
  161. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/font_metrics.py +0 -0
  162. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/models.py +0 -0
  163. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/paradigm.py +0 -0
  164. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/schema.py +0 -0
  165. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/state.py +0 -0
  166. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/text.py +0 -0
  167. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/core/thresholds.py +0 -0
  168. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/badge_modes.yaml +0 -0
  169. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/css/accessibility.css +0 -0
  170. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/css/bridge.css +0 -0
  171. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/css/expression.css +0 -0
  172. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/css/status.css +0 -0
  173. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/font-metrics/chakra-petch.json +0 -0
  174. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/font-metrics/inter.json +0 -0
  175. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/font-metrics/jetbrains-mono.json +0 -0
  176. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/font-metrics/orbitron.json +0 -0
  177. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/barlow-condensed-700.b64 +0 -0
  178. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/barlow-condensed-700.meta.json +0 -0
  179. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/barlow-condensed-900.b64 +0 -0
  180. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/barlow-condensed-900.meta.json +0 -0
  181. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/chakra-petch.b64 +0 -0
  182. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/chakra-petch.meta.json +0 -0
  183. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/jetbrains-mono.b64 +0 -0
  184. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/jetbrains-mono.meta.json +0 -0
  185. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/orbitron.b64 +0 -0
  186. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/fonts/orbitron.meta.json +0 -0
  187. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/genomes/automata.json +0 -0
  188. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/genomes/brutalist.json +0 -0
  189. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/genomes/chrome.json +0 -0
  190. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/genomes/telemetry-claude-code.json +0 -0
  191. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/genomes/telemetry-codex.json +0 -0
  192. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/genomes/telemetry-cream.json +0 -0
  193. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/genomes/telemetry-voltage.json +0 -0
  194. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/glyphs.json +0 -0
  195. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/motions/border/chromatic-pulse.yaml +0 -0
  196. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/motions/border/corner-trace.yaml +0 -0
  197. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/motions/border/dual-orbit.yaml +0 -0
  198. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/motions/border/entanglement.yaml +0 -0
  199. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/motions/border/rimrun.yaml +0 -0
  200. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/motions/static.yaml +0 -0
  201. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/paradigms/brutalist.yaml +0 -0
  202. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/paradigms/cellular.yaml +0 -0
  203. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/paradigms/chrome.yaml +0 -0
  204. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/paradigms/default.yaml +0 -0
  205. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/policies/normal.json +0 -0
  206. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/policies/permissive.json +0 -0
  207. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/policies/ungoverned.json +0 -0
  208. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/profiles/brutalist.contract.json +0 -0
  209. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/profiles/brutalist.yaml +0 -0
  210. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/profiles/chrome.contract.json +0 -0
  211. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/profiles/chrome.yaml +0 -0
  212. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/reasoning/__init__.py +0 -0
  213. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/reasoning/brutalist.yaml +0 -0
  214. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/specimens.yaml +0 -0
  215. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/telemetry/model-pricing.yaml +0 -0
  216. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/telemetry/runtimes/claude-code.yaml +0 -0
  217. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/telemetry/runtimes/codex.yaml +0 -0
  218. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/telemetry/stage-config.yaml +0 -0
  219. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/telemetry/stage-labels.yaml +0 -0
  220. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/telemetry/tool-colors.yaml +0 -0
  221. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/arrow.json +0 -0
  222. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/aurora.json +0 -0
  223. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/beacon.json +0 -0
  224. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/bracket3d.json +0 -0
  225. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/chevron.json +0 -0
  226. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/crosshair.json +0 -0
  227. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/diamond.json +0 -0
  228. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/rocket.json +0 -0
  229. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/rules/bar.json +0 -0
  230. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/rules/dashed.json +0 -0
  231. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/rules/five-wave.json +0 -0
  232. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/rules/spectral.json +0 -0
  233. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/rules/straight.json +0 -0
  234. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/rules/wave.json +0 -0
  235. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/data/terminals/stijl.json +0 -0
  236. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/kit.py +0 -0
  237. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/mcp/__init__.py +0 -0
  238. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/mcp/__main__.py +0 -0
  239. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/mcp/server.py +0 -0
  240. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/py.typed +0 -0
  241. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/render/__init__.py +0 -0
  242. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/render/chart_engine.py +0 -0
  243. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/render/glyphs.py +0 -0
  244. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/render/motion.py +0 -0
  245. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/render/templates.py +0 -0
  246. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/serve/__init__.py +0 -0
  247. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/serve/app.py +0 -0
  248. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/serve/data_tokens.py +0 -0
  249. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/__init__.py +0 -0
  250. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/capture.py +0 -0
  251. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/codex_parser.py +0 -0
  252. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/contract.py +0 -0
  253. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/corrections.py +0 -0
  254. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/cost.py +0 -0
  255. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/models.py +0 -0
  256. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/parser.py +0 -0
  257. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/receipt_paths.py +0 -0
  258. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/runtimes.py +0 -0
  259. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/telemetry/stages.py +0 -0
  260. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-area.svg.j2 +0 -0
  261. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-axes.svg.j2 +0 -0
  262. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-empty-state.svg.j2 +0 -0
  263. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-gridlines.svg.j2 +0 -0
  264. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-markers/circle.svg.j2 +0 -0
  265. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-markers/diamond.svg.j2 +0 -0
  266. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-markers/endpoint-diamond.svg.j2 +0 -0
  267. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-markers/endpoint-rect.svg.j2 +0 -0
  268. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-markers/rect.svg.j2 +0 -0
  269. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-milestone-brutalist.svg.j2 +0 -0
  270. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-milestone.svg.j2 +0 -0
  271. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/chart-polyline.svg.j2 +0 -0
  272. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/filter.svg.j2 +0 -0
  273. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/glyph-inline.svg.j2 +0 -0
  274. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/glyph.svg.j2 +0 -0
  275. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/gradient.svg.j2 +0 -0
  276. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/metadata.svg.j2 +0 -0
  277. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/metric.svg.j2 +0 -0
  278. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/phase-segment.svg.j2 +0 -0
  279. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/rule.svg.j2 +0 -0
  280. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/status.svg.j2 +0 -0
  281. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/components/terminal.svg.j2 +0 -0
  282. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/document.svg.j2 +0 -0
  283. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/error-badge.svg.j2 +0 -0
  284. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/brutalist-content.j2 +0 -0
  285. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/brutalist-dark-content.j2 +0 -0
  286. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/brutalist-defs.j2 +0 -0
  287. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/brutalist-light-content.j2 +0 -0
  288. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/cellular-content.j2 +0 -0
  289. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/cellular-defs.j2 +0 -0
  290. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/chrome-content.j2 +0 -0
  291. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/chrome-defs.j2 +0 -0
  292. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/default-content.j2 +0 -0
  293. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge/default-defs.j2 +0 -0
  294. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/badge.svg.j2 +0 -0
  295. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/catalog.svg.j2 +0 -0
  296. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/chart/brutalist-content.j2 +0 -0
  297. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/chart/brutalist-dark-content.j2 +0 -0
  298. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/chart/brutalist-defs.j2 +0 -0
  299. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/chart/brutalist-light-content.j2 +0 -0
  300. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/chart/cellular-content.j2 +0 -0
  301. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/chart/cellular-defs.j2 +0 -0
  302. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/chart/chrome-content.j2 +0 -0
  303. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/chart/chrome-defs.j2 +0 -0
  304. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/chart.svg.j2 +0 -0
  305. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/divider/brutalist-seam.svg.j2 +0 -0
  306. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/divider/chrome-band.svg.j2 +0 -0
  307. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/divider.svg.j2 +0 -0
  308. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/icon/brutalist-content.j2 +0 -0
  309. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/icon/brutalist-defs.j2 +0 -0
  310. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/icon/cellular-content.j2 +0 -0
  311. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/icon/cellular-defs.j2 +0 -0
  312. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/icon/chrome-content.j2 +0 -0
  313. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/icon/chrome-defs.j2 +0 -0
  314. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/icon/default-content.j2 +0 -0
  315. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/icon/default-defs.j2 +0 -0
  316. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/icon.svg.j2 +0 -0
  317. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-content.j2 +0 -0
  318. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-defs.j2 +0 -0
  319. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-overlay.j2 +0 -0
  320. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/cellular-content.j2 +0 -0
  321. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/cellular-defs.j2 +0 -0
  322. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/cellular-overlay.j2 +0 -0
  323. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/chrome-content.j2 +0 -0
  324. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/chrome-defs.j2 +0 -0
  325. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/chrome-overlay.j2 +0 -0
  326. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/default-content.j2 +0 -0
  327. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal/default-defs.j2 +0 -0
  328. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/marquee-horizontal.svg.j2 +0 -0
  329. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/master-card.svg.j2 +0 -0
  330. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/receipt.svg.j2 +0 -0
  331. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/rhythm-strip.svg.j2 +0 -0
  332. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/stats/brutalist-content.j2 +0 -0
  333. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/stats/brutalist-dark-content.j2 +0 -0
  334. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/stats/brutalist-defs.j2 +0 -0
  335. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/stats/brutalist-light-content.j2 +0 -0
  336. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/stats/cellular-content.j2 +0 -0
  337. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/stats/cellular-defs.j2 +0 -0
  338. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/stats/chrome-content.j2 +0 -0
  339. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/stats/chrome-defs.j2 +0 -0
  340. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/stats.svg.j2 +0 -0
  341. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/brutalist-content.j2 +0 -0
  342. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/brutalist-dark-content.j2 +0 -0
  343. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/brutalist-defs.j2 +0 -0
  344. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/brutalist-light-content.j2 +0 -0
  345. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/brutalist-status.j2 +0 -0
  346. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/cellular-content.j2 +0 -0
  347. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/cellular-defs.j2 +0 -0
  348. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/cellular-status.j2 +0 -0
  349. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/chrome-content.j2 +0 -0
  350. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/chrome-defs.j2 +0 -0
  351. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/chrome-status.j2 +0 -0
  352. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/default-content.j2 +0 -0
  353. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/default-defs.j2 +0 -0
  354. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip/default-status.j2 +0 -0
  355. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/frames/strip.svg.j2 +0 -0
  356. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/motions/border/chromatic-pulse.svg.j2 +0 -0
  357. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/motions/border/corner-trace.svg.j2 +0 -0
  358. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/motions/border/dual-orbit.svg.j2 +0 -0
  359. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/motions/border/entanglement.svg.j2 +0 -0
  360. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/motions/border/rimrun.svg.j2 +0 -0
  361. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/partials/provider-glyphs.svg.j2 +0 -0
  362. {hyperweave-0.3.6 → hyperweave-0.3.7}/src/hyperweave/templates/partials/state-signal-cascade.j2 +0 -0
  363. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/__init__.py +0 -0
  364. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/conftest.py +0 -0
  365. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/fixtures/codex_session.jsonl +0 -0
  366. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/fixtures/codex_session_patches.jsonl +0 -0
  367. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/fixtures/github_contributions/synthetic.html +0 -0
  368. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/fixtures/session.json +0 -0
  369. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/fixtures/session.jsonl +0 -0
  370. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/fixtures/synthetic_session.jsonl +0 -0
  371. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/helpers.py +0 -0
  372. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/snapshots/url_stability/divider_band_chrome_static.svg +0 -0
  373. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/snapshots/url_stability/icon_github_chrome_static.svg +0 -0
  374. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_assembler.py +0 -0
  375. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_badge_brutalist_dark.py +0 -0
  376. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_badge_cellular.py +0 -0
  377. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_badge_layout.py +0 -0
  378. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_badge_mode.py +0 -0
  379. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_chart_engine.py +0 -0
  380. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_chromatic_coverage_validator.py +0 -0
  381. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_chrome_variants.py +0 -0
  382. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_codex_parser.py +0 -0
  383. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_compose_bar_chart.py +0 -0
  384. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_compose_rhythm_strip.py +0 -0
  385. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_compose_treemap.py +0 -0
  386. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_compose_variant_field.py +0 -0
  387. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_connectors.py +0 -0
  388. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_core.py +0 -0
  389. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_data_tokens.py +0 -0
  390. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_divider_cellular.py +0 -0
  391. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_divider_genome_specific.py +0 -0
  392. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_doctor.py +0 -0
  393. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_font_metrics_chakra.py +0 -0
  394. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_genome_automata.py +0 -0
  395. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_github_scrape.py +0 -0
  396. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_install_hook.py +0 -0
  397. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_kit.py +0 -0
  398. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_marquee_v0_2_16.py +0 -0
  399. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_mcp.py +0 -0
  400. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_paradigm_dispatch.py +0 -0
  401. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_paradigm_extensibility.py +0 -0
  402. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_parse_transcript_auto.py +0 -0
  403. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_proofset.py +0 -0
  404. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_receipt_paths.py +0 -0
  405. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_receipt_token_compliance.py +0 -0
  406. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_render.py +0 -0
  407. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_resolver_rhythm.py +0 -0
  408. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_runtime_registries.py +0 -0
  409. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_serve.py +0 -0
  410. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_serve_live_state.py +0 -0
  411. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_slot_metric_state.py +0 -0
  412. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_state_inference.py +0 -0
  413. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_stats_brutalist.py +0 -0
  414. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_stats_card.py +0 -0
  415. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_strip_brutalist_grammar.py +0 -0
  416. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_strip_cellular.py +0 -0
  417. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_strip_status_toggle.py +0 -0
  418. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_telemetry.py +0 -0
  419. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_telemetry_contract_per_stage.py +0 -0
  420. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_telemetry_integration.py +0 -0
  421. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_telemetry_skin_dispatch.py +0 -0
  422. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_tool_class_completeness.py +0 -0
  423. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_url_stability.py +0 -0
  424. {hyperweave-0.3.6 → hyperweave-0.3.7}/tests/test_variant_default_resolution.py +0 -0
  425. {hyperweave-0.3.6 → hyperweave-0.3.7}/uv.lock +4 -4
@@ -5,6 +5,27 @@ All notable changes to HyperWeave are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.7] - 2026-05-18
9
+
10
+ Font payloads now embed only the characters each artifact actually renders, and fonts an artifact never displays are no longer embedded at all. Across every text-bearing artifact type — badges, strips, stats cards, star charts, marquees, receipts, and rhythm strips — and across all three genomes, gzip size drops by an average of 59% per artifact.
11
+
12
+ ### Changed
13
+
14
+ - **Brutalist badge embedding** — single JetBrains Mono `@font-face` block. Barlow Condensed embeds only in stats, strips, and charts.
15
+ - **Automata badge embedding** — Orbitron + Chakra Petch only. JetBrains Mono no longer ships in badges since no badge text uses it.
16
+ - **Automata chart embedding** — Orbitron + JetBrains Mono only. Chakra Petch dropped since no chart text uses it.
17
+ - **Per-genome, per-frame embed list** — `data/font-embedding.yaml` declares which fonts ship for each genome-and-artifact combination. Adding a font is a single YAML edit, no Python changes.
18
+
19
+ ### Fixed
20
+
21
+ - **Codex Stop hook crash on receipt render** — `fonttools` and `brotli` are now runtime dependencies, so `uv tool install` users no longer hit `ModuleNotFoundError: fontTools` when the hook fires.
22
+
23
+ ### Notes
24
+
25
+ - Repeat renders of the same text reuse a cached subset, so the first request pays the subsetting cost and subsequent requests don't.
26
+ - CJK locale font embedding deferred to a future release.
27
+ - Icons and dividers continue to embed zero fonts.
28
+
8
29
  ## [0.3.6] - 2026-05-18
9
30
 
10
31
  Receipt active-duration sources from per-turn compute when the runtime emits it; long-running sessions no longer inflate via stage-span summation. Codex hooks migrate to the wrapped-matcher GA layout shipped in the Codex CLI v0.129 release. The `data-hw-genome` root attribute reflects the resolved genome ID instead of raw spec input.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperweave
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
  Summary: Headless visual output layer for AI agents. One API call → self-contained SVG.
5
5
  Project-URL: Repository, https://github.com/InnerAura/hyperweave
6
6
  Project-URL: Issues, https://github.com/InnerAura/hyperweave/issues
@@ -19,8 +19,10 @@ Classifier: Topic :: Multimedia :: Graphics
19
19
  Classifier: Topic :: Software Development :: Libraries
20
20
  Classifier: Typing :: Typed
21
21
  Requires-Python: >=3.12
22
+ Requires-Dist: brotli>=1.2.0
22
23
  Requires-Dist: fastapi>=0.115
23
24
  Requires-Dist: fastmcp>=3.0
25
+ Requires-Dist: fonttools>=4.62.1
24
26
  Requires-Dist: httpx[http2]>=0.28
25
27
  Requires-Dist: jinja2>=3.1
26
28
  Requires-Dist: pydantic-settings>=2.0
@@ -241,11 +243,11 @@ Why genome and not theme? Because brand isn't a design problem, it's an infrastr
241
243
  <tr>
242
244
  <th align="left">Icons<br/><sub>circle + square</sub></th>
243
245
  <td>
244
- <img src="https://hyperweave.app/v1/icon/github/brutalist.static?shape=circle&variant=celadon" alt="github — celadon" width="56"/>
245
- <img src="https://hyperweave.app/v1/icon/discord/brutalist.static?shape=circle&variant=carbon" alt="discord — carbon" width="56"/>
246
+ <img src="https://hyperweave.app/v1/icon/spotify/brutalist.static?shape=circle&variant=celadon" alt="spotify — celadon" width="56"/>
247
+ <img src="https://hyperweave.app/v1/icon/github/brutalist.static?shape=circle&variant=carbon" alt="github — carbon" width="56"/>
246
248
  <img src="https://hyperweave.app/v1/icon/docker/brutalist.static?shape=circle&variant=alloy" alt="docker — alloy" width="56"/>
247
249
  <img src="https://hyperweave.app/v1/icon/npm/brutalist.static?shape=square&variant=temper" alt="npm — temper" width="56"/>
248
- <img src="https://hyperweave.app/v1/icon/spotify/brutalist.static?shape=square&variant=pigment" alt="spotify — pigment" width="56"/>
250
+ <img src="https://hyperweave.app/v1/icon/discord/brutalist.static?shape=square&variant=pigment" alt="discord — pigment" width="56"/>
249
251
  <img src="https://hyperweave.app/v1/icon/anthropic/brutalist.static?shape=square&variant=ember" alt="anthropic — ember" width="56"/>
250
252
  <br/>
251
253
  <ul>
@@ -269,11 +271,23 @@ Why genome and not theme? Because brand isn't a design problem, it's an infrastr
269
271
  <h3 id="automata">automata</h3>
270
272
 
271
273
  <p align="center">
272
- <img src="https://hyperweave.app/v1/badge/DOCKER/PULL/automata.static?glyph=docker&variant=teal" alt="DOCKER PULL teal variant"/>
273
- <img src="https://hyperweave.app/v1/badge/DISCORD/JOIN/automata.static?glyph=discord&variant=violet" alt="DISCORD JOIN violet variant"/>
274
- <img src="https://hyperweave.app/v1/badge/STARS/automata.static?data=gh:eli64s/readme-ai.stars&glyph=github&variant=amber" alt="STARSamber variant"/>
275
- <img src="https://hyperweave.app/v1/badge/HF/MODELS/automata.static?glyph=huggingface&variant=sulfur" alt="HF MODELS sulfur variant"/>
276
- <img src="https://hyperweave.app/v1/badge/SPOTIFY/LISTEN/automata.static?glyph=spotify&variant=jade" alt="SPOTIFY LISTEN jade variant"/>
274
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=violet&size=compact" alt="PYPIviolet variant"/>
275
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=teal&size=compact" alt="PYPIteal variant"/>
276
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=bone&size=compact" alt="PYPIbone variant"/>
277
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=steel&size=compact" alt="PYPIsteel variant"/>
278
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=amber&size=compact" alt="PYPIamber variant"/>
279
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=jade&size=compact" alt="PYPI — jade variant"/>
280
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=magenta&size=compact" alt="PYPI — magenta variant"/>
281
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=cobalt&size=compact" alt="PYPI — cobalt variant"/>
282
+ <br/>
283
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=toxic&size=compact" alt="PYPI — toxic variant"/>
284
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=solar&size=compact" alt="PYPI — solar variant"/>
285
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=abyssal&size=compact" alt="PYPI — abyssal variant"/>
286
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=crimson&size=compact" alt="PYPI — crimson variant"/>
287
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=sulfur&size=compact" alt="PYPI — sulfur variant"/>
288
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=indigo&size=compact" alt="PYPI — indigo variant"/>
289
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=burgundy&size=compact" alt="PYPI — burgundy variant"/>
290
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=copper&size=compact" alt="PYPI — copper variant"/>
277
291
  </p>
278
292
 
279
293
  <p align="center">
@@ -370,11 +384,11 @@ Why genome and not theme? Because brand isn't a design problem, it's an infrastr
370
384
  <h3 id="chrome">chrome</h3>
371
385
 
372
386
  <p align="center">
373
- <img src="https://hyperweave.app/v1/badge/BUILD/chrome.static?data=gh:InnerAura/hyperweave.build&glyph=githubactions&variant=horizon" alt="BUILD — horizon variant"/>
374
- <img src="https://hyperweave.app/v1/badge/BLUESKY/POST/chrome.static?glyph=bluesky&variant=abyssal" alt="BLUESKY POST — abyssal variant"/>
375
- <img src="https://hyperweave.app/v1/badge/DOCKER/chrome.static?data=docker:zeroxeli/readme-ai.pull_count&glyph=docker&variant=lightning" alt="DOCKER pulls — lightning variant"/>
376
- <img src="https://hyperweave.app/v1/badge/STARS/chrome.static?data=gh:eli64s/readme-ai.stars&glyph=github&variant=graphite" alt="STARS — graphite variant"/>
377
- <img src="https://hyperweave.app/v1/badge/ANTHROPIC/CLAUDE/chrome.static?glyph=anthropic&variant=moth" alt="ANTHROPIC CLAUDE — moth variant"/>
387
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=horizon" alt="PYPI — horizon variant"/>
388
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=abyssal" alt="PYPI — abyssal variant"/>
389
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=lightning" alt="PYPI — lightning variant"/>
390
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=graphite" alt="PYPI — graphite variant"/>
391
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=moth" alt="PYPI — moth variant"/>
378
392
  </p>
379
393
 
380
394
  <p align="center">
@@ -442,10 +456,11 @@ Why genome and not theme? Because brand isn't a design problem, it's an infrastr
442
456
  <tr>
443
457
  <th align="left">Icons<br/><sub>circle + square</sub></th>
444
458
  <td>
445
- <img src="https://hyperweave.app/v1/icon/youtube/chrome.static?shape=circle&variant=horizon" alt="youtube" width="56"/>
446
- <img src="https://hyperweave.app/v1/icon/notion/chrome.static?shape=circle&variant=horizon" alt="notion" width="56"/>
447
- <img src="https://hyperweave.app/v1/icon/npm/chrome.static?shape=square&variant=horizon" alt="npm" width="56"/>
448
- <img src="https://hyperweave.app/v1/icon/instagram/chrome.static?shape=square&variant=horizon" alt="instagram" width="56"/>
459
+ <img src="https://hyperweave.app/v1/icon/github/chrome.static?shape=circle&variant=horizon" alt="github — horizon" width="56"/>
460
+ <img src="https://hyperweave.app/v1/icon/notion/chrome.static?shape=circle&variant=graphite" alt="notion — graphite" width="56"/>
461
+ <img src="https://hyperweave.app/v1/icon/rust/chrome.static?shape=square&variant=moth" alt="rust — moth" width="56"/>
462
+ <img src="https://hyperweave.app/v1/icon/docker/chrome.static?shape=square&variant=lightning" alt="docker — lightning" width="56"/>
463
+ <img src="https://hyperweave.app/v1/icon/spotify/chrome.static?shape=square&variant=abyssal" alt="spotify — abyssal" width="56"/>
449
464
  <br/>
450
465
  <ul>
451
466
  <li><sub><code>/v1/icon/{glyph}/{genome}.static?shape={circle|square}&variant={variant}</code></sub></li>
@@ -209,11 +209,11 @@ Why genome and not theme? Because brand isn't a design problem, it's an infrastr
209
209
  <tr>
210
210
  <th align="left">Icons<br/><sub>circle + square</sub></th>
211
211
  <td>
212
- <img src="https://hyperweave.app/v1/icon/github/brutalist.static?shape=circle&variant=celadon" alt="github — celadon" width="56"/>
213
- <img src="https://hyperweave.app/v1/icon/discord/brutalist.static?shape=circle&variant=carbon" alt="discord — carbon" width="56"/>
212
+ <img src="https://hyperweave.app/v1/icon/spotify/brutalist.static?shape=circle&variant=celadon" alt="spotify — celadon" width="56"/>
213
+ <img src="https://hyperweave.app/v1/icon/github/brutalist.static?shape=circle&variant=carbon" alt="github — carbon" width="56"/>
214
214
  <img src="https://hyperweave.app/v1/icon/docker/brutalist.static?shape=circle&variant=alloy" alt="docker — alloy" width="56"/>
215
215
  <img src="https://hyperweave.app/v1/icon/npm/brutalist.static?shape=square&variant=temper" alt="npm — temper" width="56"/>
216
- <img src="https://hyperweave.app/v1/icon/spotify/brutalist.static?shape=square&variant=pigment" alt="spotify — pigment" width="56"/>
216
+ <img src="https://hyperweave.app/v1/icon/discord/brutalist.static?shape=square&variant=pigment" alt="discord — pigment" width="56"/>
217
217
  <img src="https://hyperweave.app/v1/icon/anthropic/brutalist.static?shape=square&variant=ember" alt="anthropic — ember" width="56"/>
218
218
  <br/>
219
219
  <ul>
@@ -237,11 +237,23 @@ Why genome and not theme? Because brand isn't a design problem, it's an infrastr
237
237
  <h3 id="automata">automata</h3>
238
238
 
239
239
  <p align="center">
240
- <img src="https://hyperweave.app/v1/badge/DOCKER/PULL/automata.static?glyph=docker&variant=teal" alt="DOCKER PULL teal variant"/>
241
- <img src="https://hyperweave.app/v1/badge/DISCORD/JOIN/automata.static?glyph=discord&variant=violet" alt="DISCORD JOIN violet variant"/>
242
- <img src="https://hyperweave.app/v1/badge/STARS/automata.static?data=gh:eli64s/readme-ai.stars&glyph=github&variant=amber" alt="STARSamber variant"/>
243
- <img src="https://hyperweave.app/v1/badge/HF/MODELS/automata.static?glyph=huggingface&variant=sulfur" alt="HF MODELS sulfur variant"/>
244
- <img src="https://hyperweave.app/v1/badge/SPOTIFY/LISTEN/automata.static?glyph=spotify&variant=jade" alt="SPOTIFY LISTEN jade variant"/>
240
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=violet&size=compact" alt="PYPIviolet variant"/>
241
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=teal&size=compact" alt="PYPIteal variant"/>
242
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=bone&size=compact" alt="PYPIbone variant"/>
243
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=steel&size=compact" alt="PYPIsteel variant"/>
244
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=amber&size=compact" alt="PYPIamber variant"/>
245
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=jade&size=compact" alt="PYPI — jade variant"/>
246
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=magenta&size=compact" alt="PYPI — magenta variant"/>
247
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=cobalt&size=compact" alt="PYPI — cobalt variant"/>
248
+ <br/>
249
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=toxic&size=compact" alt="PYPI — toxic variant"/>
250
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=solar&size=compact" alt="PYPI — solar variant"/>
251
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=abyssal&size=compact" alt="PYPI — abyssal variant"/>
252
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=crimson&size=compact" alt="PYPI — crimson variant"/>
253
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=sulfur&size=compact" alt="PYPI — sulfur variant"/>
254
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=indigo&size=compact" alt="PYPI — indigo variant"/>
255
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=burgundy&size=compact" alt="PYPI — burgundy variant"/>
256
+ <img src="https://hyperweave.app/v1/badge/PYPI/automata.static?data=pypi:hyperweave.version&glyph=python&variant=copper&size=compact" alt="PYPI — copper variant"/>
245
257
  </p>
246
258
 
247
259
  <p align="center">
@@ -338,11 +350,11 @@ Why genome and not theme? Because brand isn't a design problem, it's an infrastr
338
350
  <h3 id="chrome">chrome</h3>
339
351
 
340
352
  <p align="center">
341
- <img src="https://hyperweave.app/v1/badge/BUILD/chrome.static?data=gh:InnerAura/hyperweave.build&glyph=githubactions&variant=horizon" alt="BUILD — horizon variant"/>
342
- <img src="https://hyperweave.app/v1/badge/BLUESKY/POST/chrome.static?glyph=bluesky&variant=abyssal" alt="BLUESKY POST — abyssal variant"/>
343
- <img src="https://hyperweave.app/v1/badge/DOCKER/chrome.static?data=docker:zeroxeli/readme-ai.pull_count&glyph=docker&variant=lightning" alt="DOCKER pulls — lightning variant"/>
344
- <img src="https://hyperweave.app/v1/badge/STARS/chrome.static?data=gh:eli64s/readme-ai.stars&glyph=github&variant=graphite" alt="STARS — graphite variant"/>
345
- <img src="https://hyperweave.app/v1/badge/ANTHROPIC/CLAUDE/chrome.static?glyph=anthropic&variant=moth" alt="ANTHROPIC CLAUDE — moth variant"/>
353
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=horizon" alt="PYPI — horizon variant"/>
354
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=abyssal" alt="PYPI — abyssal variant"/>
355
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=lightning" alt="PYPI — lightning variant"/>
356
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=graphite" alt="PYPI — graphite variant"/>
357
+ <img src="https://hyperweave.app/v1/badge/PYPI/chrome.static?data=pypi:hyperweave.version&glyph=python&variant=moth" alt="PYPI — moth variant"/>
346
358
  </p>
347
359
 
348
360
  <p align="center">
@@ -410,10 +422,11 @@ Why genome and not theme? Because brand isn't a design problem, it's an infrastr
410
422
  <tr>
411
423
  <th align="left">Icons<br/><sub>circle + square</sub></th>
412
424
  <td>
413
- <img src="https://hyperweave.app/v1/icon/youtube/chrome.static?shape=circle&variant=horizon" alt="youtube" width="56"/>
414
- <img src="https://hyperweave.app/v1/icon/notion/chrome.static?shape=circle&variant=horizon" alt="notion" width="56"/>
415
- <img src="https://hyperweave.app/v1/icon/npm/chrome.static?shape=square&variant=horizon" alt="npm" width="56"/>
416
- <img src="https://hyperweave.app/v1/icon/instagram/chrome.static?shape=square&variant=horizon" alt="instagram" width="56"/>
425
+ <img src="https://hyperweave.app/v1/icon/github/chrome.static?shape=circle&variant=horizon" alt="github — horizon" width="56"/>
426
+ <img src="https://hyperweave.app/v1/icon/notion/chrome.static?shape=circle&variant=graphite" alt="notion — graphite" width="56"/>
427
+ <img src="https://hyperweave.app/v1/icon/rust/chrome.static?shape=square&variant=moth" alt="rust — moth" width="56"/>
428
+ <img src="https://hyperweave.app/v1/icon/docker/chrome.static?shape=square&variant=lightning" alt="docker — lightning" width="56"/>
429
+ <img src="https://hyperweave.app/v1/icon/spotify/chrome.static?shape=square&variant=abyssal" alt="spotify — abyssal" width="56"/>
417
430
  <br/>
418
431
  <ul>
419
432
  <li><sub><code>/v1/icon/{glyph}/{genome}.static?shape={circle|square}&variant={variant}</code></sub></li>
@@ -42,6 +42,13 @@ dependencies = [
42
42
  "httpx[http2]>=0.28",
43
43
  "fastmcp>=3.0",
44
44
  "pyyaml>=6.0",
45
+ # Font subsetting (v0.3.7). Runtime — not dev-only — because
46
+ # render/fonts.py imports fontTools at module top-level, which
47
+ # executes on every receipt render. brotli is the WOFF2 codec
48
+ # fontTools uses inside font.save(flavor="woff2") and must be
49
+ # importable on every install (uv tool install, pip install, etc.).
50
+ "fonttools>=4.62.1",
51
+ "brotli>=1.2.0",
45
52
  ]
46
53
 
47
54
  [project.urls]
@@ -81,8 +88,6 @@ dev = [
81
88
  "mypy>=1.14",
82
89
  "types-pyyaml>=6.0.12.20250915",
83
90
  "pre-commit>=4.0",
84
- "fonttools>=4.62.1",
85
- "brotli>=1.2.0",
86
91
  ]
87
92
 
88
93
  [tool.pytest.ini_options]
@@ -1691,6 +1691,18 @@ def main() -> None:
1691
1691
  parser.add_argument("--live", action="store_true", help="Include network-dependent artifacts")
1692
1692
  args = parser.parse_args()
1693
1693
 
1694
+ # Wipe outputs/proofset/ before regenerating so renamed/retired artifacts
1695
+ # (paired-variant pairings, telemetry size variants) don't carry stale
1696
+ # payloads forward and create false audit noise. READMEs live one level up
1697
+ # (outputs/README*.md) and are preserved.
1698
+ import shutil
1699
+
1700
+ proofset_dir = OUT / "proofset"
1701
+ if proofset_dir.exists():
1702
+ stale = sum(1 for _ in proofset_dir.rglob("*.svg"))
1703
+ shutil.rmtree(proofset_dir)
1704
+ print(f"Cleaned {stale} stale artifacts from {proofset_dir}")
1705
+
1694
1706
  print("Generating static proof set...")
1695
1707
  total = generate_static()
1696
1708
  print(f" {total} static artifacts")
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.3.6'
22
- __version_tuple__ = version_tuple = (0, 3, 6)
21
+ __version__ = version = '0.3.7'
22
+ __version_tuple__ = version_tuple = (0, 3, 7)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -19,63 +19,49 @@ _BRIDGE_FRAMES: frozenset[str] = frozenset({FrameType.BADGE, FrameType.STRIP, Fr
19
19
  # Marquee frame types — need frame_fill, status colors, ink tiers
20
20
  _MARQUEE_FRAMES: frozenset[str] = frozenset({FrameType.MARQUEE_HORIZONTAL})
21
21
 
22
- # Per-frame font allowlist: maps each frame type to the font slugs that frame's
23
- # templates actually render. Frames absent from the dict embed zero fonts (icon,
24
- # divider). This is a refinement of the pre-v0.3.0 binary gate (frozenset of
25
- # frame names): the dict shape lets each frame declare exactly the slugs it
26
- # needs, so a marquee carrying only Orbitron text doesn't ship JetBrains Mono
27
- # and Chakra Petch base64 payloads it never references.
28
- #
29
- # Slugs match the keys in ``data/fonts/{slug}.b64`` and the entries in genome
30
- # ``fonts`` lists. The intersection of the genome's font list and a frame's
31
- # allowed slugs is what actually gets embedded.
22
+
23
+ # Font embedding gate: per-(genome_id, frame_type) lookup against the YAML
24
+ # config at ``data/font-embedding.yaml``. Replaces the v0.3.5 frozenset
25
+ # table that was keyed only by frame_type which meant the brutalist
26
+ # badge embedded the genome's full font list (~28KB of unused Barlow
27
+ # Condensed base64) because the genome declared Barlow for stats/strip/
28
+ # chart and the badge frame's allowlist passed it through.
32
29
  #
33
- # Per-frame allocation rationale:
34
- # - BADGE / STRIP / RECEIPT / RHYTHM_STRIP / MASTER_CARD / CATALOG: full 3-font
35
- # set these frames render mixed typography (mono labels, display values,
36
- # chakra-petch metrics).
37
- # - STATS: full 3-font set Chakra Petch for metric values, Orbitron for
38
- # username/title, JetBrains Mono for labels.
39
- # - CHART: Orbitron (header zone) + JetBrains Mono (axis labels). Chart never
40
- # renders Chakra Petch saving ~13KB per chart artifact.
41
- # - MARQUEE_HORIZONTAL: Orbitron only. Cellular marquee scroll text is Orbitron
42
- # 11px 700 with no other typography. Saving ~55KB per marquee artifact.
43
- # - ICON / DIVIDER: not in dict zero fonts. Glyph-only rendering, no <text>
44
- # elements.
45
- _BRUTALIST_FONTS: frozenset[str] = frozenset(
46
- {"jetbrains-mono", "orbitron", "chakra-petch", "barlow-condensed-700", "barlow-condensed-900"}
47
- )
48
- _CHART_FONTS: frozenset[str] = frozenset({"jetbrains-mono", "orbitron", "barlow-condensed-700", "barlow-condensed-900"})
49
- _TELEMETRY_FONTS: frozenset[str] = frozenset({"jetbrains-mono", "orbitron", "chakra-petch"})
50
-
51
- _NEEDS_FONTS: dict[str, frozenset[str]] = {
52
- FrameType.BADGE: _BRUTALIST_FONTS,
53
- FrameType.STRIP: _BRUTALIST_FONTS,
54
- FrameType.STATS: _BRUTALIST_FONTS,
55
- FrameType.CHART: _CHART_FONTS,
56
- FrameType.MARQUEE_HORIZONTAL: frozenset({"orbitron"}),
57
- FrameType.RECEIPT: _TELEMETRY_FONTS,
58
- FrameType.RHYTHM_STRIP: _TELEMETRY_FONTS,
59
- FrameType.MASTER_CARD: _TELEMETRY_FONTS,
60
- FrameType.CATALOG: _TELEMETRY_FONTS,
61
- }
62
-
63
-
64
- def frame_needs_fonts(frame_type: str) -> bool:
65
- """Per-frame font-loading gate. Returns True if any fonts should be
66
- embedded for this frame type. Frames absent from the ``_NEEDS_FONTS`` dict
67
- return False — icon and divider render glyph-only with no ``<text>``
68
- elements, so embedding fonts in them is pure payload waste.
30
+ # The genome-aware lookup lets the brutalist badge embed only JetBrains
31
+ # Mono (the one font its CSS classes actually reference) while the
32
+ # brutalist stats card continues to embed all three fonts it needs.
33
+ # Adding a new (genome, frame) binding is a YAML edit only (Invariant 12).
34
+ def fonts_for_frame(frame_type: str, genome_id: str = "") -> frozenset[str]:
35
+ """Return the font slugs to embed for ``(frame_type, genome_id)``.
36
+
37
+ When ``genome_id`` matches a row in ``font-embedding.yaml``'s
38
+ ``genomes`` block, returns that row's per-frame list. Otherwise
39
+ falls back to ``defaults.<frame_type>`` an empty list in v0.3.7,
40
+ matching icon/divider semantics for callers without resolved genome
41
+ context (e.g. ``_error_badge``).
42
+
43
+ The composer further intersects this with the genome's declared
44
+ ``fonts`` list at ``compose/context.py:_load_font_faces``, so a slug
45
+ listed here that the genome does not declare is a noop.
69
46
  """
70
- return frame_type in _NEEDS_FONTS
47
+ from hyperweave.config.loader import load_font_embedding
48
+
49
+ embedding = load_font_embedding()
50
+ genome_block = embedding["genomes"].get(genome_id) if genome_id else None
51
+ if isinstance(genome_block, dict) and frame_type in genome_block:
52
+ slugs = genome_block.get(frame_type) or []
53
+ else:
54
+ slugs = embedding["defaults"].get(frame_type) or []
55
+ return frozenset(slugs)
71
56
 
72
57
 
73
- def fonts_for_frame(frame_type: str) -> frozenset[str]:
74
- """Return the set of font slugs allowed for embedding in ``frame_type``'s
75
- templates. Empty set for frames that don't render text. The font loader
76
- intersects this with the genome's declared font list so genomes that don't
77
- declare a slug still skip it even if the frame allows it."""
78
- return _NEEDS_FONTS.get(frame_type, frozenset())
58
+ def frame_needs_fonts(frame_type: str, genome_id: str = "") -> bool:
59
+ """Per-(frame_type, genome_id) font-loading gate. Returns True when
60
+ any fonts should be embedded used by context-builder to gate the
61
+ ``data-hw-fonts="self-contained"`` SVG-root attribute and the
62
+ ``hw:css-modules`` debug comment.
63
+ """
64
+ return bool(fonts_for_frame(frame_type, genome_id))
79
65
 
80
66
 
81
67
  # Genome fields that signal a telemetry skin (presence-gates the tool-color CSS block)
@@ -95,27 +95,164 @@ def _compute_contrast_ratio(fg_hex: str, bg_hex: str) -> str:
95
95
  return f"{ratio:.1f}:1"
96
96
 
97
97
 
98
- def _load_font_faces(genome: dict[str, Any], frame_type: str) -> str:
99
- """Load embedded font CSS for ``frame_type``, filtered to slugs the frame
100
- actually renders.
101
-
102
- Intersects the genome's declared ``fonts`` list with the per-frame allowlist
103
- returned by :func:`fonts_for_frame`. A genome that declares all 3 fonts
104
- (chakra-petch, orbitron, jetbrains-mono) will only embed Orbitron when the
105
- frame is a marquee, saving ~55KB per artifact. Frames absent from the
106
- allowlist (icon, divider) get an empty allowed set and embed zero fonts.
107
-
108
- The intersection is order-preserving against the genome's declared list so
109
- @font-face declarations render in genome-author intent order.
98
+ def _load_font_faces(
99
+ genome: dict[str, Any],
100
+ frame_type: str,
101
+ char_set: frozenset[str] | None = None,
102
+ ) -> str:
103
+ """Load embedded font CSS for ``(frame_type, genome.id)``.
104
+
105
+ Intersects the genome's declared ``fonts`` list with the per-(genome,
106
+ frame) allowlist returned by :func:`fonts_for_frame`. The allowlist
107
+ is genome-aware (v0.3.7): the brutalist badge embeds JetBrains Mono
108
+ only even though the brutalist genome declares Barlow Condensed for
109
+ its stats/strip/chart frames. Frames whose ``(genome, frame)`` row
110
+ is empty (icons, dividers, error badges) embed zero fonts.
111
+
112
+ When ``char_set`` is provided each surviving font is subset to only
113
+ the codepoints the artifact actually renders. ``None`` embeds full
114
+ fonts (legacy behavior, ``_error_badge``).
115
+
116
+ The intersection is order-preserving against the genome's declared
117
+ list so ``@font-face`` declarations render in genome-author intent
118
+ order.
110
119
  """
111
120
  declared = genome.get("fonts") or ["jetbrains-mono"]
112
121
  if not isinstance(declared, list):
113
122
  declared = ["jetbrains-mono"]
114
- allowed = fonts_for_frame(frame_type)
123
+ genome_id = genome.get("id", "")
124
+ allowed = fonts_for_frame(frame_type, genome_id)
115
125
  if not allowed:
116
126
  return ""
117
127
  filtered = [slug for slug in declared if slug in allowed]
118
- return load_font_face_css(filtered)
128
+ return load_font_face_css(filtered, char_set)
129
+
130
+
131
+ # Per-frame text-field maps for glyph subsetting. Each entry lists the
132
+ # context keys whose string content reaches a rendered <text> element
133
+ # and therefore must be present in the font subset. Glyph SVG paths,
134
+ # reasoning metadata, ARIA strings, and version/created/contract_id
135
+ # render via different paths (paths render as <path>, metadata renders
136
+ # in <hw:*> blocks read by no browser font) and stay outside the
137
+ # extraction surface.
138
+ _TEXT_FIELDS_BY_FRAME: dict[str, tuple[str, ...]] = {
139
+ "badge": ("title", "value", "label", "description"),
140
+ "strip": ("title", "value", "label", "description"),
141
+ "stats": (
142
+ "stats_username",
143
+ "stats_bio",
144
+ "stats_repo_label",
145
+ "stars_display",
146
+ "stars_delta_display",
147
+ "commits_display",
148
+ "prs_display",
149
+ "issues_display",
150
+ "contrib_display",
151
+ "streak_display",
152
+ "languages",
153
+ "activity_bars",
154
+ ),
155
+ "chart": (
156
+ "chart_repo",
157
+ "chart_title",
158
+ "chart_current_stars",
159
+ "chart_axes",
160
+ "chart_milestones",
161
+ "chart_empty_state",
162
+ ),
163
+ "marquee-horizontal": ("scroll_items",),
164
+ "receipt": (
165
+ "hero_headline",
166
+ "hero_subline",
167
+ "hero_right_stats",
168
+ "treemap_legend",
169
+ "metadata_left",
170
+ "metadata_right",
171
+ "footer_left",
172
+ "footer_right",
173
+ "dominant_profile",
174
+ "phase_legend",
175
+ ),
176
+ "rhythm-strip": (
177
+ "session_id_short",
178
+ "elapsed_label",
179
+ "token_summary",
180
+ "velocity_value",
181
+ "loop_label",
182
+ "loop_detail",
183
+ "profile_label",
184
+ "stages",
185
+ ),
186
+ "master-card": (
187
+ "mc_title",
188
+ "mc_subtitle",
189
+ "mc_total_tokens",
190
+ "mc_total_cost",
191
+ "mc_sessions",
192
+ "mc_skills",
193
+ "session_entries",
194
+ "footer_left",
195
+ "footer_right",
196
+ ),
197
+ "catalog": (
198
+ "catalog_title",
199
+ "catalog_subtitle",
200
+ "catalog_items",
201
+ "catalog_footer_left",
202
+ "catalog_footer_right",
203
+ ),
204
+ }
205
+
206
+ # Conservative baseline character set. Always included even when the
207
+ # template's resolved text is sparse — covers axis tick labels, %
208
+ # suffixes, numeric formatters, paren-wrapped clarifiers, and unicode
209
+ # arrows / dots used in chrome/brutalist label glyphs.
210
+ _SAFE_BASELINE: frozenset[str] = frozenset(
211
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .:,;-_/·→×%+()[]" # noqa: RUF001 middle-dot / right-arrow / multiplication-sign are deliberate
212
+ )
213
+
214
+
215
+ def _collect_text(value: Any, chars: set[str]) -> None:
216
+ """Recursively walk ``value`` and absorb every string codepoint into ``chars``.
217
+
218
+ Lists, tuples, and dicts (keys + values) are traversed; ``None`` and
219
+ non-string scalars (numbers, bools) are skipped. The recursive shape
220
+ keeps the collector resilient against future context-field additions
221
+ that wrap text in additional dict/list layers — a new ``chart_axes``
222
+ entry shape doesn't need a corresponding extractor edit.
223
+ """
224
+ if value is None:
225
+ return
226
+ if isinstance(value, str):
227
+ chars.update(value)
228
+ return
229
+ if isinstance(value, list | tuple):
230
+ for item in value:
231
+ _collect_text(item, chars)
232
+ return
233
+ if isinstance(value, dict):
234
+ for k, v in value.items():
235
+ if isinstance(k, str):
236
+ chars.update(k)
237
+ _collect_text(v, chars)
238
+
239
+
240
+ def _extract_char_set(ctx: dict[str, Any], frame_type: str) -> frozenset[str]:
241
+ """Return the union of the safe baseline and every rendered text char.
242
+
243
+ Reads the per-frame text-field map at :data:`_TEXT_FIELDS_BY_FRAME`
244
+ and recursively flattens each context value to its component codepoints.
245
+ Frames not in the map fall back to the baseline only.
246
+
247
+ Run AFTER the per-frame builder populates ``ctx`` (which means the
248
+ resolver-emitted text fields like ``chart_milestones`` and
249
+ ``stats_username`` are visible) — see the ordering note on
250
+ :func:`build_context`.
251
+ """
252
+ chars: set[str] = set(_SAFE_BASELINE)
253
+ for field in _TEXT_FIELDS_BY_FRAME.get(frame_type, ()):
254
+ _collect_text(ctx.get(field), chars)
255
+ return frozenset(chars)
119
256
 
120
257
 
121
258
  def build_context(
@@ -123,7 +260,17 @@ def build_context(
123
260
  resolved: ResolvedArtifact,
124
261
  css_bundle: dict[str, str],
125
262
  ) -> dict[str, Any]:
126
- """Dispatch to the per-frame context builder."""
263
+ """Dispatch to the per-frame context builder, then wire font subsetting.
264
+
265
+ Per-frame builders fill ``ctx`` with the safe defaults and then merge
266
+ ``resolved.frame_context`` (resolver output: ``chart_milestones``,
267
+ ``stats_username``, ``scroll_items[*].text``, etc.). Only after that
268
+ merge runs does the rendered text surface become observable — which is
269
+ why v0.3.7 moves the ``font_faces`` assignment OUT of ``_base_context``
270
+ and INTO this post-builder step. The extractor at :func:`_extract_char_set`
271
+ then walks the fully-populated ctx and the subsetter at
272
+ :func:`_load_font_faces` emits a payload tuned to the actual glyph set.
273
+ """
127
274
  _BUILDERS: dict[str, _CtxBuilder] = {
128
275
  FrameType.BADGE: _ctx_badge,
129
276
  FrameType.STRIP: _ctx_strip,
@@ -140,6 +287,10 @@ def build_context(
140
287
  builder = _BUILDERS.get(spec.type, _ctx_badge)
141
288
  ctx = builder(spec, resolved, css_bundle)
142
289
  _inject_motion(ctx, spec, resolved)
290
+ genome_id = resolved.genome.get("id", "")
291
+ if frame_needs_fonts(spec.type, genome_id):
292
+ char_set = _extract_char_set(ctx, spec.type)
293
+ ctx["font_faces"] = _load_font_faces(resolved.genome, spec.type, char_set)
143
294
  return ctx
144
295
 
145
296
 
@@ -168,7 +319,7 @@ def _base_context(
168
319
  # surfaces here too so `grep "hw:css-modules"` across outputs/proofset/ can
169
320
  # confirm fonts were correctly excluded for icons/dividers.
170
321
  module_names = [k for k, v in css_bundle.items() if v]
171
- if frame_needs_fonts(spec.type):
322
+ if frame_needs_fonts(spec.type, resolved.genome.get("id", "")):
172
323
  module_names.append("fonts")
173
324
  css_debug = f"/* hw:css-modules: {','.join(module_names)} */"
174
325
  css_assembled = css_debug + "\n" + "\n".join(p for p in css_parts if p)
@@ -310,14 +461,16 @@ def _base_context(
310
461
  # enforced at load time; missing entries return None and the metadata
311
462
  # template emits empty hw:reasoning fields gracefully.
312
463
  **_resolve_reasoning_context(spec, resolved),
313
- # Embedded fonts (base64 @font-face CSS) — gated per frame_type via
314
- # frame_needs_fonts() and filtered per frame's font allowlist via
315
- # fonts_for_frame(). Icons / dividers receive empty string (not in
316
- # _NEEDS_FONTS dict) so template-level {{ font_faces }} renders
317
- # nothing. Marquee receives Orbitron only; chart receives Orbitron +
318
- # JetBrains Mono. The frame-aware filtering mirrors the per-frame CSS
319
- # module pattern at assembler.py:14-32.
320
- "font_faces": _load_font_faces(resolved.genome, spec.type) if frame_needs_fonts(spec.type) else "",
464
+ # Embedded fonts (base64 @font-face CSS) — placeholder. The real
465
+ # assignment lands in build_context() AFTER the per-frame builder
466
+ # merges resolver text fields into ctx, so the glyph subsetter
467
+ # at _extract_char_set + _load_font_faces sees the full rendered
468
+ # text surface (chart milestone labels, stats username, marquee
469
+ # scroll items, etc.). Setting the empty default here keeps
470
+ # Jinja's StrictUndefined happy for any code path that bypasses
471
+ # build_context (none exist today, but the default is defense
472
+ # against future drift).
473
+ "font_faces": "",
321
474
  }
322
475
  return ctx, uid, artifact_id
323
476