Skip to content

Add a test suite to t3-hardware-scoring, and fix what it found - #1

Merged
luckiday merged 3 commits into
mainfrom
improve/tests-and-strictness
Aug 7, 2026
Merged

Add a test suite to t3-hardware-scoring, and fix what it found#1
luckiday merged 3 commits into
mainfrom
improve/tests-and-strictness

Conversation

@luckiday

@luckiday luckiday commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

The skill had no tests. Adding them turned up three bugs that change audit
verdicts, plus a set of documentation that had drifted from the code it
describes.

What the tests found

Both fully worked examples in t3-classification.md disagreed with the script
they document.

Example Doc says v2.1 script said
Gray Zone Toy + Trash (Gray Zone) Trash (Gray Zone)
Eagle Eye final_label: "Tool + Trash" Tool + Trash (Eagle Eye)

The Gray Zone case failed because the Litmus Gate override (Step 3 rule 2) was
documented but never implemented, so resolution fell through to the composite
and picked the opposite category.

A missing litmus_gate was read as "No", silently. The three
*-auditor.md guides show a JSON body — under a heading reading "MUST Follow
This Structure" — with no top-level litmus_gate, while synthesize_results.py
reads exactly that field with a "No" default. An auditor following its own
rubric produced a report whose gate silently read No. The gate is one of only
four conditions deciding the primary classification:

v2.1 : gates read as {tool: No, toy: No, trash: No} -> Low confidence, exit 0
v2.2 : refuses -> 'tool' report is missing the top-level litmus_gate field

An empty critical_issues shadowed a populated one. When the top-level
array was empty but extract_for_report.critical_issues was not, the veto
silently did not fire — turning a vetoed product back into a clean Tool. This is
a safety veto, so disagreement between the two copies now errs toward firing it,
and the validator flags the disagreement.

The Eagle Eye trigger set differed across four files. trash-red-flags.md
defined 14 patterns, trash-auditor.md listed 5, and eagle-eye-validator.md
claimed "the 6 canonical" triggers while omitting Core Flaw — which the auditor
guide did list. The Trash Auditor scored against one list while the Eagle Eye
Validator reviewed its work against another.

What changed

Tests — 136 of them, wired to CI, stdlib-only so there is no install step.

tests/fixtures/golden-ai-pendant/ is a complete worked audit of a fictional
product: Brand-Blinded source text, all three auditor reports, and the
classification they synthesize to. It doubles as the reference for what a
finished report looks like — the rubric guides only ever showed fragments with
... placeholders.

The strongest test is test_every_quote_exists_in_the_source_text: every string
in every verbatim_evidence array must appear in 02-brand-blinded.md. Zero
hallucination is the skill's central claim, and this makes it checked rather
than asserted.

Step 3.5 is a script, not prose. validate_auditor_json.py replaces the
hand-merge instructions: it checks item coverage, that totals equal the sum of
their items, the evidence-first rule, gate consistency, and that every
"Triggered:" item has a matching critical_issues entry — then builds
auditor_reports.json by copying rather than retyping. It refuses to merge on
any error.

One canonical trigger list. trash-red-flags.md now opens with a Canonical
Trigger Index; the other copies are pinned to it by
test_trigger_consistency.py. The duplication is deliberate — an auditor
subagent reads one rubric file and should not need to open a second to know what
fires — so the copies are pinned rather than merged.

Web crawling removed. crawl_product_info.py used requests.get plus regex
HTML stripping, which cannot handle JS-rendered pages; Step 1 now uses the host
agent's own web tools. It also declared beautifulsoup4 as a dependency without
ever importing it. The skill is now stdlib-only.

Also fixed: added the missing references/trash-auditor-template.md, which
trash-auditor.md had pointed at since v2.0; added
.claude-plugin/marketplace.json so the plugin install path the README
documents actually resolves; documented display_label in report-schema.md;
renamed defluff-guide.md, whose central rule is "do NOT delete hype", to
brand-blinding-guide.md; removed the deprecated peer-review-guide.md; and
corrected README references to tooling that was never committed.

final_label now stays clean for leaderboard grouping while display_label
carries the annotations — which also stops (Gray Zone) being dropped whenever
Eagle Eye fired too.

Verification

20 deliberate mutations were introduced to confirm the suite actually detects
breakage — every threshold, the composite direction, the veto, the gate
override, and each validator check. All 20 are caught. Two tests that initially
passed for the wrong reason were tightened. The suite was re-run from a fresh
clone to confirm it depends on nothing untracked.

🤖 Generated with Claude Code

luckiday and others added 3 commits August 7, 2026 16:35
The skill had no tests, and both fully worked examples in
t3-classification.md disagreed with the script they document:

  - The Gray Zone example expects "Toy + Trash (Gray Zone)". The Litmus
    Gate override it relies on (Step 3 rule 2) was documented but never
    implemented, so the script returned "Trash (Gray Zone)".
  - The Eagle Eye example expects final_label "Tool + Trash". The script
    baked the annotation into the label field itself.

