Skip to content

[business-logic] verify_suppress.go: output-hiding (2>/dev/null) on non-verification commands accumulates forever without warning — contradicts 'any suppression ≥2' contract #160

Description

@topcheer

File/Line

  • internal/agent/verify_suppress.go L128-154 (threshold logic), wired at internal/agent/agent.go L3575

Problem

The comment contract states: "Any suppression on non-verification commands = warn after 2 occurrences". The implementation only honors it for error-masking:

} else {
    maskCount := 0
    for _, c := range s.suppressedCmds {
        if c.category == "error-masking" {   // output-hiding never counted
            maskCount++
        }
    }
    if maskCount >= 2 { shouldFire = true }
}

The verification-command branch correctly counts ALL categories (len(s.suppressedCmds) >= 2); the non-verification branch silently drops output-hiding occurrences.

Trigger scenario (false negative)

cmd1: echo step1 2>/dev/null   → suppressedCmds=[output-hiding], maskCount=0
cmd2: ls -la 2>/dev/null       → ×2, maskCount=0
cmd3: cat f.txt 2>/dev/null    → ×3, maskCount=0 — never fires

An agent can systematically hide stderr on every non-verification command (e.g. silencing build noise) and the reward-hacking detector never injects its warning — the exact pattern the file's research basis ("npm test 2>/dev/null", ICML 2026 reward hacking) calls out.

Expected vs actual

  • Expected: any suppression category ×2 on non-verification commands fires the warning
  • Actual: only error-masking counts; output-hiding accumulates unboundedly with zero feedback

Fix

Count both categories in the non-verification branch (maskCount → count of all suppressedCmds, or explicitly both categories), matching the comment and the verification-branch semantics.

Severity

Medium — exit codes still surface (error-masking remains caught), but a documented suppression exploit escapes detection; no test asserts the current gap (TestCheckVerificationSuppression_NonVerifyNeedsTwoMasks only covers error-masking).

Verified by independent review subagent (sa-9, static trace of both branches + test coverage check).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions