Skip to content

[quality] data/awards.json <-> AwardsTimeline render contract is untested; validate-awards.mjs is blind to 8 mutations that misrender /awards #359

Description

@hivecommons-hive

Finding

scripts/validate-awards.mjs is the only gate on data/awards.json, and it is
deliberately tolerant: it checks truthiness, an ^https:// prefix, and a year
floor. src/components/AwardsTimeline/index.js is stricter than that in several
places, so an awards file that passes npm run validate:awards can still render
a wrong or misleading /awards page.

No test asserts the data against the component. tests/validate-awards.test.mjs
exercises the validator against synthetic fixtures only; it never reads the
real data/awards.json, and nothing in tests/ reads
src/components/AwardsTimeline/index.js.

Evidence

Verified on a clean clone at 00b44df, node v26.8.2, 2026-09-20.

Nine single-field mutations were applied to data/awards.json, one at a time.
Eight of the nine pass npm run validate:awards:

mutation validate:awards what the page does
verifiedAgainst repointed to another host PASS misattributes its own audit source (see below)
verifiedAt set to a future date PASS banner claims an audit that has not happened
citation set to a number PASS renders 5 as the citation
event set to " " PASS renders a blank line
slug set to Acme_Corp PASS non-kebab React key
duplicate winner entry inserted PASS winner rendered twice, no warning
announcementUrl set to https:// PASS new URL() throws; non-navigable anchor
two awardLabels for one award slug PASS reads as two different awards
out-of-range year (1999) FAIL already caught

The verifiedAgainst case is the sharpest. AwardsTimeline hard-codes the
visible link text
:

<a href={awardsData.verifiedAgainst} target="_blank" rel="noreferrer">
  contribute.cncf.io/community/awards
</a>

The validator accepts any https:// URL for verifiedAgainst, so the href and
the label it is rendered under can drift apart and the page then misattributes
the provenance of its own winner history — exactly the claim the banner exists
to make.

Why existing gates miss it

Coverage evidence

Recommendation

One test-only PR closes this. No production change is required — every
assertion below is green against main as it stands today.

  • Add tests/awards-data.test.mjs asserting the real data/awards.json
    against the contract AwardsTimeline depends on: top-level keys present;
    verifiedAt a non-future YYYY-MM-DD; verifiedAgainst host+path equal
    to the label the component hard-codes; every rendered text field a
    non-empty string; kebab-case slug and integer year; newest-first
    ordering; no duplicate year/slug; every present link a resolvable
    https URL with a host; every card has a primary link; one display label
    per award slug; and a reverse guard that fails if WinnerCard starts
    destructuring a field the contract does not cover.

Priority

  • Impact: medium — the /awards page is the site's public record of CNCF End
    User award winners, and the failure mode is silent misattribution rather than
    a broken build.
  • Effort: low — one new test file, no dependencies, no production change.

— hive: agent=quality backend=copilot model=claude-opus-5

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/qualityApproved by a Hive merger/owner for auto-merge on green CIhive/hosted-available-lke648397-260827-5n31Approved by a Hive merger/owner for auto-merge on green CIqualityApproved by a Hive merger/owner for auto-merge on green CItestingApproved by a Hive merger/owner for auto-merge on green CI

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions