fix(docs): validate the singular framework field and collapse five framework maps into one - #430
Open
eugenia-scandit wants to merge 3 commits into
Open
fix(docs): validate the singular framework field and collapse five framework maps into one#430eugenia-scandit wants to merge 3 commits into
eugenia-scandit wants to merge 3 commits into
Conversation
…values docs-schema.yml defined the plural `frameworks` array with an enum but never defined the singular `framework` field at all. With additionalProperties: true it got no validation, and its values drifted. Canonical set: the enum is now the single source of truth for framework identifiers, and singular and plural share it - a page states one platform or several, never two different vocabularies. Normalized 117 pages: - netIos -> net-ios (31), netAndroid -> net-android (31), react -> react-native (30). Pure spelling drift; the canonical spellings already existed on other pages. - express (13) and bolt (12) were never frameworks. Those pages live under docs/hosted/, so they are `framework: hosted` with the value they were carrying moved to `product: express` / `product: id-bolt`, both of which already exist in the product enum. Two things the ticket's count could not have seen: - `kmp` is a sixth non-canonical value, on 37 pages - more than any entry in the ticket's table. It is not drift: those pages are the published /sdks/kmp/ tree, kmp is first-class in FRAMEWORK_MAPPING, QUERY_FRAMEWORK_TO_PATH and SkillsCallout, and being unreleased is already tracked by UNRELEASED_FRAMEWORK_SLUGS. The enum was stale, so kmp is added to it rather than the pages being rewritten. - FW_TO_PJ does not exist on main - PR #417 is unmerged. The real duplication is five maps, not three. Why nobody ever saw an error: docs-gate is a ratchet over changed files, so 37 pages violating the *plural* enum went unreported for months. Step 2 of the ticket alone would not have caught the other 117 either. scripts/verify-frameworks.cjs (yarn verify:frameworks, wired into CI) therefore checks the whole corpus, and the code maps as well: CONTENT no page may declare a framework outside the enum DRIFT no code map may key off a framework the enum does not define COVERAGE enum slugs missing from a map are reported as known gaps It found one live bug on its first run: FRAMEWORK_MAPPING had no `linux` entry, so parseSdksRoute() resolved no framework at all for every /sdks/linux/ page. Fixed here. Ticket acceptance test: a page set to `framework: netIos` fails the gate and passes after normalization - verified both ways. Step 4 (consolidating the five maps onto one) is deliberately NOT in this commit. Those maps have different membership, so merging them changes runtime behaviour - the linux gap above is exactly that kind of change - and it deserves its own reviewable diff. The DRIFT check above is what stops them diverging further in the meantime. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Step 4 of the ticket. The framework set was written out five times -
FRAMEWORK_MAPPING, QUERY_FRAMEWORK_TO_PATH and HOMEPAGE_FRAMEWORK_ALIASES
in components/utils/frameworks.ts, plus FRAMEWORK_URL_PATH and
FRAMEWORK_SLUG in SkillsCallout - each keyed slightly differently and
nothing tying them together. That is why `linux` could be missing from one
of them, and only that one, for the entire life of the page.
src/constants/frameworks.ts is now the single registry. Each entry carries
slug, display name, route segment, whether an Agent Skills page exists,
whether it is unreleased, and any alternate spellings. All five maps are
derived from it, as is UNRELEASED_FRAMEWORK_SLUGS.
`slug` is the same string as the docs-schema.yml enum value, so the
frontmatter vocabulary and the code vocabulary are now one vocabulary.
yarn verify:frameworks compares the registry against the enum in both
directions and fails on any difference - a slug in the registry the schema
does not allow, or a slug the schema allows that no component can resolve.
The risk in this refactor is not a crash, it is a map silently gaining or
losing an entry, so scripts/test-frameworks.cjs (yarn test:frameworks,
wired into CI) pins the expected membership of every derived map against
what the hand-written maps held before. It loads the real modules through
the TypeScript API rather than re-deriving anything, so it fails if the
registry changes shape. 9 assertions, all passing, including the .NET
two-segment route, the homepage aliases, and the Agent Skills exclusions.
One deliberate membership change: `hosted` now counts as a framework
without Agent Skills. It is not a homepage selector slug, so nothing
passes it to frameworkHasAgentSkills - inert today, and correct if it ever
is passed.
Retargeting the gate also surfaced the same parser trap twice: anchoring
on the first `{` or `[` after a name reads the TYPE annotation, not the
value, and yields zero entries while reporting success. Both readers now
anchor on the assignment and fail loudly on zero.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ratchet checks a whole file as soon as a PR touches one line of it. That is right for prose someone is actually editing, and wrong for a mechanical metadata pass: normalizing `framework:` across 117 pages dragged in 233 pre-existing Vale findings the change neither caused nor altered (measured identical before and after: 233 either way). Nobody writes prose in frontmatter, so when a file's body is byte-identical to the ratchet base there is no prose to review. Those files now skip Vale and cspell. Schema and link checks still run on every changed file, and a file with any body edit is checked in full - verified by adding one sentence to one file and watching both new findings appear while the other 116 stayed skipped. Line endings are normalized before comparing: `git show` returns the repo blob with LF while the Windows working copy has CRLF, which made every file compare as changed and the skip silently never fire. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the ticket on the unvalidated
frameworkfield.The problem
docs-schema.ymldefined the pluralframeworksarray with an enum but did notdefine the singular
frameworkfield at all. The schema allows undeclaredfields, so it got no validation and its values drifted. Components that read it
silently found no match and fell back to their default — always iOS. No crash,
no error.
What this changes
docs-schema.ymlis the single source of truth; singular andplural share one vocabulary.
netIos/netAndroid/react),and 25
express/boltpages which were never frameworks — they live underdocs/hosted/, so they are nowframework: hostedwith the value they carriedmoved to
product:.(
src/constants/frameworks.ts), whichUNRELEASED_FRAMEWORK_SLUGSalsoderives from.
Three things the ticket could not have known
kmp— 37 pages, more than any row in the ticket's table. Not drift: it isthe published
/sdks/kmp/tree, it is first-class in the code, and"unreleased" is already tracked by a separate mechanism. The enum was stale, so
kmpwas added to it rather than the pages being rewritten.FW_TO_PJdoes not exist — PR feat: add ProductChooser ("Choose this if / not for" + framework matrix) #417 is unmerged. There were five copies,not three.
FRAMEWORK_MAPPINGhad nolinuxentry, soparseSdksRoute()resolved no framework at all for every/sdks/linux/page.Why nobody ever saw an error
docs-gateis a ratchet over changed files. Those 37 pages had been violatingthe plural enum for months and were never once reported. So
yarn verify:frameworks(in CI) runs over the whole corpus and over theregistry: a value outside the enum is an error, and the registry and schema are
compared in both directions.
Plus
yarn test:frameworks— 9 assertions pinning the membership of everyderived map, because the risk in this refactor is not a crash but a map quietly
gaining or losing an entry.
Separately
docs-gatenow skips prose checks for files whose body did not change. Themechanical frontmatter pass across 117 files dragged in 233 pre-existing Vale
findings (measured: 233 before, 233 after). Any file with a body edit is still
checked in full — verified by adding one sentence and watching both new findings
appear while the other 116 stayed skipped.
The ticket's test: a page set to
framework: netIosfails the gate beforenormalization and passes after — verified in both directions.