Skip to content

fix(scripts): check-skill-precompute-compose.sh argument parser is never exercised by its test suite #2708

Description

@kyle-sexton

Found by a measured mutation run while piloting the detector-findings producer contract (#2680). Filed separately because it is a real defect in this repo's own tooling, independent of that pilot.

The gap

scripts/check-skill-precompute-compose.sh:30:

while [[ $# -gt 0 ]]; do
  case "$1" in
  --strict) STRICT=1; shift ;;
  -h | --help) usage ;;
  -- | --all | --paths)
    POSITIONAL+=("$1")
    shift
    break
    ;;
  *)
    POSITIONAL+=("$1")
    shift
    ;;
  esac
done

Mutating -gt 0 to -ge 0 survives the full suite (scripts/check-skill-precompute-compose.test.sh, baseline green, 5 tests).

It survives because every existing test enters through the -- | --all | --paths) branch, which breaks out of the loop before $# reaches 0. Nothing drains arguments through the *) fall-through, so the loop's termination condition is unasserted.

Why it matters

The script runs set -uo pipefail (line 17). With the mutation, once $# reaches 0 the loop body still executes and case "$1" hits an unbound variable. Measured behavior of the mutant, run from a real checkout:

Invocation Original Mutant
(no args) usage, exit 2 line 31: $1: unbound variable, exit 1
--strict usage, exit 2 line 31: $1: unbound variable, exit 1
<base-ref> scans, exit 0 line 31: $1: unbound variable, exit 1
--strict <base-ref> scans, exit 0 line 31: $1: unbound variable, exit 1
--all scans, exit 0 scans, exit 0 (identical — break fires first)

So five of six invocation shapes break outright and the suite still reports green. The surviving mutant is not itself interesting; the oracle gap it reveals is — the argument parser has no coverage except through the one branch that short-circuits it.

Suggested fix

Add a case to scripts/check-skill-precompute-compose.test.sh that invokes the script with a bare base-ref argument (no --all, no --paths) and asserts it reaches the scan rather than erroring. A case passing --strict ahead of a base-ref would cover the *)-then-drain path as well.

Reproduction

Copy the script and its test into a scratch directory (the test resolves its subject as $(dirname "$BASH_SOURCE")/check-skill-precompute-compose.sh), apply sed -i '30s/-gt 0/-ge 0/' to the copy, and run the test — it exits 0.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions