You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Thirteen JSX <p> elements in docs/ defer their content to the following
line. MDX v3 parses those children as markdown flow content and wraps them
in a paragraph of its own, so the server-rendered HTML is <p><p>…</p></p> —
nested paragraphs, which HTML does not permit.
The two affected pages are the site's homepage (/) and /architectures/ — the two highest-traffic routes on the site.
docusaurus build reports this, and then succeeds anyway:
- "/endusers/":
- [HTML minifier diagnostic - error] No "p" element in scope but a "p" end tag seen
... (5 total)
- "/endusers/architectures/":
- [HTML minifier diagnostic - error] No "p" element in scope but a "p" end tag seen
... (8 total)
[SUCCESS] Generated static files in "build".
Because the diagnostics are non-fatal, ci.yml and deploy-gh-pages.yml stay
green and the invalid markup ships on every deploy.
What the browser actually receives
Source (docs/architectures/index.md:14-18):
<divclassName="pillar"><h3>Showcase your brand's engineering</h3><p>
Put your production work in front of the whole cloud native community —
...
</p></div>
Built output at 00b44df:
<divclass=pillar><h3>Showcase your brand's engineering</h3><p><p>Put your production work in front of the whole cloud native community — …<p></div>
A <p> may not contain a <p>, so every HTML parser applies the same recovery:
it closes the outer paragraph at the inner one and discards the now-unmatched
end tag. The DOM the browser builds therefore does not match the DOM the
author wrote — one paragraph becomes two siblings plus, on the homepage, a
stray empty <p></p>. Any .pillar p or .hero-tagline rule in src/css/custom.css then applies to a different element set than intended,
and the empty paragraph collects that styling with no content in it.
Affected locations
All 13 are the same pattern — an opening <p …> tag with nothing after it on
its line.
file
lines
docs/architectures/index.md
15, 23, 31, 40, 59, 66, 74, 81
docs/practitioners/index.md
13, 24, 31, 38, 45
These map 1:1 onto the 13 build diagnostics. Single-line <p>text</p> elements elsewhere in the same files (for example docs/practitioners/index.md:92-107 and all six in docs/community/end-user-community.md) are correct and are not affected.
Why existing gates miss it
The minifier diagnostics are non-fatal; the build exits [SUCCESS].
onBrokenLinks: 'throw' governs page routes, not element nesting.
npm run check (prettier, markdownlint, cspell, markdown-link-check) does not
parse embedded JSX/HTML nesting. Prettier is happy with both forms.
No test in tests/ reads docs/ markup or the build/ output.
Two boxes. They must land in one PR: the guard test is red against main
until the content fix is applied.
Collapse each multi-line <p> onto a single line. The verified patch
is below — it is content-only, changes no wording, and is prettier --check clean.
Add tests/mdx-paragraph-nesting.test.mjs so the pattern cannot
return. Verified text is below.
Patch 1 of 2 — the content fix
diff --git a/docs/architectures/index.md b/docs/architectures/index.md
index 3597047..eb8d369 100644
--- a/docs/architectures/index.md+++ b/docs/architectures/index.md@@ -5,82 +5,53 @@ sidebar_position: 1
# Reference architectures
-A growing catalog of real-world cloud native architectures contributed by CNCF end users. Browse by organization, industry, and the CNCF projects used in each architecture.+A growing catalog of real-world cloud native architectures contributed by CNCF+end users. Browse by organization, industry, and the CNCF projects used in each+architecture.
## Why submit a reference architecture?
<div className="pillars pillars-duo">
<div className="pillar">
<h3>Showcase your brand's engineering</h3>
- <p>- Put your production work in front of the whole cloud native community —- shared architectures have helped earn organizations the Top End User Award.- You've already done the work — take your victory lap.- </p>+ <p>Put your production work in front of the whole cloud native community — shared architectures have helped earn organizations the Top End User Award. You've already done the work — take your victory lap.</p>
</div>
<div className="pillar">
<h3>Get expert review</h3>
- <p>- Every submission is reviewed by the End User TAB and your peers, giving- your design vetted, independent feedback. Hundreds of collective years of- production experience lead to cheaper prototyping.- </p>+ <p>Every submission is reviewed by the End User TAB and your peers, giving your design vetted, independent feedback. Hundreds of collective years of production experience lead to cheaper prototyping.</p>
</div>
<div className="pillar">
<h3>Guide the projects you rely on</h3>
- <p>- Real adoption patterns show maintainers how their projects are used in- production and help shape roadmaps around end user needs. The more you- participate, the more you influence — move the needle on the projects- your business depends on.- </p>+ <p>Real adoption patterns show maintainers how their projects are used in production and help shape roadmaps around end user needs. The more you participate, the more you influence — move the needle on the projects your business depends on.</p>
</div>
<div className="pillar">
<h3>Help the next adopter</h3>
- <p>- A decade of shared knowledge has led to the immense scale of cloud native.- Your trade-offs and lessons learned become a practical map for teams- facing the same decisions — a contribution no code can replace. Take the- lessons of your peers back to your platform teams and continue the circle- of open source.- </p>+ <p>A decade of shared knowledge has led to the immense scale of cloud native. Your trade-offs and lessons learned become a practical map for teams facing the same decisions — a contribution no code can replace. Take the lessons of your peers back to your platform teams and continue the circle of open source.</p>
</div>
</div>
Organizations with community-accepted Reference Architectures are
-[automatically eligible](https://www.cncf.io/enduser-contributor/) for the End User-Contributor program free of charge.+[automatically eligible](https://www.cncf.io/enduser-contributor/) for the End+User Contributor program free of charge.
## Benefits for your Organization
<div className="benefit-cards">
<div className="benefit">
<h3>KubeCon + CloudNativeCon Keynote time</h3>
- <p>- Tell your data-driven story from the biggest stage in open source — the- community celebrates its end users in front of thousands of practitioners.- </p>+ <p>Tell your data-driven story from the biggest stage in open source — the community celebrates its end users in front of thousands of practitioners.</p>
</div>
<div className="benefit">
<h3>Complimentary KubeCon passes</h3>
- <p>- Bring the engineers behind your architecture to KubeCon + CloudNativeCon- to meet the maintainers and peers they work alongside. Celebrate our- collective operational successes, learn from the failures.- </p>+ <p>Bring the engineers behind your architecture to KubeCon + CloudNativeCon to meet the maintainers and peers they work alongside. Celebrate our collective operational successes, learn from the failures.</p>
</div>
<div className="benefit">
<h3>End User track talk selection</h3>
- <p>- Coming soon: special consideration for production-grade stories to share- with the community.- </p>+ <p>Coming soon: special consideration for production-grade stories to share with the community.</p>
</div>
<div className="benefit">
<h3>CNCF marketing support</h3>
- <p>- Celebrate your brand's success with full support from the CNCF Marketing team, backed by the Linux Foundation's global events.- </p>+ <p>Celebrate your brand's success with full support from the CNCF Marketing team, backed by the Linux Foundation's global events.</p>
</div>
</div>
@@ -91,10 +62,14 @@ or start with the
## The catalog
-import ReferenceArchitectures from '@site/src/components/ReferenceArchitectures';+import ReferenceArchitectures from+'@site/src/components/ReferenceArchitectures';
<ReferenceArchitectures />
## About this catalog
-Architecture content is imported from the [CNCF Cloud Native Reference Architecture project](https://github.com/cncf/architecture). Each architecture includes its source revision and attribution. Documentation is distributed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).+Architecture content is imported from the+[CNCF Cloud Native Reference Architecture project](https://github.com/cncf/architecture).+Each architecture includes its source revision and attribution. Documentation is+distributed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).diff --git a/docs/practitioners/index.md b/docs/practitioners/index.md
index 96a1e96..04f6ff1 100644
--- a/docs/practitioners/index.md+++ b/docs/practitioners/index.md@@ -10,10 +10,7 @@ import ProjectsBorn from '@site/src/components/ProjectsBorn';
# CNCF End Users
-<p className="hero-tagline">- Proven performance in production- <span>by the organizations running cloud native at scale</span>-</p>+<p className="hero-tagline">Proven performance in production <span>by the organizations running cloud native at scale</span></p>
Welcome to the home of the **CNCF End User Community** — the practitioners,
architects, and organizations running cloud native technologies in production.
@@ -21,31 +18,19 @@ architects, and organizations running cloud native technologies in production.
<div className="pillars">
<div className="pillar">
<h3>Work with proven leaders</h3>
- <p>- Maximize what open source can do for your business, alongside the- organizations already doing it at scale.- </p>+ <p>Maximize what open source can do for your business, alongside the organizations already doing it at scale.</p>
</div>
<div className="pillar">
<h3>Stay ahead of change</h3>
- <p>- CNCF projects move at <a href="https://insights.linuxfoundation.org/collection/details/cncf">high velocity</a> —- end users keep their organizations in the know on modern infrastructure.- </p>+ <p>CNCF projects move at <a href="https://insights.linuxfoundation.org/collection/details/cncf">high velocity</a> — end users keep their organizations in the know on modern infrastructure.</p>
</div>
<div className="pillar">
<h3>Sustain open source</h3>
- <p>- Pool resources with your peers to support the sustainable development of- the projects you depend on.- </p>+ <p>Pool resources with your peers to support the sustainable development of the projects you depend on.</p>
</div>
<div className="pillar">
<h3>Elevate your platform teams</h3>
- <p>- A supportive, knowledge-focused community where teamwork and empathy- help your teams succeed.- </p>+ <p>A supportive, knowledge-focused community where teamwork and empathy help your teams succeed.</p>
</div>
</div>
@@ -77,7 +62,11 @@ architects, and organizations running cloud native technologies in production.
## Member proof and recognition
-The End User Community is where production experience gets recognized. Recent [Top End User Award](/awards) winners include [SNCF](/awards), [Michelin](/awards), [ANT Group](/awards), [Adobe](/awards), and [CERN](/awards) — organizations that have shared architectures, case studies, and operational lessons with the wider community.+The End User Community is where production experience gets recognized. Recent+[Top End User Award](/awards) winners include [SNCF](/awards),+[Michelin](/awards), [ANT Group](/awards), [Adobe](/awards), and [CERN](/awards)+— organizations that have shared architectures, case studies, and operational+lessons with the wider community.
<ProjectsBorn
title="Lead the way, set the industry standard"
Patch 2 of 2 — the guard test
tests/mdx-paragraph-nesting.test.mjs:
// Guards against JSX <p> elements in docs/ and blog/ whose content starts on a// following line. MDX parses such children as markdown flow content and wraps// them in a paragraph of its own, emitting <p><p>...</p></p> — invalid HTML// that the HTML parser recovers from by splitting the paragraph and leaving a// stray end tag. `docusaurus build` reports it only as a non-fatal minifier// diagnostic, so the build stays green and nothing in the suite notices.importassertfrom'node:assert/strict';importtestfrom'node:test';import{readFileSync,readdirSync}from'node:fs';import{join,relative}from'node:path';import{fileURLToPath}from'node:url';constrepoRoot=fileURLToPath(newURL('..',import.meta.url));functionmarkdownFiles(dir){constfound=[];for(constentryofreaddirSync(join(repoRoot,dir),{withFileTypes: true,recursive: true,})){if(!entry.isFile())continue;if(!/\.mdx?$/.test(entry.name))continue;found.push(relative(repoRoot,join(entry.parentPath,entry.name)));}returnfound;}constfiles=[...markdownFiles('docs'), ...markdownFiles('blog')].sort();// A `<p ...>` open tag with nothing but whitespace after it on the same line.constMULTILINE_P=/^[\t]*<p(?:\s[^>\n]*)?>[\t]*$/;functionoffendingLines(source){returnsource.split('\n').map((line,index)=>[index+1,line]).filter(([,line])=>MULTILINE_P.test(line)).map(([lineNumber])=>lineNumber);}test('the scan finds markdown sources to check',()=>{assert.ok(files.length>0,'no .md/.mdx files found under docs/ or blog/ — the assertions below would be vacuous',);});test('the detector matches a multi-line <p> and not a single-line one',()=>{assert.deepEqual(offendingLines('<p>\n text\n</p>\n'),[1]);assert.deepEqual(offendingLines(' <p className="x">\n text\n </p>\n'),[1]);assert.deepEqual(offendingLines('<p>text</p>\n'),[]);assert.deepEqual(offendingLines('<p className="x">text</p>\n'),[]);});test('no JSX <p> in docs/ or blog/ defers its content to the next line',()=>{constoffenders=[];for(constfileoffiles){for(constlineNumberofoffendingLines(readFileSync(join(repoRoot,file),'utf8'),)){offenders.push(`${file}:${lineNumber}`);}}assert.deepEqual(offenders,[],`MDX wraps these <p> elements' content in a second paragraph, emitting invalid nested <p>. Put the content on the same line as the tag:\n${offenders.join('\n')}`,);});
Evidence
Revision 00b44df, node v26.8.2, run locally 2026-09-21.
npx docusaurus build (SITE_URL=https://cncf.github.io BASE_URL=/endusers/)
before the fix: 13No "p" element in scope diagnostics (5 on /endusers/, 8 on /endusers/architectures/), exit [SUCCESS].
Built HTML contains 12 literal <p><p> plus 1 stray <p></p>.
Same command after the fix: 0 diagnostics, 0 occurrences of <p><p>
or <p></p> across every file in build/.
Guard test verified red on unfixed main — it names all 13 locations,
matching the 13 diagnostics 1:1 — and green once the fix is applied. Its
second test pins the detector itself against four inputs so a regex
regression cannot make the scan silently vacuous.
Full suite with both patches: 58/58 pass (55 before, +3).
npx prettier --check clean on all three files.
Unit coverage: no test in tests/ reads docs/ element nesting or build/.
End-to-end coverage: package.json declares no playwright, cypress or puppeteer, so there is no e2e mechanism to query — the e2e status is unobtainable rather than absent. See [quality] CI publishes no coverage evidence, so coverage findings cannot be verified #186. A rendered-DOM assertion is
exactly the class of check that would have caught this at authoring time.
Priority
Impact: medium — invalid HTML on the site's two highest-traffic routes, with a
real DOM/CSS divergence from what the author wrote, shipped silently on every
deploy
Effort: low — content-only patch plus one test file, no new dependencies
Why there is no PR attached
The half that carries the fix is a change to docs/content, which is
outside the quality lane's PR scope (tests only). The guard test cannot be
PR'd on its own because it is red against main by exactly the 13 locations
above, and splitting it out to make it mergeable would mean shipping a test
that asserts an invariant the repository violates. Both patches are given here
in full so applying them is mechanical.
Finding
Thirteen JSX
<p>elements indocs/defer their content to the followingline. MDX v3 parses those children as markdown flow content and wraps them
in a paragraph of its own, so the server-rendered HTML is
<p><p>…</p></p>—nested paragraphs, which HTML does not permit.
The two affected pages are the site's homepage (
/) and/architectures/— the two highest-traffic routes on the site.docusaurus buildreports this, and then succeeds anyway:Because the diagnostics are non-fatal,
ci.ymlanddeploy-gh-pages.ymlstaygreen and the invalid markup ships on every deploy.
What the browser actually receives
Source (
docs/architectures/index.md:14-18):Built output at
00b44df:A
<p>may not contain a<p>, so every HTML parser applies the same recovery:it closes the outer paragraph at the inner one and discards the now-unmatched
end tag. The DOM the browser builds therefore does not match the DOM the
author wrote — one paragraph becomes two siblings plus, on the homepage, a
stray empty
<p></p>. Any.pillar por.hero-taglinerule insrc/css/custom.cssthen applies to a different element set than intended,and the empty paragraph collects that styling with no content in it.
Affected locations
All 13 are the same pattern — an opening
<p …>tag with nothing after it onits line.
docs/architectures/index.mddocs/practitioners/index.mdThese map 1:1 onto the 13 build diagnostics. Single-line
<p>text</p>elements elsewhere in the same files (for exampledocs/practitioners/index.md:92-107and all six indocs/community/end-user-community.md) are correct and are not affected.Why existing gates miss it
[SUCCESS].onBrokenLinks: 'throw'governs page routes, not element nesting.npm run check(prettier, markdownlint, cspell, markdown-link-check) does notparse embedded JSX/HTML nesting. Prettier is happy with both forms.
tests/readsdocs/markup or thebuild/output.docs/markdown links and frontmatter; test: cover docs/ and blog/ MDX component import and prop contract (tests/mdx-components.test.mjs) #298 coversMDX component imports and props; test: cover the src/ JSX link and image hygiene contract (tests/jsx-link-hygiene.test.mjs) #343 covers
src/JSX link and imagehygiene. None of the three reads element nesting, and none reads the two
files above for this invariant.
Recommendation
Two boxes. They must land in one PR: the guard test is red against
mainuntil the content fix is applied.
<p>onto a single line. The verified patchis below — it is content-only, changes no wording, and is
prettier --checkclean.tests/mdx-paragraph-nesting.test.mjsso the pattern cannotreturn. Verified text is below.
Patch 1 of 2 — the content fix
Patch 2 of 2 — the guard test
tests/mdx-paragraph-nesting.test.mjs:Evidence
00b44df,node v26.8.2, run locally 2026-09-21.npx docusaurus build(SITE_URL=https://cncf.github.io BASE_URL=/endusers/)before the fix: 13
No "p" element in scopediagnostics (5 on/endusers/, 8 on/endusers/architectures/), exit[SUCCESS].Built HTML contains 12 literal
<p><p>plus 1 stray<p></p>.<p><p>or
<p></p>across every file inbuild/.main— it names all 13 locations,matching the 13 diagnostics 1:1 — and green once the fix is applied. Its
second test pins the detector itself against four inputs so a regex
regression cannot make the scan silently vacuous.
npx prettier --checkclean on all three files.tests/readsdocs/element nesting orbuild/.package.jsondeclares noplaywright,cypressorpuppeteer, so there is no e2e mechanism to query — the e2e status isunobtainable rather than absent. See [quality] CI publishes no coverage evidence, so coverage findings cannot be verified #186. A rendered-DOM assertion is
exactly the class of check that would have caught this at authoring time.
Priority
real DOM/CSS divergence from what the author wrote, shipped silently on every
deploy
Why there is no PR attached
The half that carries the fix is a change to
docs/content, which isoutside the quality lane's PR scope (tests only). The guard test cannot be
PR'd on its own because it is red against
mainby exactly the 13 locationsabove, and splitting it out to make it mergeable would mean shipping a test
that asserts an invariant the repository violates. Both patches are given here
in full so applying them is mechanical.
— hive: agent=quality backend=copilot model=claude-opus-5