Table of Contents generated with DocToc
Capability: substrate:analytics
Harness: agnostic
Dry-run the bulk-mode pre-flight classifier against a real or replayed tracker. Use to measure skip-rate before / after any rule change — closes the tune-then-verify loop so rule edits are made against evidence, not guesswork.
uv (stdlib only, no third-party deps).gh (GitHub CLI) for live mode; replay mode needs none.gh authenticated to the tracker repo (live mode only).gh (live mode); replay mode runs fully offline.The bulk-mode pre-flight classifier (bulk-mode.md § Pre-flight no-op classifier) decides whether to dispatch a subagent for each tracker in a bulk sync. Its rule table evolves as we learn how real adopter trackers behave. Each rule change needs a before / after measurement to know whether the change helped (more skips) or hurt (false-positive skips that miss real work).
Without a tool, that measurement is a one-off Python script per PR — easy to lose, hard to reproduce, can't be wired into CI. This tool makes the measurement reusable.
uv run --directory tools/preflight-audit preflight-audit classify [options]
Fetch tracker state via gh api graphql and classify:
uv run --directory tools/preflight-audit preflight-audit classify \ --repo <owner>/<name> \ --issues 221,232,233,242,244
--issues is a comma-separated list of issue numbers (with or without # prefix). For the full sync all set, resolve the list yourself via gh issue list --json number and pipe the numbers in — the tool intentionally doesn‘t reimplement selector resolution (that’s the sync skill's job).
Pass --bot-logins login1,login2 to extend the bot-equivalent login list for an adopter with personal-account bots.
Classify a pre-fetched GraphQL response — for CI / regression testing without network calls:
uv run --directory tools/preflight-audit preflight-audit classify \ --load tests/fixtures/sample_response.json \ --now 2026-05-31T12:00:00Z
--now is required for replay mode to keep the classification deterministic (rules depend on “days ago” calculations).
Default is a human-readable grouped table:
Total trackers: 43 dispatch: 29 (67%) dispatch-urgent: 0 (0%) skip-noop: 14 (32%) --- skip-noop (14) --- # 221 OPEN last=<bot> [skill] → fix released; awaiting advisory; skill-last (1d) labels: airflow+cve allocated+fix released ... === Estimated savings === Subagents skipped: 14 → ~700 KB context saved (~175000 tokens @ 250 tok/KB)
Pass --json for machine-readable output (one object per tracker with number, decision, reason, label set).
The classifier in src/preflight_audit/classifier.py is the executable spec of the rule table in .claude/skills/security-issue-sync/bulk-mode.md. The skill instructs the orchestrator how to apply the rules prose-by-prose; this tool implements them in code. Both forms describe the same rules and must be edited in lock-step — a PR that changes one should change the other.
The tests in tests/test_classifier.py cover each rule with a focused synthetic-input case. If the skill's rule table grows a new entry, add the matching test_rule_N_* case here.
The intended workflow when changing a rule:
preflight-audit classify --repo <r> --issues <list> against your adopter tracker to capture the before distribution.bulk-mode.md AND the matching condition in classifier.py.For tests, save the captured GraphQL response as a fixture and add a replay-mode test that asserts the expected classification breakdown — that's the eval-fixture pattern.