Skip to content

Add a derived docs link to every changelog entry - #19739

Open
joethreepwood wants to merge 5 commits into
masterfrom
posthog/changelog-docs-links
Open

Add a derived docs link to every changelog entry#19739
joethreepwood wants to merge 5 commits into
masterfrom
posthog/changelog-docs-links

Conversation

@joethreepwood

@joethreepwood joethreepwood commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Changes

Changelog entries only link to their docs page when the author happens to write a /docs link into the description text. There is no automatic mechanism — that is why some entries show a docs link and others do not.

This PR derives a docs link for every entry, in priority order:

  1. An explicit CTA that points at /docs
  2. The first /docs link written into the description
  3. The entry topic's docs home page, via a new topic-slug → docs-path map (src/components/Changelog/docsLinks.ts)

The derived link shows in three places:

  • A Read the docs button in the changelog side panel, directly under the entry description and above the emoji reactions (hidden when it would duplicate the entry's CTA)
  • The server-rendered entry list that crawlers and agents see, which now also shows the entry topic and links each entry's date to its canonical /changelog?id= URL
  • The generated changelog.md and per-year archives, where each entry title now links to its canonical URL and a Docs link is appended, so agents that read the Markdown can follow entries to the docs

Strapi CTA import (added after review)

Review feedback proposed to import the docs links into the Strapi CTA field. This PR now includes that import as scripts/import-changelog-docs-ctas.ts, and keeps the derived link as the fallback layer:

  • The script finds each completed entry that has an empty CTA and a /docs link in its own description, and writes that link to the CTA field as "Read the docs".
  • It imports only these high-confidence links. The generic topic fallbacks stay derived at render time, so they update centrally when docs URLs move and do not become stale data in Strapi.
  • It is a dry run by default and prints the planned writes. Pass --write with STRAPI_TOKEN set to apply. A dry run against production data found 1,067 changelog entries, of which 421 get a CTA from the import.
  • After the import, the derived button hides itself for imported entries, because the de-dup guard sees the docs link in the CTA. The rendered result is identical.

Run it with:

npx --yes tsx@4.20.6 scripts/import-changelog-docs-ctas.ts            # dry run
STRAPI_TOKEN=... npx --yes tsx@4.20.6 scripts/import-changelog-docs-ctas.ts --write

How new entries get a link going forward

Links are derived at build time, not stored, so every deploy re-computes them:

  • A new entry with a mapped topic gets a docs link automatically on the next deploy, with no action from anyone. This also applied retroactively to all historical entries.
  • The topic fallback is only as good as the topic tag. An entry tagged with an adjacent topic gets that topic's docs home, not the most specific page. Retagging the entry in Strapi fixes the link on the next deploy.
  • A brand-new topic that is not yet in the map produces no link until someone adds one line to CHANGELOG_TOPIC_DOCS.

Suggested upstream fixes

The biggest wins are upstream of this repo, in the automation that authors changelog entries from merged PRs:

  • Write a docs CTA (or an inline /docs link) into new entries when a clearly relevant page exists. The derivation order rewards this — an author-chosen link beats the topic fallback, and it is how an entry can point at the exact page (e.g. a Slack-related entry linking /docs/slack even when the entry is tagged with a broader topic).
  • Pick the most specific topic available when tagging entries, and create product-specific topics where they are missing.
  • Longer term, move the mapping into Strapi: add a docsUrl field to the topic content type and have the build read it. New topics then carry their docs home from day one, content owners maintain it, and CHANGELOG_TOPIC_DOCS can be retired. Alternative: a build-time convention fallback that uses /docs/<topic-slug> when that page exists, which covers topics whose slug matches a docs path.

Screenshots

CleanShot 2026-08-26 at 10 33 22@2x

Checklist

  • I've read the docs and/or content style guides.
  • Words are spelled using American English
  • Use relative URLs for internal links
  • I've checked the pages added or changed in the Vercel preview build
  • If I moved a page, I added a redirect in vercel.json

Why: Some changelog entries link to their docs and some do not, and the changelog is hard for agents to consume. This makes the docs link consistent, visible in the side panel, and readable by MCP clients and agents.


Created with PostHog Desktop

Changelog entries only linked to docs when the author wrote a docs link
into the description text. Derive a docs link for every entry instead:
an explicit docs CTA wins, then the first /docs link in the description,
then the entry topic's docs home page.

Show the link as a "Read the docs" button at the bottom of the changelog
side panel, in the server-rendered entry list, and in the generated
changelog.md files. Also link each entry in changelog.md and the
server-rendered list to its canonical URL so agents can address single
entries.

Generated-By: PostHog Desktop
Task-Id: b1606fd1-83d7-4755-b4dc-ed10f1ee6200
@github-actions github-actions Bot added the website About the website (beyond just landing pages) label Aug 26, 2026
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Deploy preview

Status Details Updated (UTC)
🟢 Ready View preview Sep 05, 2026 05:35PM

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Bundle report

Total JS (gzip)

8.16 MiB (+0.7 KiB / +0.0%)

Eager graph (modules shipped in each entrypoint's initial chunks)

Entrypoint Eager size Budget Modules
app 18.42 MiB (no change) report-only 2052
Largest modules in the app closure
Module Size
./src/data/mcp-tools.json 1081.9 KiB
css ./node_modules/.pnpm/css-loader@5.2.7_webpack@5.101.3/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[1]!./node_modules/.pnpm/postcss-loader@4.3.0_postcss@8.5.6_webpack@5.101.3/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[2]!./src/styles/global.css 758.7 KiB
./src/components/Stickers/Stickers.tsx 696.4 KiB
./node_modules/.pnpm/@radix-ui+react-icons@1.3.2_react@18.3.1/node_modules/@radix-ui/react-icons/dist/react-icons.esm.js 481.4 KiB
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/x-ray.mjs 480.8 KiB
./node_modules/.pnpm/rehype-raw@7.0.0/node_modules/rehype-raw/lib/index.js + 29 modules 395.1 KiB
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/im-the-driver.mjs 385.7 KiB
./src/hooks/useCustomers.tsx + 55 modules 370.0 KiB
./node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js 354.8 KiB
./node_modules/.pnpm/react-markdown@8.0.7_@types+react@16.14.66_react@18.3.1/node_modules/react-markdown/lib/react-markdown.js + 88 modules 351.4 KiB
./src/components/ProductComparisonTable/index.tsx + 126 modules 301.8 KiB
./node_modules/.pnpm/cloudinary-core@2.14.0_lodash@4.17.21/node_modules/cloudinary-core/cloudinary-core.js 281.9 KiB
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/doll-house.mjs 281.7 KiB
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/director.mjs 275.6 KiB
./src/components/SearchUI/index.tsx + 87 modules 273.0 KiB

Eager-graph budgets are report-only until a baseline is established. Sizes are gzip of public/**/*.js; eager size is webpack module source bytes for the modules actually shipped in the entrypoint's initial chunks (post-tree-shake).

Move the side panel's "Read the docs" button out of the pinned footer
and place it directly under the entry description, above the emoji
reactions, so it reads as part of the entry. Also open the static-list
docs link in a new window, matching the site's link convention.

Generated-By: PostHog Desktop
Task-Id: b1606fd1-83d7-4755-b4dc-ed10f1ee6200
@joethreepwood
joethreepwood requested a review from a team August 26, 2026 14:29
@joethreepwood

Copy link
Copy Markdown
Contributor Author

Before
Screenshot 2026-08-26 at 15 28 59

After
Screenshot 2026-08-26 at 15 29 16

@joethreepwood
joethreepwood marked this pull request as ready for review August 26, 2026 14:30
@joethreepwood
joethreepwood requested a review from a team as a code owner August 26, 2026 14:30
@joethreepwood joethreepwood self-assigned this Aug 26, 2026

@sarahxsanders sarahxsanders 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.

like the button approach, good backup for when the robot can't add a link

question though: should we just favor this? and I remove the step in the robot to add links?

@joethreepwood

Copy link
Copy Markdown
Contributor Author

I'm a belt and braces guy personally, but up to you.

@joethreepwood
joethreepwood enabled auto-merge (squash) September 4, 2026 12:40

@smallbrownbike smallbrownbike left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

think we can just import these docs links into Strapi under the CTA field, and it will show up basically the same with no code changes. then maybe future changelog entries we can automatically add the docs link to the CTA field when creating?

Copy link
Copy Markdown
Contributor Author

Agent status note (automated maintenance run — not a reply on the author's behalf):

  • CI is green on the latest commit, the branch is up to date with master, and there are no open inline review threads.
  • The one remaining blocker is the changes-requested review, which proposes to import the docs links into the Strapi CTA field instead of this code. That needs Strapi access and a product decision, so it stays with the humans on this PR.

Two facts from the code that may help the decision:

  1. An entry has one CTA slot. An entry whose CTA already points somewhere else (for example, into the app) cannot also carry a docs link through a CTA import. This PR shows the docs link next to the CTA when the two differ, and its derivation prefers a docs CTA when one exists — so imported CTAs take precedence over the topic fallback if both ship. The two approaches are compatible.
  2. Until the entry-creation automation writes docs CTAs, only the topic fallback in this PR gives a new entry a docs link on day one.

I will make no further changes until this is decided.

🦉 via talyn.dev

Generated-By: PostHog Desktop
Task-Id: 7e545b76-4db9-4738-92e0-9de6c1fbde1c

Copy link
Copy Markdown
Contributor Author

@smallbrownbike Thanks — I checked how a Strapi CTA import interacts with this PR. The two approaches work together rather than against each other:

  • The derivation in docsLinks.ts gives first priority to an explicit docs CTA. The "Read the docs" button and the Docs link in changelog.md hide themselves when they would duplicate the entry's CTA. If you import docs links into the CTA field, this code steps back automatically for those entries, and the result looks the same.
  • The CTA field holds one link. Entries that already use the CTA for a product action (for example "Try it now") cannot also carry a docs link in that field. The derived link renders in addition to the CTA, so those entries keep both.
  • A one-time import covers existing entries only. The build-time derivation also covers future entries when the creation step does not add a link — the "backup" case Sarah described in her review.
  • Separate from the button, this PR also adds canonical entry URLs and topic labels to the server-rendered list and to changelog.md, for crawlers and agents. A CTA import does not produce those.

I cannot write to Strapi from this environment, so I cannot run the import myself. Two ways forward:

  1. Merge this PR as the fallback layer, and run the CTA import as well. Entries with a docs CTA render exactly as they do today.
  2. If you prefer the import alone, tell me and I will cut this PR down to only the changelog.md and crawler-list improvements.

Which do you prefer?

🦉 via talyn.dev

The script writes the docs link found in each completed entry's own
description into the entry's empty CTA field. It does not touch entries
that already have a CTA, and it does not import the generic topic
fallbacks, which stay derived at render time. Dry run by default;
--write with STRAPI_TOKEN applies the changes.

Generated-By: PostHog Desktop
Task-Id: 81894005-21c9-4078-b450-8041bf5c9f6f
@github-actions github-actions Bot removed the website About the website (beyond just landing pages) label Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

3 participants