Skip to content

feat(guard): injection-phrase FP instrumentation (Refs #12)#81

Merged
ernestprovo23 merged 1 commit into
mainfrom
feat/issue-12-fp-instrumentation
Jul 14, 2026
Merged

feat(guard): injection-phrase FP instrumentation (Refs #12)#81
ernestprovo23 merged 1 commit into
mainfrom
feat/issue-12-fp-instrumentation

Conversation

@ernestprovo23

Copy link
Copy Markdown
Member

Summary

Ships the unblocked slice of #12 — the instrumentation operators need to collect field false-positive (FP) evidence for WRD-RES-INJECT-PHRASEwithout changing any default posture. Per the CSO scoping, the default-block flip stays gated (no field FP data yet, and INJECT-PHRASE error-replaces the whole tool result), so this PR references #12, it does not close it.

WRD-RES-INJECT-PHRASE keeps its tier (MONITOR), its default action (monitor-only), and its position in guard_result.error_rules. No matching was broadened toward regex/fuzzy (RESULT_INSPECTION.md §9 respected).

What shipped

  1. Structured matched_phrases. A discrete matched_phrases[] on the INJECT-PHRASE finding, threaded through emit_res.result_finding_to_dict (JSONL) and a matchedPhrases SARIF property — per-phrase aggregation without parsing prose.
  2. Inspected-frame denominator. frames_inspected counted in both guard and inspect, emitted as a run-summary JSONL record (kind: "run-summary") + SARIF run property — the base rate for a per-phrase FP rate.
  3. Per-phrase opt-in block. --block-inject-phrase-only <file> blocks ONLY the named exact phrases while every other curated phrase stays monitor. Default-off, narrower than --block-inject-phrase, and the future deterministic-subset promotion mechanism. Reflected honestly in the startup posture banner.
  4. Operator FP-collection workflow docs. docs/RESULT_INSPECTION.md §10 documents the record → inspect → label loop and the graduated promotion path.

Security (non-negotiable)

The telemetry surface emits only the curated denylist phrase, rule id, tool/server metadata, action, and counts — never raw result content (which can carry secrets/PII, per WRD-RES-SECRET-ECHO). Aggregation is local-only; no phone-home. A dedicated test (test_no_raw_result_content_leaks_into_inject_phrase_telemetry) asserts distinctive raw markers never reach the emitted JSONL/SARIF record.

Verification

  • pytest — 604 passed, 2 skipped; whole-project coverage 86.6% (floor 80, replicated with COVERAGE_PROCESS_START=pyproject.toml as CI does).
  • ruff check . — clean.
  • pip-audit — no known vulnerabilities.

Issue #12 status

Remains open. This is the prerequisite evidence-collection work; the default-block flip stays gated on the FP data this instrumentation collects.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QofWZ4MivqEKPevjSYuwdk

Ship the unblocked, non-default-changing slice of issue #12 so operators can
collect field false-positive data for WRD-RES-INJECT-PHRASE without flipping any
default. No tier, default action, or error-replacement membership changes.

- Add a discrete matched_phrases[] to the INJECT-PHRASE finding, threaded through
  the JSONL record and a matchedPhrases SARIF property, so per-phrase aggregation
  reads a structured field instead of parsing the free-text message.
- Count inspected tools/call result frames (frames_inspected) in guard and
  inspect and emit it as a run-summary JSONL record + SARIF run property, giving a
  per-phrase FP rate its base-rate denominator.
- Add --block-inject-phrase-only <file>: a default-off, per-phrase opt-in that
  blocks ONLY the named exact phrases while all other curated phrases stay
  monitor. Narrower than --block-inject-phrase; the future deterministic-subset
  promotion mechanism. Surfaced honestly in the startup posture banner.
- Document the operator record -> inspect -> label FP-collection loop in
  RESULT_INSPECTION.md section 10.

Security: the telemetry surface emits only the curated denylist phrase, rule id,
tool/server metadata, action, and counts -- never raw result content (which can
carry secrets/PII). Local-only, no phone-home. Covered by a dedicated no-leak
test asserting raw content never reaches the emitted record.

Tests: matched_phrases correctness, frame denominator, per-phrase selective
block (named blocks, unnamed stays monitor), and the no-raw-content assertion.
Whole-project coverage 86.6% (floor 80).
@ernestprovo23
ernestprovo23 merged commit ca3e212 into main Jul 14, 2026
10 checks passed
@ernestprovo23
ernestprovo23 deleted the feat/issue-12-fp-instrumentation branch July 14, 2026 01:42
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