Skip to content

Add --no-heuristics CLI flag and heuristics_filter audit (v0.21 E5)#121

Open
pengfei-threemoonslab wants to merge 2 commits into
mainfrom
feat/v021-no-heuristics-flag
Open

Add --no-heuristics CLI flag and heuristics_filter audit (v0.21 E5)#121
pengfei-threemoonslab wants to merge 2 commits into
mainfrom
feat/v021-no-heuristics-flag

Conversation

@pengfei-threemoonslab
Copy link
Copy Markdown
Contributor

Summary

Closes round-3 / round-4 review's E5: Either --no-heuristics flag OR formal provenance_kind retirement carryover. We ship the flag.

Finding.provenance_kind has shipped on every report since v0.15 as required + non-nullable wire metadata, but had no consumer for four review cycles. v0.21 lands the consumer the field was always designed for: a security/GRC-friendly filter that excludes findings whose provenance is keyword_heuristic or regex_heuristic from the active release-gating set.

  • New --no-heuristics flag on agents-shipgate scan (stable in 0.x). Findings whose provenance_kindNO_HEURISTICS_EXCLUDED_PROVENANCE_KINDS are marked suppressed=True with suppression_reason="filtered by --no-heuristics" before the release decision is built. Filtered findings remain in findings[] for transparency; they no longer gate release.
  • New top-level report.heuristics_filter audit envelope (required, always present — parallel to privacy_audit). Fields: enabled, excluded_provenance_kinds: list[str], filtered_finding_count, filtered_by_kind: dict[str, int]. Earns provenance_kind's contract weight by giving it a first-class consumer.
  • Manifest-driven suppression wins on overlap: a finding the user explicitly suppressed via checks.ignore keeps the user's reason text. The audit envelope still counts the overlap.
  • Schema bump: report_schema_version: "0.20""0.21". v0.20 moves to frozen-reference; existing v0.20 consumers ignore the new field (purely additive).
  • Contract-stamp pin in docs/architecture.md bumped to date 2026-05-23, report v0.21.

Decision recorded — why ship, not retire

Round-4 review's E5 offered ship-or-retire on provenance_kind. Retiring would have forced a deprecation cycle on a stable-contract field used by every report since v0.15. Shipping the flag earns the field's weight and serves a real audience (security/GRC reviewers triaging declared-only findings before promotion). The flag is opt-in; nothing changes for current callers.

Test plan

  • pytest -q1820 passed, 4 skipped, 0 failed
  • ruff check . — clean
  • 11 new tests in tests/test_no_heuristics.py covering:
    • Pure-function filter semantics (KEEP / FILTER classifications per provenance_kind)
    • Envelope shape parity across enabled=True/False
    • Manifest-suppression preservation
    • Contract-list completeness (every value in NO_HEURISTICS_EXCLUDED_PROVENANCE_KINDS is a real ProvenanceKind; KEEP+EXCLUDE partition is exact)
    • End-to-end run_scan(no_heuristics=True) (envelope populated, blockers preserved, review_items shrink)
    • CLI subprocess smoke test
    • Monotone-non-increasing reviewer-summary lens counts under filtering
  • Sample fixture diffs reviewed (samples/* regenerated for v0.21 schema bump)
  • Contract-stamp test (test_architecture_doc_contract_stamp_matches_runtime) updated in lockstep

🤖 Generated with Claude Code

pengfei-threemoonslab and others added 2 commits May 22, 2026 23:26
Closes round-3 / round-4 review's E5 carryover. `Finding.provenance_kind`
has shipped on every report since v0.15 as required+non-nullable wire
metadata but had no consumer for four review cycles. v0.21 lands the
security/GRC-friendly consumer the field was always designed for: a
filter that excludes findings whose provenance is `keyword_heuristic`
or `regex_heuristic` from the active release-gating set.

Wire surface (additive, schema bumped 0.20 -> 0.21):
- New `--no-heuristics` flag on `agents-shipgate scan` (stable in 0.x).
  When set, findings whose `provenance_kind` is in the EXCLUDE set
  (today: keyword_heuristic, regex_heuristic) are marked
  `suppressed=True` with `suppression_reason="filtered by --no-heuristics"`
  BEFORE the release decision is built. Filtered findings remain in
  `findings[]` for transparency; they no longer gate release.
- New top-level `report.heuristics_filter` audit envelope. Required +
  always present on emitted scans regardless of whether the flag was
  set (parallel to `privacy_audit`). Fields: `enabled`,
  `excluded_provenance_kinds`, `filtered_finding_count`,
  `filtered_by_kind`. Earns `provenance_kind`'s contract weight by
  giving it a first-class consumer.

Decision recorded: round-4 review offered ship-or-retire. We ship.
Retiring would force a deprecation cycle on a stable-contract field
used by every report since v0.15; shipping the flag earns the weight
and serves a real audience (security/GRC reviewers triaging
declared-only findings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…iew)

Addresses PR #121 review:

[P1] v0.21 schema now enforces heuristics_filter as a real, non-nullable,
fully-shaped envelope. Without these changes the schema accepted payloads
with the field missing, null, or {}, contradicting STABILITY/AGENTS
saying it's required + always present.
- scripts/generate_schemas.py: add `heuristics_filter` to the top-level
  `schema["required"]` list; tighten `properties["heuristics_filter"]`
  to `{"$ref": "#/$defs/HeuristicsFilter"}` (parallel to privacy_audit,
  reviewer_summary); set HeuristicsFilter's $defs `required` to all
  four fields (enabled, excluded_provenance_kinds,
  filtered_finding_count, filtered_by_kind).
- docs/report-schema.v0.21.json regenerated.
- New negative schema test in tests/test_no_heuristics.py
  (`test_v21_schema_requires_heuristics_filter_and_rejects_null`)
  parallel to the v0.12 agent_summary regression test: real payload
  validates, but strip-field / set-null / set-{} / drop-sub-field all
  raise jsonschema.ValidationError.

[P2] docs/architecture.md pipeline diagram now shows
`apply_no_heuristics_filter` BEFORE `core/findings.build_report` (which
calls `build_release_decision`), matching the actual runtime ordering
in `_run_checks_and_decide` (scan.py:641). Stamped doc no longer teaches
the reverse ordering — preserves the main safety property of the flag
(filtered findings cannot gate release).

[P3] AGENTS.md stable-flag table for `agents-shipgate scan` now lists
`--no-heuristics`, matching STABILITY.md. This is the file downstream
agents ingest.

Test gap: `test_keep_list_is_explicit_and_non_overlapping` was
tautological (`kept = valid - excluded` then asserting the partition is
exact). Replaced with explicit pin of EXPECTED_KEEP and EXPECTED_EXCLUDE
sets — a new `ProvenanceKind` literal now fails the test until it's
deliberately classified.

llms-full.txt regenerated to pick up the AGENTS.md flag-table change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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