Skip to content

refactor(website): finish the json-render rename; generalise style contracts - #926

Merged
blove merged 1 commit into
mainfrom
blove/json-render-marketing-and-style-contracts
Sep 1, 2026
Merged

refactor(website): finish the json-render rename; generalise style contracts#926
blove merged 1 commit into
mainfrom
blove/json-render-marketing-and-style-contracts

Conversation

@blove

@blove blove commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Two follow-ups from #923.

1 — json-render on marketing surfaces

#923 renamed the docs picker but deliberately left marketing alone. They now agree: the homepage FeatureBlock eyebrow, the footer link, and the three solutions architecture layers all read json-render. Verified in the browser — no bare "Render" remains on /, /solutions/*, or the footer.

Two hazards this surfaced, both silent:

  • The footer derives cta_id from the visible label. Renaming the link would have turned footer_render into footer_json_render and split the PostHog series with no error. trackFooterCta now takes an optional explicit CtaId and the render link pins the original id, so the analytics series stays continuous while the text changes.
  • The solutions page maps library name → href through Record<string, string>. Renaming the data without the key returns undefined and renders the card unlinked — no error, no type failure, nothing visible in review. solutions-links.spec.ts asserts every layer resolves; mutation-tested by renaming one side only, and it correctly reports [ 'json-render', 'json-render', 'json-render' ] unresolved.

2 — Generalising the style contract

docs-sidebar-styles.spec.ts guarded two CSS declarations jsdom can't see, but it was a one-off with an inline parser. Replaced by style-contract.ts plus a registry in style-contracts.spec.ts, so adding a guard is one entry rather than a new file — with a documented bar for what belongs (the tell is "you wrote a CSS comment explaining why a declaration must not be removed") and an explicit warning against adding ordinary styling, since a contract that fires on every design tweak teaches people to delete contracts.

Seeded with four live rules:

Selector Guards Silent failure
.docs-sidebar-lib-item-text flex column The #892 collision that shipped
.docs-sidebar-lib-menu max-height, overflow-y Menu runs past the fold
.docs-control-plane position sticky, align-self Stretches to article height; internal scroll dies
[data-control-plane-pane] overflow-y Lower nav unreachable on short viewports

Every contract was mutation-tested by deleting the declaration and by renaming the selector wholesale. The first attempt at the rename mutation was invalid — .docs-sidebar-lib-menu has two rule blocks and I renamed only one, so the contract stayed green for a legitimate reason. Redone against both.

Writing the registry also found a bug in the extracted parser: a CSS comment above a rule lands inside the selector capture, so the exact match never fires and a guarded rule reports as missing. That would have produced a false failure the moment someone documented the rule a contract guards. Comments are stripped first.

Dead code

Removes the DocsSidebar wrapper and its .docs-sidebar rule — dead since #892 moved the docs nav into the control plane. Only DocsNavigation is imported, and the sole .docs-sidebar class usage was inside the dead component. Its comment documented the same align-self hazard now held by the .docs-control-plane contract, so the knowledge is kept rather than deleted.

Testing

432 tests pass, 0 lint errors, production build green.

🤖 Generated with Claude Code

…ntracts

Two follow-ups from #923.

json-render on marketing surfaces
---------------------------------
#923 renamed the docs picker label but deliberately left the marketing
surfaces. They now agree: the homepage FeatureBlock eyebrow, the footer
link, and the three solutions architecture layers all read json-render.

Two hazards this surfaced:

- The footer derives cta_id from the visible label, so renaming the link
  would have silently split PostHog's footer_render into a new
  footer_json_render series. trackFooterCta now takes an optional
  explicit CtaId and the render link pins the original.
- The solutions page maps library name to href through a
  Record<string, string>. Renaming the data without the key returns
  undefined and renders the card unlinked — no error, no type failure.
  solutions-links.spec.ts asserts every layer resolves; mutation-tested
  by renaming one side only.

Style contracts
---------------
docs-sidebar-styles.spec.ts guarded two CSS declarations whose loss is
invisible to jsdom, but it was a one-off with an inline parser. It is
replaced by style-contract.ts plus a registry in style-contracts.spec.ts,
so adding a guard is one entry rather than a new file.

Seeded with four live rules, each mutation-tested by deleting the
declaration and by renaming the selector wholesale:

