Skip to content

test: pin the .markdown-link-check.json key contract - #1007

Merged
mrbobbytables merged 1 commit into
mainfrom
quality/test-markdown-link-check-config
Oct 3, 2026
Merged

mrbobbytables merged 1 commit into
mainfrom
quality/test-markdown-link-check-config

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Test Improvement

Adds tests/markdown-link-check-config.test.mjs and removes one dead key from
.markdown-link-check.json. Nothing in the suite read that file before this.

The failure mode being closed

markdown-link-check does not pass the parsed config through to the checker. Its
CLI copies a fixed list of keys onto opts and drops the rest, with no warning
and no non-zero exit (node_modules/markdown-link-check/markdown-link-check:430-439).
A key that is misspelled, invented, or renamed by a devDependency bump is
therefore indistinguishable from one that works: npm run check:links stays
green and the setting silently does not apply.

fallbackHttpStatus: [200, 206, 429] was such a key — read nowhere in
markdown-link-check or link-check. It sat next to retryOn429/retryCount
reading as the clause that tolerates a rate-limited host, while liveness is
decided solely by aliveStatusCodes ([200, 206]), so a host still answering
429 after the third retry is reported dead. The config documented a guarantee
the tool was not providing.

What the test asserts

  • every key in .markdown-link-check.json is one the installed CLI reads, with
    the accepted set derived from the CLI source rather than hard-coded, so an
    upstream rename fails here instead of quietly disabling a setting;
  • a guard that the derivation itself still finds anything — if markdown-link-check
    is restructured so it no longer reads keys off a config object, the test says
    so rather than passing vacuously;
  • acceptedKeys() ignores config.trim() (a method call on the --config
    argument, not a setting) and bare reads that never reach opts;
  • each ignorePatterns[].pattern compiles as a RegExp;
  • aliveStatusCodes is a non-empty list of integer HTTP status codes;
  • retryOn429: true is paired with retryCount >= 1, since link-check only
    retries while attempts < retryCount;
  • timeout parses as an ms() duration;
  • some package script still passes --config .markdown-link-check.json, since a
    config the CLI is not pointed at is inert too.

Deliberately not changed

Whether 429 should be tolerated — adding it to aliveStatusCodes, or setting
fallbackRetryDelay — is a behaviour change and a maintainer's call. This PR only
deletes a setting that was never read, so npm run check:links behaves exactly as
it did before.

Verification

  • node --test tests/markdown-link-check-config.test.mjs fails on unmodified
    main with declares keys markdown-link-check never reads: fallbackHttpStatus,
    and passes once the key is removed — the test demonstrably catches the defect it
    was written for.
  • npm run test:unit:coverage:check exits 0 (TZ=UTC, node v26.8.1). The new file
    is 100.00% lines / 85.19% regions; the uncovered regions are assertion-message
    and early-return arms that only execute on failure. Repository totals stay above
    every gate: src files 100.00 | 100.00, all files 99.37 | 94.98 against
    --check 99 --check-source 100 --check-regions 94 --check-source-regions 99.
  • npx markdown-link-check --config .markdown-link-check.json -q README.md exits
    0 with the key removed, confirming the config is still accepted.
  • npx prettier --check passes on both touched files.

Scope and overlap

Touches .markdown-link-check.json and one new test file. Disjoint from every
open hold-gated PR: #989/#991 (tests/tools/e2e-coverage-report.mjs and its
tests), #996 (tests/tools/coverage-report.mjs, package.json), #998 (adr/),
#1000/#1002 (ci.yml job guards), #1004 (.prettierignore /
.markdownlintignore — ignore-file entries, not link-checker config), #994
(SECURITY.md, .cspell.yml). Branched from a fresh origin/main at 6ccdaac.

Related Issue

Closes #1006


Filed by quality agent (hold-gated mode). Human review required.

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

markdown-link-check's CLI copies a fixed list of keys off the parsed
config onto its options object and silently drops the rest, so a key
that is misspelled, invented, or renamed by a dependency bump is
indistinguishable from one that works: the run stays green and the
setting simply does not apply.

fallbackHttpStatus was such a key. It sat next to retryOn429/retryCount
reading as the clause that tolerates a rate-limited host, while liveness
is decided solely by aliveStatusCodes. Removing it is behaviour
preserving, because nothing ever read it.

Add a test that derives the accepted key set from the installed CLI
source rather than hard-coding it, so an upstream rename fails here
instead of quietly disabling a setting, and shape-check ignorePatterns,
aliveStatusCodes, the retryOn429/retryCount pairing and timeout.

Signed-off-by: quality <quality@hive.kubestellar.io>
@hivecommons-hive hivecommons-hive Bot added the hold label Oct 3, 2026
@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. Non-outreach agents are held at ACMM L3–L5; the outreach agent is always held because it publishes project-facing communication.

Hive will automatically remove the hold label once current policy no longer requires a level hold for "quality". If this is an outreach PR, a human must review it and remove the label.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[quality] .markdown-link-check.json declares fallbackHttpStatus, a key markdown-link-check never reads, and no test guards that file

1 participant