A third bug had no example to contradict: the three *-auditor.md rubric
guides show a JSON body with no top-level litmus_gate, while
synthesize_results.py reads exactly that field with a "No" default. An
auditor following the rubric guide verbatim produced a report whose gate
silently read No — one of only four primary-classification conditions,
lost without a warning or a non-zero exit.

Changes:

  - tests/ with 79 unit tests, an end-to-end golden case, and a link
    checker, wired to CI. Fixtures hold a complete worked audit of a
    fictional product; the strongest test verifies every verbatim_evidence
    quote actually appears in the brand-blinded source, which turns the
    zero-hallucination claim into something checked rather than asserted.
  - Implement the Gray Zone gate override and the negative-composite
    secondary rule; split final_label (parseable) from display_label
    (annotated), which also stops "(Gray Zone)" being dropped whenever
    Eagle Eye fired too.
  - Missing or malformed litmus_gate/total_score is now a hard error.
  - scripts/validate_auditor_json.py replaces the hand-merge prose of Step
    3.5: it checks arithmetic, item coverage, the evidence-first rule and
    the trigger/critical_issues correspondence, then builds
    auditor_reports.json by copying rather than retyping.
  - Add the missing references/trash-auditor-template.md, which
    trash-auditor.md had pointed at since v2.0.
  - Drop crawl_product_info.py in favour of the host agent's web tools,
    and drop the now-unused requests/beautifulsoup4 dependencies. The
    skill is stdlib-only, so it installs with no Python environment.
  - Drop the deprecated peer-review-guide.md, and fix README paths to
    tooling that was never committed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four files enumerated the triggers and three of them disagreed:

  trash-red-flags.md            14 patterns  (the real set)
  trash-auditor.md               5 patterns
  eagle-eye-validator.md         6 patterns, and omitted Core Flaw —
                                 which trash-auditor.md did list

The Trash Auditor scored against one list while the Eagle Eye Validator
reviewed its work against a different one, so nine patterns could never
be scored and Core Flaw could be scored but never revalidated.

trash-red-flags.md is now the single source of truth: it opens with a
Canonical Trigger Index of all 14 patterns and their items, and the other
copies are regenerated from it. The duplication stays deliberately — an
auditor subagent reads one rubric file and should not need to open a
second to know what fires — so the fix is to pin the copies, not merge
them. test_trigger_consistency.py fails the build when any copy, or the
pattern table in validate_auditor_json.py, drifts from the index.
Verified by mutation: dropping a row, changing an item id, and editing
the code table each fail the suite.

Also fixed along the way:

  - A blank line inside the Honesty table split Architectural
    Implausibility into its own broken one-row table.
  - validate_auditor_json.py now checks that a "Triggered:" reason names
    a canonical pattern and lands on that pattern's item, instead of only
    checking the item was trigger-capable.
  - Three pattern names contain a period ("Price vs. Doubt"), so parsing
    the name by splitting the reason on its first period yields
    "Price vs". trigger_pattern() matches known names longest-first.
  - The golden fixture said "Subscription Trap" where the canonical name
    is "Subscription Trap / Brick" — caught by the new test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A sweep over everything the earlier passes had not verified. Suite goes
from 92 to 136 tests, and 20 deliberate mutations are now all caught.

Correctness:

  - An empty top-level critical_issues silently shadowed a populated
    extract_for_report.critical_issues, turning a vetoed product back
    into a clean Tool. This is a safety veto, so where the two copies
    disagree it now errs toward firing; the validator flags the
    disagreement itself.
  - The validator collapsed a duplicated item ID across two sections,
    so the arithmetic check passed against the wrong evidence.
  - The validator now checks that a "Triggered:" reason names a real
    pattern and lands on that pattern's item, not merely that the item
    was trigger-capable.

Metadata that did not describe reality:

  - report-schema.md never documented display_label, though SKILL.md
    Step 6 tells the agent to use it. Added, with gray_zone and the
    real confidence values.
  - references/defluff-guide.md is titled "Brand Blinding Guide" and its
    central rule is "do NOT delete hype" — a filename that instructs the
    opposite of the file. Renamed to brand-blinding-guide.md.
  - eagle-eye-validator.md never said where Step 4's diffs get applied.
    Now states 03-*.json then re-merge, so totals stay derived.
  - Added .claude-plugin/marketplace.json, so the plugin install path
    the README documents actually resolves. Schema taken from two
    working marketplaces rather than guessed, and a test asserts every
    listed path exists and every skill on disk is published.

New guards, each verified by mutation:

  - Auditor templates are the JSON subagents copy: all three must parse,
    carry exactly their rubric's item IDs, agree with their own scoring
    table, and declare the fields the scripts read.
  - report-schema.md's chart dimension maxima must sum to each role's
    total, so they cannot outlive a rubric change.
  - Version, skill name, and stdlib-only imports are checked, the last
    via AST — a prose line beginning "from a source file" reads as an
    import to a grep.
  - CLI exit codes for both scripts, including that a refused merge
    leaves no partial output and that merge output feeds the synthesizer.

Two earlier tests passed for the wrong reason and were tightened: a
critical_issues assertion that the new top-vs-nested check also
satisfied, and a missing case for a pattern scored on the wrong item.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@luckiday
luckiday merged commit c0132f2 into main Aug 7, 2026
1 check passed
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