- .docs-sidebar-lib-item-text     flex column (the #892 collision)
- .docs-sidebar-lib-menu          max-height + overflow-y
- .docs-control-plane             position sticky + align-self
- [data-control-plane-pane]       overflow-y

Writing the registry found a bug in the extracted parser: a CSS comment
above a rule lands inside the selector capture, so the exact match never
fires and a guarded rule reports as missing. Comments are stripped first.

Also removes the DocsSidebar wrapper and its .docs-sidebar rule, dead
since #892 moved the docs nav into the control plane — only
DocsNavigation is imported, and the sole class usage was inside the dead
component. Its comment documented the same align-self hazard now held by
the .docs-control-plane contract.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
threadplane Ready Ready Preview Sep 1, 2026 5:39am UTC

Request Review

@blove
blove enabled auto-merge (squash) September 1, 2026 05:37

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval: this PR received an intelligent (AI) code review. See the review comments on this PR.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@blove
blove merged commit b80b0e2 into main Sep 1, 2026
65 checks passed
blove added a commit that referenced this pull request Sep 1, 2026
PR #863 deleted the global `.shiki` rules from docs.css on the finding that
zero elements matched. That was true of docs and blog — rehype-pretty-code
writes its background inline and never emits a `.shiki` class — but two TSX
call sites highlight with Shiki's `codeToHtml` directly, which does:

  - components/landing/HighlightedCode.tsx  (homepage Code tabs, /langgraph,
    /render, /chat)
  - components/solutions/SolutionCodeBlock.tsx  (every /solutions/* page)

Those <pre> elements lost their padding. The dark theme background rides
inline on the <pre>, while the landing override put its 16px 20px on the
wrapper <div> (which carries `shiki` too) — outside the dark box. The result
was a light gutter with the code flush against the dark edges.

Restores the padding as a `pre.shiki` base rule in global.css, and moves the
landing override's padding off the wrapper onto `> pre.shiki`. The selector is
pre-scoped deliberately: both call sites also put the class on a wrapper div,
where padding lands outside the surface. SolutionCodeBlock's comment claimed
Shiki emits its own padding — that wrong premise is what made the deletion
look safe, so it is corrected too.

Guarded in two halves, since neither is sufficient alone. The CSS half is a
style contract (#926's registry — this is precisely the "comment explaining
why a declaration must not be removed" that it asks for), mutation-tested by
deleting the declaration and by renaming the selector. The markup half lives
in HighlightedCode.spec.tsx: that Shiki still emits a `pre.shiki` carrying an
inline background and no padding of its own, so the contract keeps guarding a
rule something actually matches.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
blove added a commit that referenced this pull request Sep 1, 2026
PR #863 deleted the global `.shiki` rules from docs.css on the finding that
zero elements matched. That was true of docs and blog — rehype-pretty-code
writes its background inline and never emits a `.shiki` class — but two TSX
call sites highlight with Shiki's `codeToHtml` directly, which does:

  - components/landing/HighlightedCode.tsx  (homepage Code tabs, /langgraph,
    /render, /chat)
  - components/solutions/SolutionCodeBlock.tsx  (every /solutions/* page)

Those <pre> elements lost their padding. The dark theme background rides
inline on the <pre>, while the landing override put its 16px 20px on the
wrapper <div> (which carries `shiki` too) — outside the dark box. The result
was a light gutter with the code flush against the dark edges.

Restores the padding as a `pre.shiki` base rule in global.css, and moves the
landing override's padding off the wrapper onto `> pre.shiki`. The selector is
pre-scoped deliberately: both call sites also put the class on a wrapper div,
where padding lands outside the surface. SolutionCodeBlock's comment claimed
Shiki emits its own padding — that wrong premise is what made the deletion
look safe, so it is corrected too.

Guarded in two halves, since neither is sufficient alone. The CSS half is a
style contract (#926's registry — this is precisely the "comment explaining
why a declaration must not be removed" that it asks for), mutation-tested by
deleting the declaration and by renaming the selector. The markup half lives
in HighlightedCode.spec.tsx: that Shiki still emits a `pre.shiki` carrying an
inline background and no padding of its own, so the contract keeps guarding a
rule something actually matches.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@blove
blove deleted the blove/json-render-marketing-and-style-contracts branch September 1, 2026 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant