Repository navigation
Gap analysis: missing gates behind recurring Hive findings (last 100 issues/PRs) #1718
Description
Summary
I reviewed the 100 most recent issues (#1447 to #1716, opened 2026-10-14 to 2026-10-21) and the 100 most recent PRs (#1555 to #1717). Hive agents opened 93 of those issues and 75 of those PRs. Most of the findings fall into a small number of recurring classes, and each class keeps coming back because no gate catches the underlying problem. Each finding gets fixed one at a time, and the agent then finds the next instance.
This issue lists those classes, the gate that is missing for each, and a suggested order of work. The aim is to replace whole classes of recurring findings with automated gates, so the agents run out of work in those areas.
The "expected effect" estimates are judgement calls; none of the proposed gates have been prototyped yet.
Findings by class
Counts are by issue title prefix ([quality], [architect] and so on) across the 100 issues.
| Class | Issues | Example issues |
|---|---|---|
| quality | 43 | #1674, #1670, #1620, #1705, #1660, #1676, #1682, #1512 |
| architect | 16 | #1658, #1690, #1699, #1709, #1669, #1681, #1558, #1622 |
| sec-check | 11 | #1515, #1672, #1695, #1716, #1494, #1501, #1543, #1684 |
| guide | 11 | #1568, #1529, #1537, #1663, #1703, #1459, #1637 |
| scanner | 10 | #1602, #1609, #1599, #1630, #1618, #1594, #1448 |
| ci-maintainer | 2 | #1707, #1645 |
1. Code that runs under test but is never asserted (quality)
Pattern: "X's Y arm is unpinned or unasserted: collapsing Z leaves the unit suite green." Examples: #1674 (FilterToolbar's value/label ternary), #1670 (the data: arm of activeScheme), #1620 (useFilterToolbar query exclusion), #1705 (DATELINE_RE arms), #1660 (websiteUrl authority parsing), #1676, #1682, #1512, #1651.
Root cause: test:unit:coverage:check enforces 100% source lines and regions, which only shows that code ran. Nothing checks whether a test would fail if the code changed. The quality agent is doing mutation testing by hand, one branch per issue.
Missing gate: mutation testing (for example StrykerJS with the node:test runner, or a lightweight custom mutator) over src/ and scripts/lib/, with a minimum score ratchet in CI. It could start as incremental, mutating only files changed in the PR, to keep CI time bounded.
Expected effect: this removes the largest single source of Hive issues.
2. Unit-covered branches that no end-to-end build reaches (quality)
Pattern: "guard is unit-covered but reached by no e2e fixture build." Examples: #1486, #1654, #1656, #1692, #1469, #1593, and PRs #1688, #1693, #1717.
Root cause: there is no written policy on which branches need browser coverage. #1617 dropped the per-file region floor, but the quality agent still treats every unreached defensive arm as a bug, and each one costs a new fixture build.
Missing gate (policy, not code): state in GOVERNANCE.md or an ADR that defensive guards (nullish, unparseable, or all-absent data) only need unit coverage, and that e2e coverage is required only for user-reachable interaction states. Then tell the quality agent, through its skill or prompt, not to file this class of issue.
3. Duplication outside the duplication gate's scope (architect)
Pattern: the same component, CSS rule or workflow block copied across files. Examples: #1658, #1690, #1699, #1709 (components); #1669 and #1681 (freshness-note CSS, one copy already drifted); #1558 and #1622 (workflow YAML); #1474, #1553 and #1455 (script helpers).
Root cause: .jscpd.json scans only tests, src and scripts, with minTokens: 50. Workflows and composite actions under .github/ are not scanned, and short CSS-module rules fall under the token threshold.
Missing gates:
- Add
.githubto the jscpdpath, or add a second jscpd run with YAML-specific settings. - Add a CSS-specific jscpd pass over
src/**/*.module.csswith a lowerminTokens, or a stylelint rule. - Make the
CLONE_CEILINGratchet automatic: fail when the count drops by more thanCEILING_SLACKwithout the ceiling being lowered, so [ci-maintainer] Duplication gate has only one clone below its ceiling #1645-style issues are not needed.
Expected effect: the architect agent's duplication findings move into CI.
4. No linter (scanner and quality)
Pattern: the repository has no ESLint configuration. Several bespoke tests stand in for lint rules, and the remaining cases are filed as issues one by one:
URL.pathnameinstead offileURLToPath([architect] Four scripts.mjs compute repo root via URL.pathname instead of the repo's own fileURLToPath convention #1599, [scanner] tests/: 18 files resolve paths with URL.pathname instead of fileURLToPath #1609, PR test: resolve import.meta.url paths with fileURLToPath across tests/ #1612).- Hyphenated SVG and DOM attributes in JSX ([scanner] Footer icons use hyphenated SVG attributes that React rejects in development #1602, with the bespoke guard in PR test: guard the camelCase JSX DOM prop convention across src/ #1634).
- An unused
clsxdependency ([architect] unused direct dependency: clsx in package.json #1604) and unused private npm scripts (PR test: guard that package.json's private _ scripts still have a caller #1575). - Bare
returnbail-outs in tests (PR test: stop three unit tests bailing with a bare return #1571).
Missing gates:
- ESLint with
eslint-plugin-react(react/no-unknown-property),eslint-plugin-react-hooks,jsx-a11y, and ano-restricted-syntaxrule banningnew URL(...).pathnamefor file paths. - knip (or depcheck) for unused dependencies, exports, files and scripts.
- Replace the bespoke guard tests with these rules where they overlap, which also shrinks the test tree.
Expected effect: the scanner agent's static findings, and their one-off guard tests, move into the linter.
5. Security filters that block known-bad patterns, and partial CSP (sec-check)
Pattern: each sec-check issue finds another way past the SVG and MDX active-content filters, or another missing header:
- Filter bypasses: [sec-check] stripActiveContent() never re-scans the SVG it returns, though its contract and two mirroring callers depend on it #1515 (the returned SVG is not re-scanned), [sec-check] MDX active-content gate resolves duplicate link definitions last-wins, bypassing the remote-image check #1672 (duplicate link definitions resolved last-wins), [sec-check] mdx-code-block fences bypass both the import-time and publish-time active-content gates #1695 (
mdx-code-blockfences), Submitted architecture SVGs can submit forms to remote hosts: no gate on action/formaction, no form-action in asset CSP #1716 (action/formaction). - Headers added one at a time: [sec-check] Site serves no security response headers after the Netlify migration: any origin can frame it #1494 (no headers), [sec-check] Served SVGs carry no script-src: the one CSP layer a meta tag can never reach is still missing after #1496 #1501 (
script-src), [sec-check] netlify.toml sends no Strict-Transport-Security: HTTPS is never pinned, so one cleartext request is strippable #1543 (HSTS), [sec-check] asset-scoped CSP in netlify.toml names no default-src, so a directly-opened SVG may still fetch from any host #1684 (default-src), Submitted architecture SVGs can submit forms to remote hosts: no gate on action/formaction, no form-action in asset CSP #1716 (form-action).
Root cause:
stripActiveContentand the MDX gates enumerate dangerous constructs, so every construct they don't list is a bypass.- In
netlify.toml, only/img/*and/favicons/*carry a full CSP. HTML pages (/*) send onlyframe-ancestors 'self', so the next findings are predictable:script-src,base-uri,form-action,object-srcand Permissions-Policy on pages.
Missing gates:
- Switch SVG sanitization to an allowlist: only listed elements and attributes survive, and everything else is removed and fails the import. For example, an svgo or DOMPurify allowlist profile, or a hand-rolled allowlist.
- Switch the MDX gate to an allowlist of node types and URL schemes.
- Add a property-based or fuzz corpus test (for example fast-check) that feeds generated SVG and MDX through both gates.
- Define a complete site-wide CSP and Permissions-Policy, with a contract test that asserts every
[[headers]]block includes a fixed baseline directive set, so a missing directive fails CI instead of being found later.
Expected effect: high. This category produces the highest-severity issues.
6. Documentation claims nothing verifies (guide)
Pattern: docs describe scripts, routes, workflows, recipes or ADR status that are wrong or have since changed:
- Routes: [guide] Three docs still cite the /awards route removed by #1552 #1568 (the
/awardsroute), [guide] CONTRIBUTING.md stale references after restructures: retired import workflow/recipe, nonexistent /practitioners route #1529 (a nonexistent route). - Workflows: [guide] docs/metrics/index.md names retired 'Import reference architectures' workflow as the metrics refresh path #1537 (a retired workflow).
- npm scripts: [guide] CONTRIBUTING.md still says no validate:end-user-talks script exists (added by #1624) #1663 (a script that now exists).
- Justfile recipes: [guide] Justfile shortcuts paragraph: 'superset of the Netlify build' is false — just build never runs validate:end-user-talks #1703 (the Justfile "superset" claim).
- ADR status: [guide] ADR 0004 still marked Proposed after its decision shipped and tracking issue #1407 closed #1459 (an ADR still marked Proposed).
- Scope descriptions: [guide] SECURITY.md Scope omits composite actions from the CodeQL scan description #1637 (SECURITY.md's CodeQL scope).
Root cause: tests/markdown-references.test.mjs (PR #1580) checks file references, but not:
npm run <x>andjust <x>mentions- site routes
- workflow names
- the link between an ADR's status and the state of its tracking issue
Missing gate: extend the Markdown reference contract so that every inline-code npm run X resolves to a package.json script, every just X to a Justfile recipe, every site-relative route to a built route, and every workflow name to a file in .github/workflows/. Add a check that an ADR marked Proposed doesn't reference a closed tracking issue.
Expected effect: the guide agent's drift findings become CI failures in the PR that causes the drift.
7. Dependencies and CI environment (ci-maintainer and sec-check)
Pattern:
- New advisories turn the audit gate red on main ([sec-check] follow-redirects 1.16.0 carries two high advisories and fails the check:audit gate on main #1702, [sec-check] Dependency audit gate has no time trigger: a new advisory against the committed lockfile goes undetected while main is quiet #1478). Dependabot alert 140 (
braces, high) is open now; it is allowlisted in SECURITY.md, so the gate passes. - Runner environment assumptions break the build ([ci-maintainer] PR queue hygiene fails when scheduled onto the self-hosted GPU runner: spawnSync gh ENOENT #1707:
ghmissing on a self-hosted runner).
Missing gates:
- Turn on Dependabot security updates, with auto-merge for lockfile-only patch bumps once required checks pass.
- Add a scheduled check that allowlisted advisories still apply and have an upstream fix tracked.
- Add a contract test that every job pins a GitHub-hosted
runs-onlabel, or explicitly declares the tools it needs.
8. Self-checks over the test tree
Pattern: stale citations and recorded measurements inside test prose: #1447, #1468, #1471, #1497, PR #1597, and open PR #1714.
Root cause: ADR 0006 retired line-number citations, but there are still 138 #1xxx issue citations under tests/. Each time a cited issue closes, the citation goes stale and is re-filed.
Missing gate: remove issue-number citations from test prose (move the rationale into commit messages or ADRs), then add a lint check that rejects new ones. Close #1714 as covered by this.
Proposed order
- Mutation testing gate (class 1), plus the coverage policy ADR (class 2).
- ESLint and knip (class 4), retiring the overlapping bespoke guard tests.
- Allowlist sanitization, a fuzz corpus, and a full CSP/Permissions-Policy baseline with a contract test (class 5).
- The Markdown claims contract (class 6).
- Extend duplication scope to
.github/and CSS, and automate the ceiling ratchet (class 3). - Dependabot security auto-merge and the runner contract (class 7).
- Remove test-prose issue citations and add the lint check (class 8).
Each item should be its own PR and linked back here. Once each gate lands, update the matching Hive agent's skill or prompt so it stops filing that class of finding.
Activity
mrbobbytables commentedon Oct 21, 2026
Correction to class 3:
scripts/check-duplication.mjsalready ratchets the ceiling down (CEILING_SLACK), so only the scope widening (.github/ and CSS) is still open for item 5.Work in progress, one PR per item, each linked back here:
mrbobbytables commentedon Oct 21, 2026
All items now have PRs (none merged yet):
Runner fix for #1707 needs a CNCF org admin: restrict the
gpusrunner group so it is not available to cncf/endusers, or remove theubuntu-24.04label from those runners. #1733 duplicates #1731.fix: switch SVG and MDX active-content gates to allowlists
fix: switch SVG and MDX active-content gates to allowlists (#1730)
ci: add ESLint and gate it in the Lint repository job
ci: add ESLint and gate it in the Lint repository job (#1727)
ci: add knip and gate unused code in the Lint repository job
ci: add knip and gate unused code in the Lint repository job (#1728)
test: retire issue-number citations from test prose
test: retire issue-number citations from test prose (#1725)
mrbobbytables commentedon Oct 21, 2026
All items have landed: #1719, #1720, #1721, #1722, #1724, #1725, #1727, #1728, #1730 and #1731. #1733 and #1714 were closed as duplicates or superseded.
Fixes made while rebasing onto the combined main:
@stryker-mutator/apias a dev dependency.Validated main at the final merge:
npm ci,test:unit:coverage:check, all six lint checks andnpm run buildall pass.Still open, outside this repository: #1707 needs a CNCF org admin to restrict the
gpusrunner group.docs(adr): scope end-to-end coverage findings to user-reachable states (
clubanderson commentedon Oct 21, 2026
Thanks Bob - this is exactly the feedback the hive needed, and the gate PRs are great work. Filed two small prompt-level changes upstream so the agents stop generating this kind of work: hivecommons/hive#13427 (stop filing a class once the repo has a gate or policy for it) and hivecommons/hive#13428 (after three same-class findings, propose the gate instead of a fourth finding). Once those land, the lanes will honour the gates you added here.