Skip to content

docs(api-reference): add v2 service landing pages - #2833

Open
aaronmichaelacosta wants to merge 8 commits into
APPEX-956/deprecation-policyfrom
APPEX-1609/v2-service-pages
Open

docs(api-reference): add v2 service landing pages#2833
aaronmichaelacosta wants to merge 8 commits into
APPEX-956/deprecation-policyfrom
APPEX-1609/v2-service-pages

Conversation

@aaronmichaelacosta

Copy link
Copy Markdown
Contributor

What this adds

Twelve service landing pages under the v2 API — one per service in the Stable API proposal — in a new Services group above the generated Endpoints list.

Each page says what the service covers. None of them list endpoints yet, on purpose: endpoints move into these services one at a time, so the pages fill up as the migration lands. The placeholder block is what a generated endpoint list will replace later, once there's real data to generate from.

They live under v2 rather than in a new unversioned section, per the call in [this thread] — customers already know the v1/v2 split, so v1 drains and disappears instead of a third concept showing up.

Also drops the blanket "experimental" framing

The new services contradict it, in two places:

  • the dropdown said v2 (Experimental) — claiming the whole API is experimental, while the page inside it explains per-endpoint maturity badges. Now just v2.
  • the Introduction opened with "The v2 API is under active development". Removed. The rest of that sentence stays, since "we won't deprecate v1 until v2 covers it" is still true.

One thing left alone

The Introduction's maturity list still says stable endpoints get "no breaking changes", while the deprecation policy says they get six months' notice before one. Two different public promises on adjacent pages. Reconciling them is an editorial call rather than a scaffolding change, so I've left it — happy to fold it in if you'd rather.

Test plan

  • npx mintlify@latest validate passes

Stacked on #2832. Pairs with the semgrep-app directory scaffolding (APPEX-1609).

Copy link
Copy Markdown
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@aaronmichaelacosta
aaronmichaelacosta force-pushed the APPEX-956/deprecation-policy branch from 9400249 to 691f1ba Compare September 8, 2026 17:17
@aaronmichaelacosta
aaronmichaelacosta force-pushed the APPEX-1609/v2-service-pages branch 2 times, most recently from 84d07fd to 310ed6d Compare September 8, 2026 17:27
@aaronmichaelacosta
aaronmichaelacosta force-pushed the APPEX-956/deprecation-policy branch from 691f1ba to 547a2d0 Compare September 8, 2026 17:27
@aaronmichaelacosta
aaronmichaelacosta changed the base branch from APPEX-956/deprecation-policy to graphite-base/2833 September 9, 2026 17:26
aaronmichaelacosta and others added 8 commits September 9, 2026 10:27
Twelve landing pages under the v2 dropdown, one per service in the Stable
API proposal, in a new "Services" nav group above the generated Endpoints
group. Each describes what the service covers and where its endpoints will
appear. They stay in v2 rather than a new unversioned section: customers
already know the v1/v2 split, so v1 drains and disappears instead of a
third concept arriving.

Every page is empty of endpoints today, by design. Endpoints arrive one at
a time as each is defined in its new service, migrated, and promoted, so
the pages fill up as the migration lands. The placeholder block is what a
generated endpoint list will replace once there is real data to generate
from -- building it now would duplicate the slug rules in
generate_api_changelog.py before we know the shape of what it renders.

Also drops the blanket-experimental framing, which the new services
contradict:

- the dropdown was labelled "v2 (Experimental)", which claims the whole
  API is experimental while the page inside it explains per-endpoint
  maturity badges and the deprecation policy promises per-endpoint notice
- the Introduction opened with "The v2 API is under active development",
  same problem; the rest of that sentence is kept, since not deprecating
  v1 until v2 covers it is still true

Not addressed here: the Introduction's maturity list still says stable
endpoints get "no breaking changes", while the deprecation policy says
they get six months' notice before one. Two different public promises on
adjacent pages, and reconciling them is an editorial call, not a
scaffolding change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The v2 Introduction told customers "No breaking changes will be made to
this API" for stable endpoints. The deprecation policy on the next page
over says stable endpoints get six months' notice *before a breaking
change* -- which concedes they happen. Two different public promises,
and the weaker one is the honest one.

Point the bullet at the policy rather than restating it, so there is one
customer-facing definition of what each maturity level owes you (which is
what the policy was written to be).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Mintlify builds an endpoint's page URL from its first tag:

  /api-reference/v2/<tag-slug>/<summary-slug>

So regrouping the public API into its new services moves every affected
page, even though the path, request and response are untouched. Today's
/api-reference/v2/miscservice/check-container-health becomes
/api-reference/v2/deployments/... and the old URL 404s for anyone who
bookmarked it, linked it, or reached it from search.

Derive the redirects instead of hand-maintaining ~200 of them: diff the
committed spec against the working tree, compute both URLs with the same
slug rules the changelog already uses, and emit one redirect per
difference. Runs in the spec-sync workflow, so a tag change and its
redirect land in the same PR. docs.json joins add-paths, or the redirects
would be generated and then left behind.

Chains collapse rather than accumulate: an endpoint that moves A -> B and
later B -> C leaves A -> C, not A -> B pointing at a page that no longer
exists.

docs.json is patched textually. A json round-trip is not byte-identical
against the checked-in formatting, so it would bury a two-line change in a
whole-file diff.

Slug rules are imported from generate_api_changelog rather than copied --
they were reverse-engineered against the rendered site, and two
independent copies would drift into broken links.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Services and endpoints were two separate things in the sidebar: a
"Services" group of twelve descriptions, and an autogenerated "Endpoints"
group of per-tag subgroups. Clicking a service in the second one opened
whichever endpoint happened to sort first.

Mintlify supports a `root` page on a nav group -- "clicking the group title
in the sidebar navigation opens the root page" -- but only on an explicitly
declared group, not an autogenerated one. So the endpoint list has to be
enumerated, which is why this generates it rather than asking anyone to
maintain 226 entries by hand.

One group per tag now, each with its landing page as `root` and its
endpoints as pages. The separate "Services" group is gone; its pages are
the roots. A tag with no landing page still gets a working group, so this
degrades gracefully for the services that do not have one yet.

Landing pages bind by slugged display name, not by tag name, so they
attach both before and after the endpoints are regrouped in semgrep-app.
Today's spec still carries the old service tags and yields 48 groups, 7 of
which already find their page; once the re-tagging deploys that collapses
to twelve, all with pages, without touching this code.

Runs in the spec-sync workflow after the sort step, whose ordering it
inherits, so a newly published endpoint lands in the nav in the same PR
that publishes it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The first version declared each service group at the dropdown's top level.
Mintlify renders a top-level group as a flat section heading, so the
services stopped being collapsible -- every endpoint of every service was
expanded at once. The collapsibility came from the autogenerated
`Endpoints` group nesting them one level down, and removing that group
removed the nesting with it.

Nest them inside a `Services` group instead. 27 other groups in this
docs.json already nest this way, so this follows the file's own pattern
rather than inventing one.

Adds a regression test asserting the groups land nested rather than
top-level, since the symptom is only visible in the rendered sidebar and
`mintlify validate` passes either way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The landing pages carried a hardcoded "This service has no published
endpoints yet", which was wrong the moment the first endpoint was filed.
Each page now imports a generated table of its endpoints: method badge,
summary linked to the endpoint's reference page, and the lead sentence of
its description.

Generated per landing page rather than per spec tag, so a tag with no page
produces nothing and a page whose service is still empty gets an accurate
empty state -- generated, so it cannot go stale, which is what the
hardcoded sentence could not manage. Prose on the page stays hand-written.

Endpoint URLs come from generate_api_changelog's slug rules rather than a
second copy: those were reverse-engineered against the rendered site, and
two copies would drift into broken links.

Also fixes a URL regression this work exposed. The previous commit replaced
the autogenerated endpoint group, which carried `directory:
api-reference/v2`, with explicit groups that did not -- so Mintlify served
every endpoint from /api-reference/<tag>/ instead of
/api-reference/<version>/<tag>/. That silently moved every existing
endpoint URL and would have collided v1 with v2. `mintlify validate`
passes either way; the only thing that caught it was fetching the URLs,
where all 202 generated links 404'd. The nav generator now emits the
object form of `openapi` with `directory`.

Verified against the re-tagged spec from semgrep-app on a local dev
server: all 202 links 200, every landing page renders, and the tables show
linked summaries with descriptions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
38 of 43 entries under a service carry a maturity pill. In the narrow nav
rail the pill wraps onto its own line, roughly doubling each entry's height
and making a service look far larger than it is. Maturity is already stated
on the endpoint page and defined in the deprecation policy, so hide it in
the rail -- but keep `deprecated`, which is rare and worth interrupting for.

Hides the pill's wrapper rather than the pill: the wrapper carries `h-[1lh]`
inside a flex-wrap row, so hiding only the pill left a line-tall empty box
that wrapped below any two-line title, showing up as a stray gap under
exactly those entries.

Also turns off Mintlify's `hyphens: auto` on nav titles, which was breaking
words mid-syllable -- "Preview a detection poli-cy apply".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The step ran generate_api_nav.py over v1 as well as v2, which would have
regrouped the v1 dropdown from its flat "Endpoints" list into per-service
groups on the next sync. Nothing asked for that: v1 has no service landing
pages, so the groups would open an arbitrary endpoint, and regrouping moves
every v1 endpoint's page URL -- Mintlify builds it from the first tag.

It also meant the committed docs.json did not match what the workflow
produced, so the next run would have opened an unreviewed nav change.
With the v1 call gone, running the step reproduces the committed file
exactly.

The redirect step still covers v1. It is a no-op while v1 keeps its flat
group, and it is what would catch the URL moves if v1 is ever regrouped
deliberately.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aaronmichaelacosta
aaronmichaelacosta force-pushed the APPEX-1609/v2-service-pages branch from d9aad15 to 4d634d9 Compare September 9, 2026 17:27
@aaronmichaelacosta
aaronmichaelacosta changed the base branch from graphite-base/2833 to APPEX-956/deprecation-policy September 9, 2026 17:27
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