cc-triage: skip below-floor versions #1739 (W1h)

Smallest-diff fix: cc-triage.mjs now reads shared/cc-support.json at startup and skips the LLM call for any version below supported_floor. Marks the entry with below_floor: true; the workflow's existing jq 'select(.gap_score >= 10)' filter naturally skips entries with empty features[], so issue filing already does the right thing.

Real-run evidence job timeout

cc-watch run 25632103449 (2026-05-10) attempted to triage every unsnapshotted version — W1b's snapshot-presence filter exposed 100+ ancient versions. The job hit GH Actions' cancellation timeout before finishing.

cc-triage: extracting features from 2.0.59...
cc-triage: extracting features from 2.0.60...
cc-triage: extracting features from 2.0.61...
[... 100+ iterations ...]
##[error]The operation was canceled.

Try it interactive

Implements the same compareSemver used in cc-release-watch.mjs — numeric-tuple compare, no prerelease handling needed (CC versions are X.Y.Z).

Decision matrix

ConditionActionfeatures[]parse_failedbelow_floor
version < supported_floorSKIP LLM[](unset)true
version >= supported_floor, snapshot presentCALL LLMextractedfalse(absent)
version >= floor, LLM fails twiceCALL LLM[]true(absent)
cc-support.json missing/malformedCALL LLM (legacy)extractedfalse(absent)

Why a sentinel field instead of dropping the entry

Two reasons:

Files changed

PathChange
scripts/cc-triage.mjsAdd compareSemver + readSupportedFloor helpers; per-version loop sets below_floor: true and skips callClaude for sub-floor entries
tests/integration/test-cc-triage.shNew Test 8 covering W1h: below-floor entry skipped (no LLM call, no parse_failed), above-floor entry processed normally, no flag leak between entries

Verification