Repository navigation
Description
Finding
tests/architecture-catalog-contract.test.mjs is the gate that keeps one
vertical from being offered twice in the industry filter on /architectures
and /community/members — the defect #2020 and #2026 fixed by hand. It
compares word sets: an industry whose words are a subset of another's names the
same vertical ("Financial" vs "Financial Services").
That catches only wordings that overlap. Two labels for one vertical that share
no word pass the guard, and the filter then offers both. Selecting either hides
the records filed under the other, which is exactly the user-visible behaviour
#2026 removed.
This is live, not hypothetical. Merging the open PR #1976 onto main
(53e82aa) produces a catalog whose industry labels include both Banking
(China Merchants Bank) and Financial Services (Allianz Direct, Capital One,
China Merchants Bank). Selecting Banking in the /architectures industry
filter then shows one architecture and hides Capital One's — a bank. The same
split reaches the /community/members industry filter via data/members.json.
npm run test:unit on that merged tree passes all 3815 tests: no gate reports
it.
Reproduction on the merged tree:
$ git merge origin/main pr-1976
$ node -e "const c=require('./data/architectures/catalog.json');
const i=new Map(); for(const a of c) for(const x of a.industries) i.set(x,(i.get(x)||0)+1);
console.log([...i].sort())"
[ [ 'Banking', 1 ], ... [ 'Financial Services', 3 ], ... ]
$ npm run test:unit # 3815 pass, 0 failRecommendation
Extend the industry guard in tests/architecture-catalog-contract.test.mjs
with an explicit list of synonym groups, checked alongside the existing word
containment, and seed it with the one group the catalog needs today
(banking / financial services). Cover the new rule with a guard self-check
so it is not vacuous while no catalog record carries a second wording.
The data side of #1976 is the submitter's to change (Banking is redundant
there — the record already carries Financial Services); this issue is only
about the gate that should have reported it.
Priority
- Impact: medium (a filter option that hides architectures reaches production the next time a submission names a vertical a second way)
- Effort: low (test-only)
🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5n31 | SHA: 53e82aa
— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88
Activity
hivecommons-hive commentedon Oct 31, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 8 closed as completed in the last 14 days) already cite
data/architectures/catalog.json, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] Architecture tag dropdown is ordered by the build host's locale, not the visitor's served HTML
Finding
/architecturesserves a static HTML page whose "Add a tag to the search"dropdown is ordered by the build host's locale, while every other dropdown on
the same page is pinned to English. A visitor whose browser collates
differently from the build host therefore hydrates a different option order
than the one that was served.
useArchitectureFilterOptionsinsrc/components/ArchitectureFilters/index.jssorts three of its four option lists through
src/components/shared/compareLabels.js, whose docblock states the rule:The
tagslist is the one that does not. It sorts with a baretagKey(a).localeCompare(tagKey(b))(index.js:67), which uses the runtime'sdefault locale.
This is observable today
tagKey()lowercases, so the sorted alphabet is[a-z0-9 ]— but that is notenough to make the order locale-independent. Czech collates the digraph
chas a single letter that sorts after
h, sochaos engineeringandci cdswap. The catalog carries both tags.
Live production HTML (
https://endusers.cncf.io/architectures/, fetched2026-10-31) orders them build-host-first:
The same catalog, through the same exported hook, under a Czech runtime:
(
Chaos engineeringhas moved out of the first ten.)probe.mjsis therepository's own test harness driving the real export — no reimplementation:
The
industries,projectsandorganizationslists are byte-identicalacross the two runs, because they go through
compareLabels. Only the taglist moves. Traditional-Spanish collation (
es-u-co-trad) diverges the sameway.
Two consequences for that visitor: the served markup and the hydrated markup
disagree, which React reports as a hydration mismatch and recovers from by
re-rendering client-side; and the tag dropdown ends up ordered on a different
rule from the three dropdowns beside it.
compareAlphabeticalin the same file (index.js:32-33), which orders thearchitecture cards under both sort options, is on the same unpinned
localeCompare. Today's nine organization names do not diverge in any localeI tried, so that half is latent — but it is the same call in the same
function, so it belongs in the same change rather than a second issue later.
Why no gate caught it
tests/architecture-filters.test.mjsandtests/architecture-filters-ui.test.mjsassert the tag order by rebuilding itwith the same unpinned
localeCompare, so both sides shift together and theassertion holds under any locale. Nothing in
tests/pins a collation. Thisis not a re-file of #2013: PR #2016 pinned eight option builders and left this
one, and the sub-remit note I left on #23 on 2026-10-30 argued it was
unobservable because "no locale orders that alphabet differently from en".
The
chdigraph is the counter-example; that note was wrong and this issuesupersedes it.
Recommendation
One file, one change. In
src/components/ArchitectureFilters/index.js:and in
useArchitectureFilterOptions:compareLabelsis already imported in this file.Guard it so it cannot come back: add a fixture pair to
tests/architecture-filters.test.mjswhose order differs betweenenandcs—Chaos engineering/ci-cdis the pair the real catalog supplies —and assert the expected order as a literal rather than recomputing it with
localeCompare. Running that one test underLC_ALL=cs_CZ.UTF-8fails beforethe fix and passes after it.
compareAlphabeticaland thetagscomparator both route throughcompareLabelsChaos engineering/ci-cdorder as a literal and passes underLC_ALL=cs_CZ.UTF-8Priority
cs-family and traditional-Spanish collationsThe quality lane files no PR here: the fix is production code under
src/,and a test alone would land red. Same split as #2013 → #2016.
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5n31| SHA:53e82aa— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 3 closed as completed in the last 14 days) already cite
tests/architecture-catalog-contract.test.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] Project-card gate reads only braced attributes, so hand-written pages escape the two-label check
Finding
tests/architecture-catalog-contract.test.mjsholds the gate that keeps oneCNCF project from being offered twice in the project filter on
/architecturesand
/community/members— the defect fixed by hand for Argo and ExternalDNS.It learns which project each catalog label names by reading the
<CNCFProjectCard />tags on the architecture page.Its attribute parser accepts only the braced form:
That is the form
scripts/import-architecture-issue.mjswrites viascripts/lib/jsx-attributes.mjs, so every page onmainparses. Ahand-written submission may instead use the plain
name="Argo"form, whichthe MDX active-content allowlist accepts (
scripts/lib/mdx-active-content.mjs;tests/mdx-active-content.test.mjs:21) and the site renders identically. Onsuch a page the parser returns
nullfor every attribute, the pagecontributes no labels, and the check passes without covering that
architecture at all — silently.
This is live, not hypothetical. The open PR #1976 adds
docs/architectures/china-merchants-bank/index.md, whose five cards are allwritten in the plain form. Running the gate's own parser over that page
returns
name = nullfor all five.Reproduction, merging #1976 onto
main(53e82aa) and planting the defect thegate exists to report — a second label for Fluid, as Argo once had three:
The filter would offer both Fluid and Fluid Dataset, each hiding the
architecture filed under the other, and no gate reports it.
Recommendation
Widen the parser in
cardAttribute()to read both the braced and the plainattribute forms the pages legitimately use, and cover the new form with a
guard self-check: every page on
mainuses the braced form, so nothing in thecatalog would report a parser that reads only that form.
Test-only; no production code, no data.
Priority
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5n31| SHA:ded6080— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88
hivecommons-hive commentedon Oct 31, 2026
PR #2032 covers this issue: #2032
The PR body says this is partial/non-closing work (
Refs/Part ofor leave-open wording), so Hive will not add a closing keyword. GitHub will not show its issue-list PR icon without a closing keyword; the stage comment is the link.hivecommons-hive commentedon Oct 31, 2026
Third finding on this component, filed as its own issue and folded here by the
relay (which recorded the fold but posted nothing, so this comment is the
record). Test-only, disjoint from the other two.
cardAttribute()intests/architecture-catalog-contract.test.mjsreadsonly the braced attribute form, so a hand-written page escapes the two-label
check entirely.
The gate that keeps one CNCF project from being offered twice in the project
filter on
/architecturesand/community/memberslearns which project eachcatalog label names by reading the
<CNCFProjectCard />tags on the page. Itsparser accepts only
name={"Argo"}— the formscripts/import-architecture-issue.mjswrites viascripts/lib/jsx-attributes.mjs. A hand-written submission may use the plainname="Argo"form, which the MDX active-content allowlist accepts(
scripts/lib/mdx-active-content.mjs) and the site renders identically. Onsuch a page every attribute parses as
null, the page contributes no labels,and the check passes without covering that architecture — with no signal.
Live, not hypothetical: the open PR #1976 adds
docs/architectures/china-merchants-bank/index.mdwith five cards all in theplain form; the gate's own parser returns
name = nullfor all five. Merging#1976 onto
main(53e82aa) and planting the defect the gate exists to report— a second label for Fluid, as Argo once had three — leaves
no CNCF project is listed under two labels across the cataloggreen, whilethe filter would offer both Fluid and Fluid Dataset, each hiding the
architecture filed under the other.
Fix: widen the parser to both forms, with a guard self-check (every page on
mainuses the braced form, so nothing in the catalog would report the gap).PR to follow on
quality/project-card-attribute-forms.🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5n31| SHA:ded6080— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88
fix(architectures): pin the tag and card sort to English collation (c…