Skip to content

test: pin the score-scaling invariants, not one example - #34

Open
bradAGI wants to merge 2 commits into
trustabl:mainfrom
bradAGI:test/score-scaling-invariants
Open

test: pin the score-scaling invariants, not one example#34
bradAGI wants to merge 2 commits into
trustabl:mainfrom
bradAGI:test/score-scaling-invariants

Conversation

@bradAGI

@bradAGI bradAGI commented Aug 24, 2026

Copy link
Copy Markdown

Depends on #1 (the test suite) — it is the first commit here so CI can run. Review the second commit. Test-only; scan/trustabl-scan.sh is untouched.

Why

Readiness is the engine's overall_score — a float in [0,1] — scaled to an integer percent, and risk is its complement:

SCORE=$(awk -v s="$RAW_SCORE" 'BEGIN{ v = s*100; if (v<0) v=0; if (v>100) v=100; printf "%d", v + 0.5 }')
RISK=$(( 100 - SCORE ))

Those two lines decide what every gate, every artifact and every downstream consumer sees. They were covered by exactly one example: 0.9588 → 96.

One example cannot tell rounding from truncation — 0.9588 truncates to 95 and rounds to 96, but plenty of values agree under both — and it cannot exercise a clamp at all.

What this adds

  • Scaling across the range, including both rounding directions and the half-way boundaries: 0.004 → 0, 0.005 → 1, 0.994 → 99, 0.995 → 100, 1 → 100.
  • The clamp at both ends, for inputs outside the engine's stated [0,1] contract. The engine owns that contract, but a clamp that silently inverted or overflowed would publish a nonsense score.
  • readiness + risk == 100 for every input, with readiness asserted in range — the invariant, rather than a spot check.

Confirmed non-vacuous

A test that never failed proves nothing, so both were mutation-checked against the real script.

Truncate instead of rounding half up:

not ok — readiness: expected '96', got '95'
not ok — risk: expected '4', got '5'
NOT OK 2 — a scan with findings reports the engine's readiness

Drop the upper clamp:

not ok — score above 1 clamps to 100: expected '100', got '150'
NOT OK 17 — readiness is clamped to 0-100

Restored: all 18 test(s) passed.

The scanner is the whole product here — it resolves a release, verifies it,
runs the engine, scales the score, and decides whether the build fails — and
until now nothing checked any of it. A regression in the gate logic or in the
jq that reads the engine's ScanResult would ship silently.

The suite drives the real scan/trustabl-scan.sh. Each test builds an actual
gzipped release tarball containing a stub engine and a real checksums.txt over
it, then puts a stub curl on PATH that serves that directory by URL basename.
The download, sha256 verification, extraction and invocation therefore all run
unmodified; only the network and the engine binary are substituted.

The fixtures are unmodified output from a real `trustabl scan` (engine v0.1.7),
so the assertions pin the scanner against the ScanResult shape the engine
actually emits rather than a hand-written approximation of it.
Readiness is the engine's overall_score — a float in [0,1] — scaled to an
integer percent, and risk is its complement. Those two lines decide what every
gate, every artifact and every downstream consumer sees, and until now they
were covered by a single example: 0.9588 -> 96.

One example cannot distinguish rounding from truncation, and cannot see a clamp
at all. Three tests replace it:

  - scaling across the range, including both rounding directions and the
    half-way boundaries (0.004 -> 0, 0.005 -> 1, 0.994 -> 99, 0.995 -> 100)
  - the clamp at both ends, for inputs outside the engine's stated contract
  - readiness + risk == 100 for every input, with readiness in range

Confirmed non-vacuous by mutation. Truncating instead of rounding half up:

  not ok — readiness: expected '96', got '95'

Dropping the upper clamp:

  not ok — score above 1 clamps to 100: expected '100', got '150'

No production change; scan/trustabl-scan.sh is untouched.
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