hyperweave 0.2.24__tar.gz → 0.2.25__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.
- {hyperweave-0.2.24 → hyperweave-0.2.25}/CHANGELOG.md +15 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/PKG-INFO +2 -1
- {hyperweave-0.2.24 → hyperweave-0.2.25}/README.md +1 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/_version.py +2 -2
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/context.py +5 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/engine.py +17 -4
- hyperweave-0.2.25/src/hyperweave/compose/layout.py +303 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/resolver.py +112 -89
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/config/loader.py +19 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/paradigm.py +18 -0
- hyperweave-0.2.25/src/hyperweave/data/badge_modes.yaml +66 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/css/expression.css +23 -7
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/paradigms/cellular.yaml +10 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/document.svg.j2 +2 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/badge/brutalist-content.j2 +11 -11
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/badge/cellular-content.j2 +8 -12
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/badge/chrome-content.j2 +5 -5
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip.svg.j2 +5 -0
- hyperweave-0.2.25/tests/snapshots/url_stability/divider_band_chrome_static.svg +195 -0
- hyperweave-0.2.25/tests/snapshots/url_stability/icon_github_chrome_static.svg +269 -0
- hyperweave-0.2.25/tests/test_badge_layout.py +281 -0
- hyperweave-0.2.25/tests/test_badge_mode.py +264 -0
- hyperweave-0.2.25/tests/test_url_stability.py +116 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/.dockerignore +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/.github/workflows/ci.yml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/.github/workflows/deploy.yml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/.github/workflows/publish.yml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/.gitignore +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/.pre-commit-config.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/Dockerfile +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/LICENSE +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/buttons/button-liquid.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/cards/card-butterfly.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/cards/card-python.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/cards/card-sunflower.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/cards/card-waves.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/badge_critical.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/badge_passing.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/badge_warning.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/banner.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/icons/discord.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/icons/notion.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/icons/reddit.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/icons/spotify.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/icons/youtube.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/marquee_counter.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/marquee_horizontal.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/marquee_vertical.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/profile-cards/chart_stars_full.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/profile-cards/stats.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/brutalist-emerald/strip.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/badge_critical.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/badge_passing.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/badge_warning.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/banner.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/icons/bluesky.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/icons/github.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/icons/instagram.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/icons/mastodon.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/icons/x.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/marquee_counter.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/marquee_horizontal.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/marquee_vertical.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/profile-cards/chart_stars_full.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/profile-cards/stats.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/chrome-horizon/strip.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/telemetry/master_card.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/telemetry/receipt.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/telemetry/receipt_claude-code_medium.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/telemetry/receipt_codex_large.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/telemetry/receipt_voltage_xlarge.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/telemetry/rhythm_strip.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/examples/telemetry/rhythm_strip_voltage_xlarge.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/footers/inneraura-footer-liquid.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/footers/inneraura-footer-purple.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/footers/inneraura-footer.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/hyperweave-banner.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/icons/cobalt-sapphire-discord.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/icons/cobalt-sapphire-docs.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/icons/cobalt-sapphire-github.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/icons/cobalt-sapphire-instagram.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/icons/cobalt-sapphire-linkedin.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/icons/cobalt-sapphire-tiktok.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/icons/cobalt-sapphire-x.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/icons/cobalt-sapphire-youtube.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/marquees/badge-showcase-triple.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/marquees/genome-marquee-triple.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/marquees/sample-badges.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/mintlify-assets/404.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/mintlify-assets/callout-icons.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/mintlify-assets/divider.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/mintlify-assets/favicon.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/mintlify-assets/hero-banner.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/mintlify-assets/hyperweave-banner-v2.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/mintlify-assets/hyperweave-navbar-logo.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/mintlify-assets/loader.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/mintlify-assets/og-image.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/assets/timelines/hyperweave-roadmap.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/assets/favicon.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/assets/hyperweave-banner.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/assets/hyperweave-navbar-logo.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/assets/og-image.svg +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/explanation/architecture.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/explanation/camo-compatibility.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/explanation/cim-compliance.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/explanation/genome-profile-system.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/explanation/metadata-tiers.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/how-to/add-motion-to-badges.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/how-to/create-session-receipts.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/how-to/set-up-claude-code-hooks.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/how-to/use-live-data-badges.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/introduction.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/mint.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/quickstart.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/reference/cli.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/reference/compose-spec.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/reference/genomes.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/reference/http-api.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/reference/mcp-tools.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/reference/motions.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/reference/telemetry-contract.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/spec/hyperweave-protocol.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/tutorials/build-an-artifact-kit.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/tutorials/compose-your-first-badge.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/docs/tutorials/install-session-telemetry.mdx +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/fly.toml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/hooks/install.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/hooks/session_end.sh +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/justfile +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/pyproject.toml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/scripts/extract_font_metrics.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/scripts/extract_glyphs.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/scripts/generate_proofset.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/scripts/probe_live_stats.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/scripts/probe_star_history.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/scripts/stress_test.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/__main__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/cli.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/assembler.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/bar_chart.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/lanes.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/resolvers/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/resolvers/chart.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/resolvers/stats.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/rhythm.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/rhythm_strip.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/treemap.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/compose/validate_paradigms.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/config/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/config/genome_validator.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/config/registry.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/config/settings.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/connectors/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/connectors/arxiv.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/connectors/base.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/connectors/cache.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/connectors/github.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/connectors/rest.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/cell_layout.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/color.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/contracts.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/enums.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/font_metrics.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/models.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/schema.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/state.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/text.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/core/thresholds.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/css/accessibility.css +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/css/bridge.css +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/css/status.css +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/font-metrics/chakra-petch.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/font-metrics/inter.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/font-metrics/jetbrains-mono.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/font-metrics/orbitron.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/fonts/chakra-petch.b64 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/fonts/chakra-petch.meta.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/fonts/jetbrains-mono.b64 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/fonts/jetbrains-mono.meta.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/fonts/orbitron.b64 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/fonts/orbitron.meta.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/genomes/automata.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/genomes/brutalist.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/genomes/chrome.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/genomes/telemetry-claude-code.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/genomes/telemetry-codex.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/genomes/telemetry-cream.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/genomes/telemetry-voltage.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/glyphs.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/motions/border/chromatic-pulse.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/motions/border/corner-trace.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/motions/border/dual-orbit.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/motions/border/entanglement.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/motions/border/rimrun.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/motions/static.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/paradigms/brutalist.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/paradigms/chrome.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/paradigms/default.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/policies/normal.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/policies/permissive.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/policies/ungoverned.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/profiles/brutalist.contract.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/profiles/brutalist.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/profiles/chrome.contract.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/profiles/chrome.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/specimens.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/telemetry/model-pricing.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/telemetry/runtimes/claude-code.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/telemetry/runtimes/codex.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/telemetry/stage-config.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/telemetry/stage-labels.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/telemetry/tool-colors.yaml +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/arrow.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/aurora.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/beacon.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/bracket3d.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/chevron.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/crosshair.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/diamond.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/rocket.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/rules/bar.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/rules/dashed.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/rules/five-wave.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/rules/spectral.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/rules/straight.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/rules/wave.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/data/terminals/stijl.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/kit.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/mcp/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/mcp/__main__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/mcp/server.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/py.typed +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/render/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/render/chart_engine.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/render/fonts.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/render/glyphs.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/render/motion.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/render/templates.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/serve/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/serve/app.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/serve/data_tokens.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/capture.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/codex_parser.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/contract.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/corrections.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/cost.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/models.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/parser.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/runtimes.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/telemetry/stages.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-area.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-axes.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-empty-state.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-gridlines.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-markers/circle.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-markers/diamond.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-markers/endpoint-diamond.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-markers/endpoint-rect.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-markers/rect.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-milestone.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/chart-polyline.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/filter.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/glyph-inline.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/glyph.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/gradient.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/metadata.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/metric.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/phase-segment.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/rule.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/status.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/components/terminal.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/error-badge.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/badge/brutalist-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/badge/cellular-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/badge/chrome-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/badge/default-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/badge/default-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/badge.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/catalog.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/chart/brutalist-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/chart/brutalist-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/chart/cellular-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/chart/cellular-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/chart/chrome-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/chart/chrome-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/chart.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/divider/brutalist-seam.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/divider/chrome-band.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/divider.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/icon/brutalist-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/icon/brutalist-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/icon/cellular-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/icon/cellular-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/icon/chrome-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/icon/chrome-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/icon/default-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/icon/default-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/icon.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/brutalist-overlay.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/cellular-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/cellular-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/cellular-overlay.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/chrome-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/chrome-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/chrome-overlay.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/default-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal/default-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/marquee-horizontal.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/master-card.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/receipt.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/rhythm-strip.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/stats/brutalist-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/stats/brutalist-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/stats/cellular-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/stats/cellular-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/stats/chrome-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/stats/chrome-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/stats.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/brutalist-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/brutalist-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/brutalist-status.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/cellular-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/cellular-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/cellular-status.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/chrome-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/chrome-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/chrome-status.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/default-content.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/default-defs.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/frames/strip/default-status.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/motions/border/chromatic-pulse.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/motions/border/corner-trace.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/motions/border/dual-orbit.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/motions/border/entanglement.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/motions/border/rimrun.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/partials/provider-glyphs.svg.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/src/hyperweave/templates/partials/state-signal-cascade.j2 +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/__init__.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/conftest.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/fixtures/codex_session.jsonl +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/fixtures/codex_session_patches.jsonl +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/fixtures/github_contributions/synthetic.html +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/fixtures/session.json +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/fixtures/session.jsonl +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/helpers.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_assembler.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_badge_cellular.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_chart_engine.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_chart_frame.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_codex_parser.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_compose_bar_chart.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_compose_rhythm_strip.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_compose_treemap.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_compose_variant_field.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_connectors.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_core.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_data_tokens.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_divider_cellular.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_divider_genome_specific.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_font_metrics_chakra.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_genome_automata.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_github_scrape.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_kit.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_marquee_v0_2_16.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_mcp.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_paradigm_cellular.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_paradigm_dispatch.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_paradigm_extensibility.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_parse_transcript_auto.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_proofset.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_receipt_token_compliance.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_render.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_resolver_rhythm.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_runtime_registries.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_serve.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_serve_live_state.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_slot_metric_state.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_state_inference.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_stats_card.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_strip_cellular.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_strip_status_toggle.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_telemetry.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_telemetry_contract_per_stage.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_telemetry_integration.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_telemetry_skin_dispatch.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_tool_class_completeness.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/tests/test_variant_default_resolution.py +0 -0
- {hyperweave-0.2.24 → hyperweave-0.2.25}/uv.lock +0 -0
|
@@ -5,6 +5,21 @@ 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.2.25] - 2026-05-07
|
|
9
|
+
|
|
10
|
+
Production badges on data-driven URLs (`STARS`, `FORKS`, `VERSION`, `LICENSE`, `PYTHON`) no longer trigger false-alarm status indicators on numeric values. Badge value text now centers correctly for every value length across all genomes.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Data badges no longer show false status indicators** — a `STARS` badge with value `6` rendered an orange warning diamond because the leading digit matched a threshold rule designed for percentages. Indicators now only appear on common build / test / CI / quality / deployment / monitoring titles (`BUILD`, `TESTS`, `CI`, `PIPELINE`, `WORKFLOW`, `COVERAGE`, `LINT`, `DEPLOY`, `RELEASE`, `STATUS`, `HEALTH`, `UPTIME`, etc.) or when explicitly set via `?state=`. Hyphen and underscore variants like `BUILD-STATUS` and `CI_CD` match the same canonical title without separate config entries.
|
|
15
|
+
- **Badge value text centers correctly across all genomes** — values drifted 1–3px right of true center, with automata badges drifting further than chrome and brutalist. Centering now verified within 0.5px across short percentages, version strings, license slugs, python_requires, and long names.
|
|
16
|
+
- **Monospace labels had extra padding on the right** — width measurement double-counted letter-spacing for mono labels like `BUILD` and `COVERAGE`; labels now match their actual rendered width.
|
|
17
|
+
- **Data-only strips drop the status diamond** — `STARS | FORKS | VERSION` strips render as pure data; mixed strips like `BUILD | STARS` keep the right-edge indicator; `?state=` always overrides.
|
|
18
|
+
|
|
19
|
+
### Notes
|
|
20
|
+
|
|
21
|
+
- 955 tests (was 914). Divider and icon URLs render unchanged; existing badge URLs continue to work, with corrected centering and tighter widths where false indicators were removed.
|
|
22
|
+
|
|
8
23
|
## [0.2.24] - 2026-05-07
|
|
9
24
|
|
|
10
25
|
Receipts no longer clip past the right edge of the card when one tool dominates the session. Cleanup pass removes an unused template, an unused styling table, and two silent default-position fallbacks in the receipt template.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperweave
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.25
|
|
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
|
|
@@ -51,6 +51,7 @@ Description-Content-Type: text/markdown
|
|
|
51
51
|
<img src="https://hyperweave.app/v1/badge/PYTHON/chrome.static?data=pypi:hyperweave.python_requires" alt="python"/>
|
|
52
52
|
</p>
|
|
53
53
|
-->
|
|
54
|
+
|
|
54
55
|
<p align="center">
|
|
55
56
|
<img src="https://hyperweave.app/v1/strip/hyperweave/chrome.static?data=gh:InnerAura/hyperweave.build,pypi:hyperweave.version,gh:InnerAura/hyperweave.license&glyph=github" alt="strip"/>
|
|
56
57
|
</p>
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
<img src="https://hyperweave.app/v1/badge/PYTHON/chrome.static?data=pypi:hyperweave.python_requires" alt="python"/>
|
|
20
20
|
</p>
|
|
21
21
|
-->
|
|
22
|
+
|
|
22
23
|
<p align="center">
|
|
23
24
|
<img src="https://hyperweave.app/v1/strip/hyperweave/chrome.static?data=gh:InnerAura/hyperweave.build,pypi:hyperweave.version,gh:InnerAura/hyperweave.license&glyph=github" alt="strip"/>
|
|
24
25
|
</p>
|
|
@@ -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.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 2,
|
|
21
|
+
__version__ = version = '0.2.25'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 25)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -117,6 +117,11 @@ def _base_context(
|
|
|
117
117
|
"slots": [s.model_dump() for s in spec.slots],
|
|
118
118
|
"numeric_value": spec.numeric_value,
|
|
119
119
|
"data_hw_value": spec.numeric_value,
|
|
120
|
+
# v0.2.25: SVG-root attribute that gates threshold-CSS auto-tinting.
|
|
121
|
+
# Default "off" = stateless; resolvers override via frame_context.
|
|
122
|
+
# Values: "off" (stateless), "auto" (stateful, threshold-CSS may fire),
|
|
123
|
+
# "explicit" (?state= set; user owns the state, no auto-inference).
|
|
124
|
+
"data_hw_statemode": "off",
|
|
120
125
|
# Profile
|
|
121
126
|
"profile": profile,
|
|
122
127
|
"badge_corner": profile.get("badge_corner", 3.33),
|
|
@@ -16,12 +16,25 @@ def compose(spec: ComposeSpec) -> ComposeResult:
|
|
|
16
16
|
# etc.) sets spec.state to something other than "active" and survives
|
|
17
17
|
# this step untouched. This is the single chokepoint covering HTTP,
|
|
18
18
|
# CLI, MCP, and kit.
|
|
19
|
-
|
|
19
|
+
#
|
|
20
|
+
# v0.2.25: gated on the stateful-title allowlist (data/badge_modes.yaml).
|
|
21
|
+
# Pre-v0.2.25 the inference fired on EVERY badge regardless of title —
|
|
22
|
+
# so a STARS=42 badge was auto-inferred to state="critical" (leading
|
|
23
|
+
# digit 4) and then re-classified as "explicit" mode by resolve_badge_mode,
|
|
24
|
+
# rendering an orange/red status indicator on a value with no semantic
|
|
25
|
+
# state. Now inference only fires for titles that meaningfully pass/fail
|
|
26
|
+
# (build / coverage / uptime / health / score / lint / ci / deploy / status).
|
|
27
|
+
if spec.state == "active" and spec.value and spec.title:
|
|
28
|
+
from hyperweave.compose.layout import normalize_title
|
|
29
|
+
from hyperweave.config.loader import load_badge_modes
|
|
20
30
|
from hyperweave.core.state import infer_state
|
|
21
31
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
# Normalize for separator-insensitive lookup (BUILD-STATUS,
|
|
33
|
+
# CI_CD, etc.) — same normalizer ``resolve_badge_mode`` uses.
|
|
34
|
+
if normalize_title(spec.title) in load_badge_modes():
|
|
35
|
+
inferred = infer_state(spec.title, spec.value)
|
|
36
|
+
if inferred != "active":
|
|
37
|
+
spec = spec.model_copy(update={"state": inferred})
|
|
25
38
|
|
|
26
39
|
# ── 1. Resolve genome, profile, frame ──
|
|
27
40
|
from hyperweave.compose.resolver import resolve
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
"""Centralized spatial-layout engine for badge / strip frames (v0.2.25).
|
|
2
|
+
|
|
3
|
+
Single source of truth for badge geometry. Replaces the inline arithmetic
|
|
4
|
+
that lived in ``compose/resolver.py:resolve_badge`` (lines 270-354) and
|
|
5
|
+
the duplicated geometry derivations in ``templates/frames/badge/*.j2``
|
|
6
|
+
(brutalist's right_x/right_w, cellular's inner_w/inner_off, the per-
|
|
7
|
+
template indicator_y duplicates).
|
|
8
|
+
|
|
9
|
+
Per Invariant 6 (CLAUDE.md): templates render, compose computes geometry.
|
|
10
|
+
Per ``feedback_compose_owns_geometry_template_renders.md``: layout
|
|
11
|
+
decisions belong in compose/, not Jinja2.
|
|
12
|
+
|
|
13
|
+
Two ``value_x`` regressions corrected by ``compute_badge_layout``:
|
|
14
|
+
|
|
15
|
+
1. **Geometric centering, not midpoint of unrelated bounds.** The old
|
|
16
|
+
resolver used ``value_x = (right_x + val_pad_l + indicator_x) / 2``,
|
|
17
|
+
which is the midpoint of [value_zone_left, indicator_left_edge].
|
|
18
|
+
Indicator's left edge is val_min_gap inside the actual value-zone
|
|
19
|
+
right boundary. Result: text drifts ``val_min_gap/2 = 1.5px``
|
|
20
|
+
rightward. The new formula centers on the actual zone center.
|
|
21
|
+
2. **No-indicator case is undefined under the old formula.** When the
|
|
22
|
+
indicator isn't rendered, ``indicator_x`` (still computed as
|
|
23
|
+
``total_w - ind_pad_r - indicator_size``) lands *inside* or *left
|
|
24
|
+
of* the value text. The old midpoint averages two unrelated points.
|
|
25
|
+
The new formula uses ``total_w - val_min_gap`` as the right bound
|
|
26
|
+
when ``show_indicator=False`` and converges to a sane center.
|
|
27
|
+
|
|
28
|
+
Three orthogonal helpers live here so all layout-and-mode decisions
|
|
29
|
+
share a module:
|
|
30
|
+
|
|
31
|
+
- ``compute_badge_layout`` — geometry only; pure function over input
|
|
32
|
+
measurements and paradigm constants.
|
|
33
|
+
- ``resolve_badge_mode`` — three-mode classification
|
|
34
|
+
(stateful / stateless / explicit) keyed off the spec and a title
|
|
35
|
+
allowlist loaded from ``data/badge_modes.yaml``.
|
|
36
|
+
- ``decide_strip_mode`` — same classification rolled up over a strip's
|
|
37
|
+
metric labels.
|
|
38
|
+
|
|
39
|
+
The data-hw-statemode SVG-root attribute that gates threshold-CSS
|
|
40
|
+
auto-tinting in ``data/css/expression.css`` is derived from the badge
|
|
41
|
+
mode via ``data_hw_statemode_for``.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
from __future__ import annotations
|
|
45
|
+
|
|
46
|
+
from dataclasses import dataclass
|
|
47
|
+
from typing import TYPE_CHECKING, Literal
|
|
48
|
+
|
|
49
|
+
if TYPE_CHECKING:
|
|
50
|
+
from collections.abc import Iterable
|
|
51
|
+
|
|
52
|
+
from hyperweave.core.models import ComposeSpec
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
BadgeMode = Literal["stateful", "stateless", "explicit"]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass(frozen=True)
|
|
59
|
+
class BadgeLayout:
|
|
60
|
+
"""Resolved spatial layout for a badge frame.
|
|
61
|
+
|
|
62
|
+
Templates consume these directly via ``{{ width }}``, ``{{ label_x }}``,
|
|
63
|
+
``{{ value_x }}``, etc. — no template-side arithmetic. The
|
|
64
|
+
``value_zone_*`` fields are exported for unit-test assertions.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
width: int
|
|
68
|
+
height: int
|
|
69
|
+
label_x: float
|
|
70
|
+
value_x: float
|
|
71
|
+
glyph_x: int
|
|
72
|
+
glyph_y: float
|
|
73
|
+
indicator_x: float
|
|
74
|
+
indicator_y: float
|
|
75
|
+
indicator_size: int
|
|
76
|
+
left_panel_w: int
|
|
77
|
+
right_panel_x: int
|
|
78
|
+
right_panel_w: int
|
|
79
|
+
value_zone_left: float
|
|
80
|
+
value_zone_right: float
|
|
81
|
+
value_zone_width: float
|
|
82
|
+
text_y: float
|
|
83
|
+
show_indicator: bool
|
|
84
|
+
inner_bit_w: int
|
|
85
|
+
inner_bit_offset: float
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def compute_badge_layout(
|
|
89
|
+
*,
|
|
90
|
+
height: int,
|
|
91
|
+
measured_label_w: float,
|
|
92
|
+
measured_value_w: float,
|
|
93
|
+
has_glyph: bool,
|
|
94
|
+
show_indicator: bool,
|
|
95
|
+
use_mono: bool,
|
|
96
|
+
label_uppercase: bool,
|
|
97
|
+
value_raw_len: int,
|
|
98
|
+
accent_w: int,
|
|
99
|
+
inset: int,
|
|
100
|
+
glyph_size: int,
|
|
101
|
+
glyph_gap: int,
|
|
102
|
+
glyph_left_offset: int,
|
|
103
|
+
sep_w: int,
|
|
104
|
+
seam_w: int,
|
|
105
|
+
indicator_size: int,
|
|
106
|
+
ind_pad_r: int,
|
|
107
|
+
val_pad_l: int,
|
|
108
|
+
val_min_gap: int,
|
|
109
|
+
text_y_factor: float,
|
|
110
|
+
value_font_size: float,
|
|
111
|
+
right_canvas_inset: int = 0,
|
|
112
|
+
min_total_w: int = 60,
|
|
113
|
+
) -> BadgeLayout:
|
|
114
|
+
"""Compute every position the badge templates need from input measurements.
|
|
115
|
+
|
|
116
|
+
All positional fields in the returned ``BadgeLayout`` are measured
|
|
117
|
+
from the SVG origin (top-left). Geometry decisions (left/right panel
|
|
118
|
+
widths, indicator centering, glyph centering, value-zone centering)
|
|
119
|
+
are made here so all paradigms inherit the same correctness without
|
|
120
|
+
re-deriving in templates.
|
|
121
|
+
|
|
122
|
+
The centering correctness is verified by ``tests/test_badge_layout``
|
|
123
|
+
against short / long / version / license / python_requires values.
|
|
124
|
+
"""
|
|
125
|
+
# Glyph pixel position. Mirrors resolver.py logic: paradigms with a
|
|
126
|
+
# left-edge decoration zone (cellular pattern strip x=2..~20) reserve
|
|
127
|
+
# space via ``glyph_left_offset``; brutalist/chrome declare 0.
|
|
128
|
+
if has_glyph:
|
|
129
|
+
glyph_x = (inset + accent_w + 4) if inset else (accent_w + 3)
|
|
130
|
+
glyph_x += glyph_left_offset
|
|
131
|
+
glyph_y = round((height - glyph_size) / 2, 1)
|
|
132
|
+
else:
|
|
133
|
+
glyph_x, glyph_y = 0, 0.0
|
|
134
|
+
|
|
135
|
+
# Label area starts after the glyph (or after the accent + paradigm
|
|
136
|
+
# left-edge decoration when there's no glyph). The no-glyph branch
|
|
137
|
+
# must respect glyph_left_offset too — cellular pattern strip runs
|
|
138
|
+
# to ~x=20 even when no glyph is rendered.
|
|
139
|
+
label_start = (glyph_x + glyph_size + glyph_gap) if has_glyph else (accent_w + 6 + glyph_left_offset)
|
|
140
|
+
|
|
141
|
+
# Left panel width — fits the label plus paradigm-driven right padding.
|
|
142
|
+
label_pad_r = 9 if use_mono else 8
|
|
143
|
+
left_panel = round(label_start + measured_label_w + label_pad_r)
|
|
144
|
+
left_panel = max(left_panel, 30)
|
|
145
|
+
|
|
146
|
+
# Label text center is the midpoint of the label area. For uppercase
|
|
147
|
+
# labels the visual right edge is 6px shy of the panel boundary so
|
|
148
|
+
# the cap glyphs don't kiss the seam.
|
|
149
|
+
label_area_end = left_panel - (6 if label_uppercase else 0)
|
|
150
|
+
label_x = round((label_start + label_area_end) / 2, 1)
|
|
151
|
+
|
|
152
|
+
# Right-panel allocation. ``ls_extra`` accounts for non-mono letter-
|
|
153
|
+
# spacing overrun (each char carries 0.4 of trailing tracking).
|
|
154
|
+
indicator_alloc = (indicator_size + ind_pad_r) if show_indicator else 0
|
|
155
|
+
ls_extra = value_raw_len * 0.4 if (not use_mono and value_raw_len) else 0
|
|
156
|
+
right_panel = val_pad_l + measured_value_w + ls_extra + 2 * val_min_gap + indicator_alloc
|
|
157
|
+
total_w = round(left_panel + sep_w + seam_w + right_panel)
|
|
158
|
+
total_w = max(total_w, min_total_w)
|
|
159
|
+
|
|
160
|
+
right_panel_x = left_panel + sep_w + seam_w
|
|
161
|
+
right_panel_w = total_w - right_panel_x
|
|
162
|
+
|
|
163
|
+
# Indicator position. Computed even when not shown — templates
|
|
164
|
+
# gate the actual rendering on ``show_indicator``; the value-zone
|
|
165
|
+
# center collapses to total_w-val_min_gap when the indicator is
|
|
166
|
+
# absent so the value text reclaims the freed space.
|
|
167
|
+
indicator_x = total_w - ind_pad_r - indicator_size
|
|
168
|
+
|
|
169
|
+
# Value-zone bounds — the heart of the v0.2.25 centering fix. The
|
|
170
|
+
# OLD resolver used ``(right_panel_x + val_pad_l + indicator_x) / 2``
|
|
171
|
+
# which is the midpoint of [zone_left, indicator_left_edge], not
|
|
172
|
+
# [zone_left, zone_right]. Old formula skewed text by val_min_gap/2
|
|
173
|
+
# toward the indicator and was undefined when no indicator rendered.
|
|
174
|
+
value_zone_left = right_panel_x + val_pad_l
|
|
175
|
+
# When stateless (no indicator), the slab's right edge is total_w minus
|
|
176
|
+
# any paradigm-specific canvas inset (cellular: 2; brutalist/chrome: 0).
|
|
177
|
+
# val_min_gap is the symmetric trailing pad — together they place
|
|
178
|
+
# value_zone_right at the slab's interior right boundary so a centered
|
|
179
|
+
# text lands at slab geometric center.
|
|
180
|
+
value_zone_right = (indicator_x - val_min_gap) if show_indicator else (total_w - right_canvas_inset - val_min_gap)
|
|
181
|
+
value_zone_width = value_zone_right - value_zone_left
|
|
182
|
+
value_x = round((value_zone_left + value_zone_right) / 2, 1)
|
|
183
|
+
|
|
184
|
+
text_y = round(height * text_y_factor, 1)
|
|
185
|
+
# Indicator vertical center pinned to value-text visual midline.
|
|
186
|
+
# cap_height ≈ 70% of font_size across the genome's display fonts
|
|
187
|
+
# (validated in data/font-metrics/), so visual_center = text_y -
|
|
188
|
+
# 0.3 * font_size. Indicator is square; top-y = visual_center -
|
|
189
|
+
# size/2. Single source of truth for vertical alignment across
|
|
190
|
+
# paradigms.
|
|
191
|
+
indicator_y = round(text_y - value_font_size * 0.3 - indicator_size / 2, 1)
|
|
192
|
+
|
|
193
|
+
# Indicator inner-bit geometry — moved from cellular/brutalist
|
|
194
|
+
# template-side arithmetic. The bit is half the indicator side,
|
|
195
|
+
# centered.
|
|
196
|
+
inner_bit_w = indicator_size // 2
|
|
197
|
+
inner_bit_offset = (indicator_size - inner_bit_w) / 2
|
|
198
|
+
|
|
199
|
+
return BadgeLayout(
|
|
200
|
+
width=total_w,
|
|
201
|
+
height=height,
|
|
202
|
+
label_x=label_x,
|
|
203
|
+
value_x=value_x,
|
|
204
|
+
glyph_x=glyph_x,
|
|
205
|
+
glyph_y=glyph_y,
|
|
206
|
+
indicator_x=indicator_x,
|
|
207
|
+
indicator_y=indicator_y,
|
|
208
|
+
indicator_size=indicator_size,
|
|
209
|
+
left_panel_w=left_panel,
|
|
210
|
+
right_panel_x=right_panel_x,
|
|
211
|
+
right_panel_w=right_panel_w,
|
|
212
|
+
value_zone_left=value_zone_left,
|
|
213
|
+
value_zone_right=value_zone_right,
|
|
214
|
+
value_zone_width=value_zone_width,
|
|
215
|
+
text_y=text_y,
|
|
216
|
+
show_indicator=show_indicator,
|
|
217
|
+
inner_bit_w=inner_bit_w,
|
|
218
|
+
inner_bit_offset=inner_bit_offset,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# ─────────────────────────────────────────────────────────────────────
|
|
223
|
+
# Three-mode state architecture
|
|
224
|
+
# ─────────────────────────────────────────────────────────────────────
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def normalize_title(title: str | None) -> str:
|
|
228
|
+
"""Lowercase + strip hyphens/underscores so allowlist lookup is
|
|
229
|
+
insensitive to common separator variants.
|
|
230
|
+
|
|
231
|
+
``BUILD-STATUS`` → ``buildstatus``; ``CI_CD`` → ``cicd``. URL slashes
|
|
232
|
+
can't appear in path segments (they'd split into separate parts), so
|
|
233
|
+
we don't need slash handling. Empty / None → empty string.
|
|
234
|
+
"""
|
|
235
|
+
if not title:
|
|
236
|
+
return ""
|
|
237
|
+
return title.lower().replace("-", "").replace("_", "")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def resolve_badge_mode(spec: ComposeSpec, allowlist: frozenset[str]) -> BadgeMode:
|
|
241
|
+
"""Classify a badge as stateful / stateless / explicit.
|
|
242
|
+
|
|
243
|
+
Three modes drive two orthogonal behaviors at render time:
|
|
244
|
+
|
|
245
|
+
* Indicator rendering: ``show_indicator = mode != "stateless"``
|
|
246
|
+
* Threshold-CSS auto-inference: gated by ``data-hw-statemode="auto"``
|
|
247
|
+
on the SVG root, which fires only for ``stateful`` (auto-inferred
|
|
248
|
+
from leading-digit value). ``stateless`` and ``explicit`` skip it.
|
|
249
|
+
|
|
250
|
+
Title lookup normalizes via ``normalize_title`` (lowercase, strip
|
|
251
|
+
hyphens/underscores) so ``BUILD-STATUS`` and ``BUILD_STATUS`` both
|
|
252
|
+
match the canonical ``buildstatus`` allowlist entry without bloating
|
|
253
|
+
the YAML with every separator variant.
|
|
254
|
+
|
|
255
|
+
Note on ``spec.state == "active"``: ComposeSpec defaults ``state`` to
|
|
256
|
+
the truthy sentinel ``"active"`` (Pydantic default in
|
|
257
|
+
core/models.py:98), NOT empty string. Treat that sentinel as "user
|
|
258
|
+
did not opine" — fall through to the allowlist check. Any other
|
|
259
|
+
value (including ``"active"`` if explicitly re-set, which is fine)
|
|
260
|
+
means the caller asked for a specific state → explicit mode.
|
|
261
|
+
"""
|
|
262
|
+
if spec.state and spec.state != "active":
|
|
263
|
+
return "explicit"
|
|
264
|
+
title = normalize_title(spec.title)
|
|
265
|
+
if title and title in allowlist:
|
|
266
|
+
return "stateful"
|
|
267
|
+
return "stateless"
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def decide_strip_mode(
|
|
271
|
+
metric_titles: Iterable[str | None],
|
|
272
|
+
spec: ComposeSpec,
|
|
273
|
+
allowlist: frozenset[str],
|
|
274
|
+
) -> BadgeMode:
|
|
275
|
+
"""Roll up the strip's mode from its metric cells' titles.
|
|
276
|
+
|
|
277
|
+
Strip's right-edge indicator is the strip's overall health pixel.
|
|
278
|
+
If ANY metric is stateful, the indicator renders with rolled-up
|
|
279
|
+
state. Stateless cells coexist; per-cell indicators were already
|
|
280
|
+
rejected (memory: ``feedback_strip_single_diamond.md``).
|
|
281
|
+
|
|
282
|
+
Metric titles are normalized via ``normalize_title`` for the same
|
|
283
|
+
reasons as ``resolve_badge_mode`` — ``BUILD-STATUS`` cell matches
|
|
284
|
+
the same canonical ``buildstatus`` allowlist entry.
|
|
285
|
+
"""
|
|
286
|
+
if spec.state and spec.state != "active":
|
|
287
|
+
return "explicit"
|
|
288
|
+
for title in metric_titles:
|
|
289
|
+
if title and normalize_title(title) in allowlist:
|
|
290
|
+
return "stateful"
|
|
291
|
+
return "stateless"
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def data_hw_statemode_for(mode: BadgeMode) -> str:
|
|
295
|
+
"""Map ``BadgeMode`` to the SVG-root ``data-hw-statemode`` attribute value.
|
|
296
|
+
|
|
297
|
+
The CSS in ``data/css/expression.css`` qualifies its threshold
|
|
298
|
+
selectors with ``[data-hw-statemode="auto"]`` so auto-inference
|
|
299
|
+
only applies to ``stateful``. ``stateless`` ("off") and ``explicit``
|
|
300
|
+
("explicit") bypass auto-tinting; explicit-mode badges still get
|
|
301
|
+
state colors via the ``[data-hw-status="..."]`` cascade.
|
|
302
|
+
"""
|
|
303
|
+
return {"stateful": "auto", "explicit": "explicit", "stateless": "off"}[mode]
|