Context
src/review/linked-issue-hard-rules-config.ts is a byte-identical "twin" of the canonical
packages/loopover-engine/src/review/linked-issue-hard-rules-config.ts (they differ only in the
types import path — a deliberate directory-scanned parity pair, same pattern as the recent
#5779/#4879 engine extractions). The engine copy has full branch coverage via
test/unit/linked-issue-hard-rules-config-engine.test.ts, but the src/ twin's own test
(test/unit/linked-issue-hard-rules.test.ts) only exercises a subset of its normalizer branches,
leaving several src/-side branches never taken by any test that imports from ../../src/review/linked-issue-hard-rules-config. A local unsharded npm run test:coverage run confirms the file sits at
62.50% branch coverage (20/32).
Specifically untested branches in the src/ copy (functions normalizeMode, normalizeBoolean,
normalizeCloseDelaySeconds, normalizeStringList, normalizeLinkedIssueHardRulesConfig):
normalizeMode (line 44-49): the value === undefined branch (return the field default) and the
invalid-string branch (push a warning, fall back to default) are never hit — the existing test only
passes a valid mode ("block") for one field.
normalizeBoolean (line 51-56): both the undefined branch and the wrong-type branch (e.g. a
string/number instead of boolean) are untested.
normalizeCloseDelaySeconds (line 58-65): the undefined branch, the invalid-value branch
(negative / NaN / non-number → warning + DEFAULT_CLOSE_DELAY_SECONDS), and the valid-but-clamped
branch (Math.min(MAX_CLOSE_DELAY_SECONDS, Math.floor(value))) are all untested against the src/
export.
normalizeLinkedIssueHardRulesConfig (line 67-68): the top-level input === undefined branch is
untested.
Because this is a scored src/** file, any future PR that legitimately touches one of these
functions inherits the 99% Codecov patch gate on lines it didn't even mean to change — closing this
gap now removes that latent trap.
Requirements
Add test cases to test/unit/linked-issue-hard-rules.test.ts (import stays
from "../../src/review/linked-issue-hard-rules-config") that exercise, for the src/ export
specifically:
normalizeLinkedIssueHardRulesConfig(undefined, warnings) returns the all-off default.
- A mode field given an invalid string (e.g.
"sometimes") falls back to its default and pushes a
warning naming the field.
- A mode field omitted (
undefined) resolves to its own default (not just tested implicitly via the
top-level default case).
defaultLabelRepo / verifyBeforeClose each get a non-boolean value (falls back + warns) and an
omitted value (falls back to default silently).
closeDelaySeconds: omitted (default 30), negative (warns, falls back to 30), NaN (warns, falls
back to 30), a fractional value under the cap (floors it), and a value above
MAX_CLOSE_DELAY_SECONDS (clamps to 300).
Deliverables
Test Coverage Requirements
This repo's Codecov codecov/patch gate is 99%+ branch-counted and hard on every changed line. Since
this issue's fix only adds test file lines (not src/** lines), it owes no new patch coverage
itself — but it should bring src/review/linked-issue-hard-rules-config.ts's own branch coverage from
62.50% to 100%, matching its engine twin.
Expected Outcome
src/review/linked-issue-hard-rules-config.ts reaches (or is verified to already effectively reach,
once these cases are added) 100% branch coverage, so the src/ twin's test suite is no longer
silently thinner than its packages/loopover-engine counterpart.
Links & Resources
src/review/linked-issue-hard-rules-config.ts
packages/loopover-engine/src/review/linked-issue-hard-rules-config.ts (fully-covered twin, use its
test file test/unit/linked-issue-hard-rules-config-engine.test.ts as the pattern to mirror)
test/unit/linked-issue-hard-rules.test.ts (file to extend)
Context
src/review/linked-issue-hard-rules-config.tsis a byte-identical "twin" of the canonicalpackages/loopover-engine/src/review/linked-issue-hard-rules-config.ts(they differ only in thetypesimport path — a deliberate directory-scanned parity pair, same pattern as the recent#5779/#4879engine extractions). The engine copy has full branch coverage viatest/unit/linked-issue-hard-rules-config-engine.test.ts, but thesrc/twin's own test(
test/unit/linked-issue-hard-rules.test.ts) only exercises a subset of its normalizer branches,leaving several
src/-side branches never taken by any test that imports from../../src/review/linked-issue-hard-rules-config. A local unshardednpm run test:coveragerun confirms the file sits at62.50% branch coverage (20/32).
Specifically untested branches in the
src/copy (functionsnormalizeMode,normalizeBoolean,normalizeCloseDelaySeconds,normalizeStringList,normalizeLinkedIssueHardRulesConfig):normalizeMode(line 44-49): thevalue === undefinedbranch (return the field default) and theinvalid-string branch (push a warning, fall back to default) are never hit — the existing test only
passes a valid mode (
"block") for one field.normalizeBoolean(line 51-56): both theundefinedbranch and the wrong-type branch (e.g. astring/number instead of boolean) are untested.
normalizeCloseDelaySeconds(line 58-65): theundefinedbranch, the invalid-value branch(negative / NaN / non-number → warning +
DEFAULT_CLOSE_DELAY_SECONDS), and the valid-but-clampedbranch (
Math.min(MAX_CLOSE_DELAY_SECONDS, Math.floor(value))) are all untested against thesrc/export.
normalizeLinkedIssueHardRulesConfig(line 67-68): the top-levelinput === undefinedbranch isuntested.
Because this is a scored
src/**file, any future PR that legitimately touches one of thesefunctions inherits the 99% Codecov patch gate on lines it didn't even mean to change — closing this
gap now removes that latent trap.
Requirements
Add test cases to
test/unit/linked-issue-hard-rules.test.ts(import staysfrom "../../src/review/linked-issue-hard-rules-config") that exercise, for thesrc/exportspecifically:
normalizeLinkedIssueHardRulesConfig(undefined, warnings)returns the all-off default."sometimes") falls back to its default and pushes awarning naming the field.
undefined) resolves to its own default (not just tested implicitly via thetop-level default case).
defaultLabelRepo/verifyBeforeCloseeach get a non-boolean value (falls back + warns) and anomitted value (falls back to default silently).
closeDelaySeconds: omitted (default 30), negative (warns, falls back to 30),NaN(warns, fallsback to 30), a fractional value under the cap (floors it), and a value above
MAX_CLOSE_DELAY_SECONDS(clamps to 300).Deliverables
it(...)blocks intest/unit/linked-issue-hard-rules.test.tscovering the fiverequirement groups above, each asserting both the returned value and the pushed warning text
where applicable.
Test Coverage Requirements
This repo's Codecov
codecov/patchgate is 99%+ branch-counted and hard on every changed line. Sincethis issue's fix only adds test file lines (not
src/**lines), it owes no new patch coverageitself — but it should bring
src/review/linked-issue-hard-rules-config.ts's own branch coverage from62.50% to 100%, matching its engine twin.
Expected Outcome
src/review/linked-issue-hard-rules-config.tsreaches (or is verified to already effectively reach,once these cases are added) 100% branch coverage, so the
src/twin's test suite is no longersilently thinner than its
packages/loopover-enginecounterpart.Links & Resources
src/review/linked-issue-hard-rules-config.tspackages/loopover-engine/src/review/linked-issue-hard-rules-config.ts(fully-covered twin, use itstest file
test/unit/linked-issue-hard-rules-config-engine.test.tsas the pattern to mirror)test/unit/linked-issue-hard-rules.test.ts(file to extend)