Repository navigation
test(mirror): cover mirrorArtworkUrls' non-regular-file destination arm - #1165
Conversation
mirrorArtworkUrls() guards its destination with `existing?.isSymbolicLink() || (existing && !existing.isFile())`. The symlink arm and the pass-through case were pinned; the second operand -- an entry that exists and is neither a symlink nor a regular file -- was the one uncovered region in scripts/lib/architecture-content.mjs. A directory on a mirror path needs no adversary: an interrupted run, or an upstream asset renamed from <name> to <name>/<name>, leaves one behind, and the import is scheduled daily over whatever the last run left. Without the guard writeFileSync() raises EISDIR and aborts the whole import instead of skipping the single asset it cannot mirror. Two tests: one that the asset is skipped with exactly one audible warning, and one that the occupied destination is left byte-for-byte alone. Closes #1164 Signed-off-by: quality <quality@hive.kubestellar.io>
|
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 Hive will keep the |
|
CI note: the 🐝 Hive Agent: — hive: agent=ci-maintainer backend=copilot model=kimi-k3 copilot=1.0.88 |
|
The newest Maintainer action needed: re-run the cancelled job ( 🐝 Hive Agent: — hive: agent=ci-maintainer backend=copilot model=kimi-k3 copilot=1.0.88 |
What this changes
mirrorArtworkUrls()(scripts/lib/architecture-content.mjs:153) refuses towrite fetched third-party bytes to a destination it does not own:
The symlink arm was pinned by
tests/architecture-content-mirror.test.mjs:59, and the pass-through case bytests/architecture-content-mirror.test.mjs:87. The second operand — an entrythat exists and is neither a symlink nor a regular file — had no test, and was
the only uncovered region in the file.
This adds two tests for it, placed directly beneath the symlink pair so both
arms of the one guard are read together. No production code changes.
directory on the mirror path and asserts exactly one
destination is not a regular filewarning. Skipping has to be audible: asilent
continuewould leave the asset missing with nothing in the importlog saying why.
asserts the destination is still a directory, still holds only its original
entry, and that the entry's contents are unchanged.
Why a directory, and why this arm matters
It needs no adversary. A directory on a mirror path is what an interrupted run
leaves behind, or what an upstream asset renamed from
<name>to<name>/<name>produces, and.github/workflows/import-architectures.ymlrerunsnpm run import:architecturesdaily over whatever the previous run left on disk.Without the guard,
writeFileSync()raisesEISDIRand aborts the wholeimport rather than skipping the single asset it cannot mirror — the arm is the
difference between one missing logo and a failed daily job.
A symlink cannot stand in for it:
lstatSync()reports a symlink and adirectory differently, and only the second operand rejects the directory.
Verification
Run locally against
mainat03cfcfe, node v26.10.0 / npm 11.19.1:npm run test:unit— 2027 passed, 0 failed (2025 before).npm run test:unit:coverage—scripts/lib/architecture-content.mjsgoesfrom
100.00 | 97.78 | | 155to100.00 | 100.00. Repositorysrc filesregions rise from 99.92% (2545/2547) to 99.96% (2544/2545); the sole
remaining sub-100% file is
scripts/lib/svg-active-content.mjs:251, aseparate already-tracked gap this PR deliberately does not touch.
npm run test:unit:coverage:check— passes.npx prettier --check tests/architecture-content-mirror.test.mjs— clean.End-to-end coverage is not claimed either way here:
scripts/lib/architecture-content.mjsis a Node build-time module that neverenters the browser bundle Playwright V8 coverage observes, so it does not
appear in the
e2e-coveragereport'ssourcesand no mechanism in thisrepository could put it there.
Coordination
Touches exactly one file,
tests/architecture-content-mirror.test.mjs, addingto it without editing any existing test. Disjoint from open hold-gated
#1161 (
npm auditgate) and #1163(
tests/tools/e2e-coverage-report.mjs,tests/e2e-coverage-report.test.mjs).Related Issue
Closes #1164
Human review required.
— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88