| name | benchguard-programbench-audit |
| description | Audit ProgramBench-style cleanroom benchmark tasks for verified fairness blockers: hidden/non-discoverable CLI flags, subcommands, env/config behavior, and active tests that require undefined, accidental, platform-specific, TTY, timing, or implementation-artifact behavior. Use when the user asks to review ProgramBench tasks, cleanroom reproducibility, from-scratch reimplementation fairness, active tests, hidden interfaces, or benchmark issues. |
BenchGuard ProgramBench Audit
Audit ProgramBench benchmark tasks themselves, not agent submissions. The
controlling principle is:
Report benchmark issues when active scored tests require behavior that a
from-scratch cleanroom author cannot reasonably discover, infer, or reproduce
from the cleanroom task contract, and the issue is verified against current
artifacts.
This skill has two v1 audit types:
discoverability: active tests depend on behavior absent from the cleanroom
start-state artifacts. This includes target-native CLI flags, short flags,
subcommands, env vars, config paths, and exact native warnings or side effects
when they are active scoring requirements.
test-validity: active tests encode unfair or non-normative behavior such as
undefined behavior, overflow accidents, platform artifacts, fragile terminal
assumptions, or accidental implementation details.
Do not analyze agent submissions as the audit target. If the user provides an
agent submission or trajectory, use it only as optional context and keep findings
about the benchmark task.
Inputs
Require a local ProgramBench checkout path and one or more task IDs, unless the
user explicitly asks to audit all tasks. Do not run all tasks unless the user
explicitly asks for all tasks; if task IDs are missing, ask which task IDs to
audit.
Accept an audit type of discoverability, test-validity, or both; default to
both when the user does not specify. Default output directory:
benchguard-output/programbench-audit/.
All-Tasks Mode
When the user explicitly asks to audit all tasks, enumerate task IDs from the
provided ProgramBench checkout using the benchmark's task metadata. In the
standard source checkout layout, this is typically
src/programbench/data/tasks/*/; if that path is not present, discover the task
list through the installed ProgramBench package or available ProgramBench CLI
metadata instead of assuming the checkout is invalid.
For each discovered task ID, verify that task metadata includes task.yaml and
tests.json before scheduling it for audit. State that an all-tasks run may pull
many Docker images and public test blobs, consume substantial disk, and take a
long time.
Prefer an orchestrated batch workflow:
- Create one top-level timestamped run directory for the full audit.
- Maintain an
all_tasks_manifest.json with each task's status: pending,
running, complete, partial, failed, or skipped, plus artifact paths
and failure reasons.
- Split task IDs into small disjoint batches.
- If the runtime supports delegated or parallel agents and the user has
requested or approved parallel work, assign each worker a disjoint batch and
require it to write only that batch's
artifacts/<task_id>/ and
per_task/<task_id>.json outputs.
- Do not launch one worker per task by default; use bounded concurrency.
- The main agent remains responsible for final aggregation into
report.md and
report.json.
- If parallel delegation is unavailable or not approved, run batches serially.
- Preserve partial results and record failed, skipped, or incomplete tasks
rather than restarting the full run.
References
Read only what is needed:
references/programbench-discoverability.md: cleanroom-visible corpus,
candidate extraction, cross-reference, and runtime probe procedure.
references/programbench-test-validity.md: unfair-test patterns and
classification policy.
references/false-positive-guardrails.md: cases that must not become
findings.
references/taxonomy.md: category, severity, finding type, and confidence
rules.
references/output-format.md: report layout and BenchGuard-compatible schema.
Always read false-positive-guardrails.md, taxonomy.md, and
output-format.md. Read the audit-specific reference for the requested audit
type.
Workflow
-
Validate context.
- Confirm task metadata can be resolved for each requested task. In the
standard source checkout layout, this usually means
src/programbench/data/tasks/<task_id>/task.yaml and tests.json.
- Verify each requested task ID exists.
- If the user asked for all tasks, state that this may pull many Docker
images and test blobs before proceeding.
-
Create a run directory.
- Use
<output_dir>/<timestamp>/.
- For each task, create
artifacts/<task_id>/.
- All evidence must be generated during this run. Do not rely on old survey
paths such as
/tmp/pb_survey as primary evidence. Existing caches created
by ProgramBench, Docker, or HuggingFace may be reused by the underlying
tools, but still record the commands and current outputs.
-
Load ProgramBench metadata.
- Read
task.yaml for repository, commit, language, and hashes.
- Read
tests.json for active branches, ignored branches, ignored tests, and
ignore reasons.
- Exclude ignored branches and ignored tests from bug evidence.
- Normalize active and ignored test names before matching evidence. ProgramBench
metadata may use
tests.* or eval.tests.*, may include class-qualified
pytest names, may include parametrization suffixes, and ignored_tests may
contain objects with a name field rather than plain strings. Build alias
sets for these spellings and do not treat an occurrence as inactive until
these aliases have been checked.
-
Sync public test sources.
- Run
uv run programbench blob sync <task_id> from the ProgramBench
checkout.
- Capture the cache path printed by the command.
- Locate active branch files under that cache. Extract and index the full
eval/ tree for context, including eval/tests/*.py, eval/conftest.py,
helper modules, eval/README*, and test resources. Active scoring evidence
still must be tied back to a non-ignored test listed in tests.json.
- If blobs cannot be synced, write a partial report explaining the blocker.
-
Pull and inspect the cleanroom image.
- Image name is
programbench/<task_id with "__" replaced by "_1776_">:task_cleanroom.
- Run
docker pull and docker image inspect.
- Record image name, repo digest or image id, platform, and command outputs.
- If Docker is unavailable, write a partial report and mark runtime/corpus
checks as not performed.
-
Generate cleanroom-visible artifacts.
- Collect only what a cleanroom agent may observe: readable docs/files and
executable behavior through normal invocation.
- Do not decompile, use
strings, inspect binary bytes, or read hidden source
material.
- Write
cleanroom_visible_corpus.txt, cleanroom_commands.log, and
cleanroom_manifest.json under the task artifact directory.
-
Run requested audits.
- For
discoverability, follow programbench-discoverability.md.
- For
test-validity, follow programbench-test-validity.md.
- When
test-validity is in scope, run the explicit active-test sweeps in
programbench-test-validity.md; do not treat test-validity as optional
commentary after discoverability extraction. If these sweeps are not
completed, mark the audit partial.
- Do not stop at long-flag extraction. ProgramBench audits must include
env/config and subcommand discovery because those are normal target
interface channels.
- Do not drop candidates solely because a first occurrence pass found zero
active tests. If a candidate is present in active branch blobs or a prior
candidate seed but active occurrence mapping is empty, audit the name
normalization, helper-wrapper, and
eval/ context path before marking it
non-active.
- Do not gate finding promotion on whether a candidate came from a seed list.
Seeded, static, AST-derived, wrapper-derived, and runtime-derived candidates
are all eligible for findings when they meet the evidence standard.
- Do not use task size as a reason to silently mark all candidates
inventory-only. For large tasks, batch verification, prioritize high-signal
candidates, or mark unverified candidates as
needs_manual_review or
partial, but report the automation gap in report.md.
- Apply
false-positive-guardrails.md before reporting any finding.
-
Verify findings.
- Before writing final reports, reread each proposed finding against the
generated artifacts and
false-positive-guardrails.md.
- Confirm the cited tests are active, ignored metadata was checked, the
behavior is target-native or otherwise unfair, cleanroom absence was
checked across all visible docs/help, runtime probe evidence exists when
claimed, and the category/severity follows
taxonomy.md.
- For cleanroom absence, require exact candidate-aware matching. Do not count
substring hits as documentation:
-download does not document -d, a
generic word in prose does not document a subcommand, and case-insensitive
or file-path-only hits are ambiguous until a human-readable help/doc entry
is confirmed.
- Drop regex-only or weak candidates. Downgrade findings when the evidence
proves only a review concern.
- Record the verification disposition in
candidate_inventory.json.
-
Write reports.
- Write
report.json, report.md, and per_task/<task_id>.json.
- Include
metadata.tool: "benchguard-programbench-skill",
audit_mode: "programbench_discoverability_test_validity", and
version: "0.1.0".
report.md must be explanatory, not only a list of evidence paths. For
every finding, include a one-sentence finding, why it is unfair for
cleanroom reproduction, what the active tests require, concrete active-test
snippets, which active tests should be ignored until fixed, cleanroom
visibility status, ignored-test status, runtime or strong-evidence status,
and the recommendation.
- Include reproduction commands, image identity, active-test references,
ignored-test checks, cleanroom absence evidence, probe logs when available,
and artifact paths for each finding.
- In
report.json and each per_task/<task_id>.json, include a
machine-readable evidence.programbench.tests_to_ignore list for every
finding. Generate it from candidate_evidence[].active_occurrences[],
deduplicated by branch and test name. Each entry should identify branch,
test name, file, line when available, candidate behavior, ignore reason,
and action.
- Treat candidates as the issue reason, not the test list. The actionable
test list comes from active occurrences and active test references.
- If confidence is
LIKELY rather than CONFIRMED, explicitly state which
verification step was not completed, such as candidate-specific runtime
probing.
-
Summarize.
- State audited tasks, audit types, BUG/WARNING counts, and the highest-impact
findings.
- Include the report paths.
- State any checks that could not be completed.
Finding Discipline
Default to WARNING. Upgrade to BUG only when active scored tests plus
cleanroom/test evidence show concrete benchmark harm.
Typical confirmed BUG cases:
- Active tests require a CLI flag, subcommand, or target-native env/config
behavior that is absent from cleanroom-visible artifacts and accepted by the
cleanroom executable.
- Active tests require an exact native warning, error, exit, side effect, or
config-file behavior that is not inferable from cleanroom-visible artifacts
and rejects reasonable from-scratch implementations.
- Active tests require undefined behavior, overflow artifacts, accidental libc
or platform behavior, or implementation details that should not define the
public task contract.
- Active tests require invalid or out-of-range numeric inputs to behave like a
specific native parser accident, such as C
atoi() overflow/wraparound,
strtol truncation, or accepting partial numeric prefixes, when the
cleanroom-visible contract does not specify that behavior.
Regex-only candidates are not findings. Candidate extraction is a recall step;
reporting requires active-test evidence, cleanroom absence evidence, target or
unfairness classification, runtime probe or strong native-behavior evidence, and
false-positive review.