Skip to content

test: kill the surviving mutants in the shared ISO 8601 timestamp gate - #1786

Merged
mrbobbytables merged 1 commit into
mainfrom
quality/test-iso-timestamp-gate-mutants
Oct 22, 2026
Merged

mrbobbytables merged 1 commit into
mainfrom
quality/test-iso-timestamp-gate-mutants

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Test Improvement

Tests only — no production change. Touches one file,
tests/validate-utils.test.mjs, and only the checkIsoTimestamp cases plus a
local withFixedNow helper.

StrykerJS over scripts/lib/validate-utils.mjs scored 91.67% with 16
surviving mutants
. Five were unasserted behaviour in the strict ISO 8601 UTC
gate (isoUtcTime / checkIsoTimestamp) that validate-community-groups,
validate-community-people, validate-enduser-members and
validate-launch-metrics all rely on:

  • validate-utils.mjs:117 — all four mutants over the composite roundTrips
    expression. Nothing rejected a four-digit year below 0100, and
    Date.UTC(26, 0, 1) is 1926-01-01, so the year arm is the only one that
    catches it: every other out-of-range component cascades into the next-higher
    unit and trips a second arm as well.
  • validate-utils.mjs:174 — the EqualityOperator mutant turning
    time > Date.now() + futureToleranceMs into >=. The existing window tests
    sit 30s inside and 24h outside the window, so neither observes the boundary.

Three added tests close those:

  • a year Date.UTC remaps into the 1900s (0026-01-01T00:00:00Z,
    0099-12-31T23:59:59Z) is rejected, isolating the year arm
  • the future-tolerance boundary is inclusive and the next millisecond is not,
    with the clock pinned — a value derived from a live Date.now() is already
    in the past by the time the comparison runs
  • text wrapped around an otherwise valid instant is rejected, pinning what the
    ISO_8601_PATTERN anchors are there for

The file now scores 94.27% with 11 survivors. Those 11 are equivalent
mutants and are not chased here: the per-arm roundTrips mutants (lines
118-122) cannot be isolated because of the cascade above; Node accepts
Buffer.from(text, '') as utf8; Date.parse rejects every wrapped form, so
neither ISO_8601_PATTERN anchor nor the value ?? '' default is observable
through the helper; Date.now() + undefined is NaN either way; and
CNCF_HOST_SUFFIXES holds a single entry, so its join separator never
appears in the message.

Verification

Run locally at rev 18caa5e (node v26.12.0):

  • TZ=UTC npx stryker run --mutate scripts/lib/validate-utils.mjs — 91.67% /
    16 survivors before, 94.27% / 11 survivors after
  • TZ=UTC npm run test:unit:coverage:check — exit 0, src files 100.00% lines /
    100.00% regions
  • npx prettier --check and eslint --max-warnings 0 on the changed file

Related Issue

Refs #1759 — the hive folded this finding into #1759 as a comment because the
body named stryker.config.mjs. #1759's own deliverable is different and
unaffected by this PR: extracting scripts/validate-architecture-assets.mjs
into a callable core so the existing scripts/lib/** mutation glob reaches it.
That remains open and parked at stage/045-needs-decision
(needs-human: it moves production code, which is outside this lane's PR remit,
and #1752 reserved the broader-adoption call to the maintainer).

No overlap with the open held PRs: #1765 is the SVG active-content allowlist,
#1773 the gitignored Stryker sandbox in two worktree walks, #1782
unescapeMdx, #1784 profileImageUrl. None of them touch
tests/validate-utils.test.mjs or scripts/lib/validate-utils.mjs.

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

StrykerJS over scripts/lib/validate-utils.mjs scored 91.67% with 16
survivors. Five of them were unasserted behaviour in the strict ISO 8601
UTC gate that four validators share:

- all four mutants over the composite roundTrips expression: nothing
  rejected a four-digit year below 0100, and Date.UTC(26, 0, 1) is
  1926-01-01, so the year arm is the only one that catches it. Every
  other out-of-range component cascades into the next-higher unit and
  trips a second arm as well.
- the EqualityOperator mutant turning the future-skew test from > into
  >=. The existing window tests sit 30s inside and 24h outside it, so
  neither observes the boundary itself.

Three tests close those: a year Date.UTC remaps into the 1900s, the
future-tolerance boundary and the millisecond past it, and text wrapped
around an otherwise valid instant. The boundary case needs the clock
pinned, since a value derived from a live Date.now() is already in the
past by the time the comparison runs.

The file now scores 94.27% with 11 survivors, all equivalent mutants:
the per-arm roundTrips mutants cannot be isolated because of the
cascade, Node accepts Buffer.from(text, '') as utf8, Date.parse rejects
every wrapped form so neither ISO_8601_PATTERN anchor is observable
through the helper, Date.now() + undefined is NaN either way, and
CNCF_HOST_SUFFIXES holds a single entry so its join separator never
appears.

Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

Important

Held for human review by the hive's ACMM level gate.

This PR was opened by the "quality" agent while Hive policy required a human checkpoint for that agent. Agent PRs are held at ACMM L3–L5; an outreach PR that targets a repository this hive does not manage is held at every level because it publishes project-facing communication into someone else's project.

Hive will keep the hold label until a human removes it. Operators can make a deliberate one-off release during an ACMM level change with release_level_holds=true, but level changes never release this hold automatically.

@netlify

netlify Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for endusers ready!

Name Link
🔨 Latest commit ece221c
🔍 Latest deploy log https://app.netlify.com/projects/endusers/deploys/6ada432b2841e408daeb47f4
😎 Deploy Preview https://deploy-preview-1786--endusers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read the diff against scripts/lib/validate-utils.mjs at head ece221c; all three new tests pin real, previously unasserted behaviour:

  • Year-remap test — Date.UTC(26, 0, 1) does resolve to 1926, so for 0026-01-01T00:00:00Z only the getUTCFullYear() === year arm (validate-utils.mjs:118) rejects it; the other round-trip arms all pass. This genuinely isolates the year arm.
  • Boundary test — the skew check at validate-utils.mjs:174-175 is strict >, so a value exactly futureToleranceMs ahead passes and the next millisecond fails, exactly as asserted. withFixedNow is sound: checkIsoTimestamp reads the clock via the Date.now global, which the helper swaps and restores in finally; Date.parse and new Date(...) inside isoUtcTime are untouched by the mock.
  • Anchor test — ISO_8601_PATTERN (validate-utils.mjs:89-90) is ^…$-anchored, so each wrapped form fails the match rather than reaching Date.parse, pinning the anchors' purpose.

Tests-only, one file, no overlap with the other held PRs (#1782 and #1784 touch the same test file but disjoint test blocks — no conflict). Mutation-testing and unit-coverage checks are green on this head. Looks correct to me; fine to land once a maintainer signs off.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.88

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant