refactor(ci): split api-reference sync into three focused jobs#677
refactor(ci): split api-reference sync into three focused jobs#677
Conversation
The monolithic sync job from #676 had three blind spots: 1. The prompt was ambiguous about what "drift" means — the generated API JSON is always fresh, but the hand-written MDX prose can go stale. The prompt didn't make this distinction explicit. 2. It explicitly skipped demos (`Do not request runnable examples/demos`), so stale code examples went undetected. 3. It only checked `site/src/content/docs/reference/` — concept pages, how-to guides, and READMEs that mention changed APIs were ignored. Split into a shell-only `analyze` gate + three parallel downstream Claude jobs, each with a narrow scope and explicit instructions: - `reference-copy` (Opus, 20 turns): MDX prose vs generated JSON - `reference-demos` (Sonnet, 14 turns): demo code drift, issues only - `cross-site-refs` (Sonnet, 14 turns): stale API mentions outside /reference/, triage issues only Also adds three drift-type-specific issue templates and removes the old generic one. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
✅ Deploy Preview for vjs10-site ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📦 Bundle Size Report
Total: 66.33 kB · 0 B · 0% Entry BreakdownSubpath sizes are the additional bytes on top of the root entry point, measured by bundling root + subpath together and subtracting the root-only size.
|
| Entry | Base | PR | Diff | % | |
|---|---|---|---|---|---|
. |
4.39 kB | 4.39 kB | 0 B | 0% | ✅ |
./dom |
6.03 kB | 6.03 kB | 0 B | 0% | ✅ |
| total | 10.41 kB | 10.41 kB | 0 B | 0% |
@videojs/element
| Entry | Base | PR | Diff | % | |
|---|---|---|---|---|---|
. |
817 B | 817 B | 0 B | 0% | ✅ |
./context |
823 B | 823 B | 0 B | 0% | ✅ |
| total | 1.60 kB | 1.60 kB | 0 B | 0% |
@videojs/html
| Entry | Base | PR | Diff | % | |
|---|---|---|---|---|---|
. |
15.45 kB | 15.45 kB | 0 B | 0% | ✅ |
./video |
9.44 kB | 9.44 kB | 0 B | 0% | ✅ |
./audio |
1.06 kB | 1.06 kB | 0 B | 0% | ✅ |
./background |
1.02 kB | 1.02 kB | 0 B | 0% | ✅ |
| total | 26.98 kB | 26.98 kB | 0 B | 0% |
@videojs/icons
| Entry | Base | PR | Diff | % | |
|---|---|---|---|---|---|
./react |
2.27 kB | 2.27 kB | 0 B | 0% | ✅ |
./html |
1.52 kB | 1.52 kB | 0 B | 0% | ✅ |
./render |
1.59 kB | 1.59 kB | 0 B | 0% | ✅ |
./element |
2.11 kB | 2.11 kB | 0 B | 0% | ✅ |
| total | 7.49 kB | 7.49 kB | 0 B | 0% |
@videojs/store
| Entry | Base | PR | Diff | % | |
|---|---|---|---|---|---|
. |
1.31 kB | 1.31 kB | 0 B | 0% | ✅ |
./html |
472 B | 472 B | 0 B | 0% | ✅ |
./react |
199 B | 199 B | 0 B | 0% | ✅ |
| total | 1.96 kB | 1.96 kB | 0 B | 0% |
@videojs/utils
| Entry | Base | PR | Diff | % | |
|---|---|---|---|---|---|
./array |
104 B | 104 B | 0 B | 0% | ✅ |
./dom |
928 B | 928 B | 0 B | 0% | ✅ |
./events |
227 B | 227 B | 0 B | 0% | ✅ |
./function |
261 B | 261 B | 0 B | 0% | ✅ |
./object |
119 B | 119 B | 0 B | 0% | ✅ |
./predicate |
265 B | 265 B | 0 B | 0% | ✅ |
./string |
148 B | 148 B | 0 B | 0% | ✅ |
./style |
185 B | 185 B | 0 B | 0% | ✅ |
./time |
478 B | 478 B | 0 B | 0% | ✅ |
./number |
158 B | 158 B | 0 B | 0% | ✅ |
| total | 2.81 kB | 2.81 kB | 0 B | 0% |
ℹ️ How to interpret
Sizes are minified + brotli, measured with esbuild.
Package totals are computed as root size + marginal subpath costs.
Subpath marginal cost = (root + subpath bundled together) − root alone.
| Icon | Meaning |
|---|---|
| ✅ | No change |
| 🔺 | Increased ≤ 10% |
| 🔴 | Increased > 10% |
| 🔽 | Decreased |
| 🆕 | New (no baseline) |
Run pnpm size locally to check current sizes.
mihar-22
left a comment
There was a problem hiding this comment.
Thanks for doing this, awesome! Only some name fix suggestions below
| ## API Changes Summary | ||
| | Surface | Change Type | Before | After | Source | | ||
| |---|---|---|---|---| | ||
| {{API_CHANGES_TABLE_ROWS}} | ||
|
|
There was a problem hiding this comment.
Oh yeah this seems super nice to keep. Good catch.
| - Provide concise usage-guidance scaffolding based on API surface and likely user intent. | ||
| - Keep issue content human-focused; no hidden agent-only instruction blocks. | ||
| Labels: | ||
| - Required: `docs`, `api`, `site`, `reference:copy`. |
There was a problem hiding this comment.
label suggestion: reference:copy -> docs:api
Easier to filter and manage labels if we keep it readable and namespaced under docs:.
There was a problem hiding this comment.
I'm thinking api might be too broad. I'll go with docs:reference-copy
| - Do NOT create an issue if no drift is found. | ||
|
|
||
| Labels (always all of these): | ||
| - `docs`, `api`, `site`, `reference:demos`, `components`, `triage`. |
There was a problem hiding this comment.
same as above: reference:demos -> docs:demos
| - Do NOT create an issue if no stale references are found. | ||
|
|
||
| Labels (always all of these): | ||
| - `docs`, `site`, `cross-ref`, `triage`. |
There was a problem hiding this comment.
label change suggestion (same as above): cross-ref -> docs:content
There was a problem hiding this comment.
Following the convention I made above... how about docs:guide-copy?
Or maybe since this isn't exactly about copy, maybe docs:guide-api or docs:guide-reference or...
Well. Let me think about it. I just like the word "guide", since it's the term we're using to describe non-reference documentation.
There was a problem hiding this comment.
template name suggestion: docs/api-ref-issue
There was a problem hiding this comment.
template name suggestion: docs/content-api-issue.md
why: lives in site/src/content and generally speaking it's highlighting API drift in content pages.
There was a problem hiding this comment.
template name suggestion: docs/demo-api-issue
| fi | ||
|
|
||
| # ─── Job 1: MDX prose drift (Claude Opus) ─────────────────────────── | ||
| reference-copy: |
There was a problem hiding this comment.
job name suggestion: docs-api (workflow is called api-reference-sync)
| - Do NOT check concept/how-to pages (separate job handles that). | ||
|
|
||
| # ─── Job 2: Demo code drift (Claude Sonnet) ───────────────────────── | ||
| reference-demos: |
There was a problem hiding this comment.
job name suggestion: docs-demos (workflow is called api-reference-sync)
| - Do NOT check concept/how-to pages (separate job handles that). | ||
|
|
||
| # ─── Job 3: Cross-site references (Claude Sonnet) ─────────────────── | ||
| cross-site-refs: |
There was a problem hiding this comment.
job name suggestion: docs-content (workflow is called api-reference-sync)
Consistent `docs:*` naming across labels, job IDs, and template files. Move templates into `docs/` subdirectory and restore API Changes Summary table in reference-copy template. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Refines and expands the scope of the API reference sync workflow from #676. Rewritten as three focused, parallel job.
Why
The original single-job workflow (#676) works but has three areas that could use refinement
1. "Drift" was ambiguous
The prompt told Claude to "compare generated API JSON with docs" without clarifying which side drifts. The API JSON is rebuilt fresh every run — it's always correct. What actually goes stale is the hand-written MDX prose. I was a little worried that the original prompt didn't seem to make this explicitly.
2. Demos were explicitly skipped
The prompt said
Do not request runnable examples/demos. But, idk. I kinda want demos. So I added that as a separate sub-task3. Only
/reference/was checkedConcept pages, how-to guides, and package READMEs that mention specific APIs (prop names, element names, selectors) were not scanned. It's harder to figure out what non-reference content applies to a given change, granted, but, I want to try.
Architecture
All three downstream jobs run in parallel after the gate passes.
Job 0:
analyzeShell-only gate — no LLM cost. Checks if the PR touched API-relevant paths (
packages/core/src/core/ui/,packages/html/src/ui/,packages/react/src/ui/,packages/store/src/,packages/core/src/core/selectors/). Forworkflow_dispatch, always passes (full scan). Outputs PR context for downstream prompts.Job 1:
reference-copy(Opus)Compares generated API JSON (source of truth) against hand-written MDX in
site/src/content/docs/reference/. The prompt is explicit: "drift" = the MDX doesn't match the JSON. Creates canonical issues + PRs per component. Uses the newreference-copy-issue.mdtemplate which drops the redundant "API Changes Summary" table and adds sidebar status.Job 2:
reference-demos(Sonnet)Reads demo files in
site/src/components/docs/demos/{component}/and checks for renamed props, removed options, changed signatures, deprecated patterns. Creates issues only — demo fixes need human judgment. Uses the newreference-demos-issue.mdtemplate.Job 3:
cross-site-refs(Sonnet)Greps concept pages, how-to guides, and package READMEs for mentions of changed APIs (all naming variants). Classifies hits as high/medium/low confidence. Creates triage issues only. Groups related APIs into one issue when they affect the same files. Uses the new
cross-site-refs-issue.mdtemplate.New labels
Three labels differentiate drift types in issues:
reference:copy— MDX prose driftreference:demos— Demo code driftcross-ref— Cross-site reference driftFile changes
.github/workflows/api-reference-sync.yml.github/templates/reference-copy-issue.mdapi-reference-update-issue.md).github/templates/reference-demos-issue.md.github/templates/cross-site-refs-issue.md.github/templates/api-reference-update-issue.md.github/templates/api-reference-update-pr.mdCost tradeoff
Sonnet for Jobs 2 and 3 keeps costs down — these are narrower tasks (code/grep comparison vs. prose writing). Opus is only used for Job 1 which needs to understand prose nuance and potentially write MDX fixes in PRs.
Test plan
workflow_dispatchto verifyanalyzeoutputs gate correctlyhas_changesis false🤖 Generated with Claude Code