Skip to content

docs: footer trademark notices scan different text than rehype-trademarks marks #497

Description

@EricAndrechek

Raised by CodeRabbit on #489 (docs/src/components/Footer.astro:51), and independently noticed-but-not-raised by the pre-push-reviewer gate on the same branch. Filing rather than folding in, because the fix is a design decision rather than a review nit.

The invariant, and how it breaks

Trademarks.astro states the contract in its own header:

The marks and their owners live in src/config/trademarks.ts, shared with src/plugins/rehype-trademarks.ts — the pass that puts the matching ® / ™ on the first mention in the prose above. One registry, so the footer can't promise a notice the prose didn't mark, or vice versa.

Both sides read one registry, but they scan different text:

  • rehype-trademarks.ts walks the rendered HTML and deliberately skips code, pre, kbd, samp, var, h1–h6, .katex, .expressive-code, and the LinkButton/LinkCard components — each for a good reason (a ® inside a copy-pasteable command is wrong; marking a heading desyncs it from the TOC that was collected before the plugin runs).
  • Footer.astro builds its notice list from pageText(entry.data, entry.body ?? "") — the raw Markdown/MDX body, which contains all of those.

So a mark named only inside a heading or a fenced block produces a footer notice with no matching symbol anywhere in the prose. Live example: docs/src/content/docs/architecture.md mentions OpenTelemetry only in excluded structures, and still emits an OpenTelemetry notice.

The direction is the safe one — over-attributing is better than claiming a mark the page never names — which is why it isn't blocking. But it is precisely the mismatch the component says can't happen.

Options

  1. Have the plugin publish the marks it actually matched (per page) and let the footer render notices from that set. Exact by construction, and the invariant becomes structural rather than a comment. Costs a build-time channel from the rehype pass to the footer component.
  2. Teach pageText() the same exclusions — strip fenced/inline code and ATX/setext headings from the body before scanning. Cheaper, no plumbing, but it duplicates the eligibility rules in a second place and they will drift.
  3. Weaken the documented invariant to "the footer may name a mark the prose didn't symbol-mark, never the reverse," and say why. Zero code, but gives up a property worth having.

Option 1 is the one that actually holds the line; option 2 is the pragmatic version if the plumbing isn't worth it.

Also in scope while there

Trademarks.astro derives from entry.body, so a mark appearing only inside a code fence still yields a footer notice — the same root cause, and it would be fixed by the same change.

Activity

  1. coderabbitai commented on Aug 19, 2026

    @coderabbitai
    🔗 Related PRs

    #142 - feat(docs): rebuild site with wavehouse logo and design tokens [closed]
    #187 - docs: prep docs for publishing [closed]
    #313 - feat(docs): view-transition polish, branded search + 404, chrome pass [closed]
    #368 - feat(docs): override Starlight header with a top-level site nav [merged]
    #489 - build(docs): cloud referrals, standard fmt, and markdown lint rules [open]


    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. EricAndrechek commented on Oct 9, 2026

    @EricAndrechek
    MemberAuthor

    This is fixed by design in the new public package @wave-rf/astro-trademarks, which is option 1 above: the notices are built from the same scan that places the symbols, over the rendered HTML, so they can't diverge. The package has a test that fails if they ever do.

    Measured, not inferred. I ran the package's HTML pass over this repo's built docs/dist/architecture/index.html, the page this issue cites, with src/config/trademarks.ts's real TRADEMARKS and the planned config (skipClasses: [defaults, Starlight preset, "not-content"]):

    Notices
    Today's footer (raw body) ClickHouse, NATS, Redis, OpenTelemetry, Prometheus, Hasura, Amazon Web Services, Kubernetes, Docker
    The package ClickHouse, NATS, Prometheus, Hasura, Docker, Claude

    OpenTelemetry, Redis, AWS and Kubernetes appear only in headings or code on that page, and they drop out.

    The Claude hit is a false positive. It comes from the starlight-llm-tools "Open with AI" dropdown inside <main>. The adoption config below skips it with sllm-links, and the proper fix is tracked in starlight-llm-tools (Wave-RF/starlight-llm-tools#11).

    Adoption, once the package is on npm (the first publish is a manual bootstrap):

    • Delete src/plugins/rehype-trademarks.ts and src/components/Trademarks.astro. In src/config/trademarks.ts, keep only the registry: wrap TRADEMARKS in defineTrademarks, and drop heroText, pageText, PageFrontmatter and the matchers. Drop rehypeTrademarks from rehypePlugins.
    • Add trademarks({ marks, skipClasses: ["not-content", "sllm-links"] }) to the integrations. The Starlight preset is auto-detected.
    • In Footer.astro, replace <Trademarks source={…} /> and pageText with:
      <TrademarkNotices
        catchAll="All other product names, logos, and brands are the property of their respective owners."
        disclaimer="WaveHouse is an independent open-source project and is not affiliated with, endorsed by, or sponsored by the trademark holders named above."
      />
    • In Hero.astro, drop markFirstMentions and render the tagline as plain text. Starlight's hero is inside <main>, so the middleware marks it.
    • Styles: keep .wh-tm via symbolClass: "wh-tm", or drop it, since the defaults match. Map .wh-legal onto --tm-notices-font-size: 0.75rem; --tm-notices-line-height: 1.5; --tm-notices-color: var(--wh-ink-subtle).
    • Trade-off to accept: Cloud CTA copy in the footer (not-content) gets neither a symbol nor a notice. Counting it without marking it was this issue's bug.
    • The .md twins and llms*.txt are left untouched by default (the machineReadable option is off).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions