Skip to content

feat(decision-capture): log the surviving silent suppression (bug 011 option 4)#120

Open
Kyarha wants to merge 3 commits into
mainfrom
claude/bug-011-suppression-logging-23ba29
Open

feat(decision-capture): log the surviving silent suppression (bug 011 option 4)#120
Kyarha wants to merge 3 commits into
mainfrom
claude/bug-011-suppression-logging-23ba29

Conversation

@Kyarha

@Kyarha Kyarha commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

additive observability only, fix class still the maintainer's — @ramboz to validate before merge.

Implements bug 011 option 4 (suppression logging), the piece #109 finding 2 left on the table. Follows #117, which decided the fix class and removed dropping on both recorded-corpus paths.

Why this exists after #117

#117 deliberately kept one drop: decision_scratch.dedup_scan_against_stubs. Its own residual 1 documents the consequence — a Tier-3 agent reversal of an in-flight stub is still silently dropped there, since agent prose never produces a stub of its own to survive as. On disk, that drop was indistinguishable from "nothing was found." Bug 011's record even overclaimed "no silent suppression remains to log" — this corrects that.

So the original A4 scope (dedup() / prune_recorded_stubs()) collapsed: #117 turned both into flags that surface, so there is nothing silent left to log there. The one surviving silent drop is the only thing worth instrumenting, and this PR instruments exactly it.

The change

dedup_scan_against_stubs on each drop, appends one JSON line to .jig/decision-suppressions.log (dropped candidate quote/tier/who, covering stub, containment score, call site). The drop is unchanged — same rule, same result, logging is a gated side-effect.
decision_scan.containment() new measure returning the raw score; is_contained is now a threshold over it, so the number that decides a drop and the number logged share one home.
logging contract fail-open (a broken sink never changes what is suppressed) and opt-in via project_dir — pure-function callers log nothing and behave identically.
.gitignore ignores the new log, matching the decision-scratch precedent (jig-local runtime state, per-checkout, never tracked).
bug 011 record + refinement-todo #255 overclaim corrected inline; ## Amendments note added; residual gains an observability line. Fix class stays deferred.
hosts/ (claude + codex) regenerated.

Scope guardrails (out of scope, on purpose)

  • Does not touch the drop. What surfaces and what is pruned is byte-for-byte unchanged.
  • Does not decide the fix class. Whether dedup_scan_against_stubs should drop at all stays the maintainer's call — this removes the silence, not the residual. Bug 011 stays DONE; the residual stays a residual.

Test evidence (red → green, TDD)

Red — the drop happened, no log existed:

TypeError: dedup_scan_against_stubs() got an unexpected keyword argument 'project_dir'
AttributeError: module 'decision_scratch' has no attribute 'suppression_log_path'

Green after implementation:

  • test_decision_scratch.SuppressionLogTests (4): a drop writes one inspectable line; a kept candidate logs nothing; logging is opt-in (no project_dir → no write, unchanged behaviour); a broken log sink never changes what is dropped (fail-open).
  • test_jig_decision_capture.py (+2, end-to-end through the real Stop hook): the dedup drop writes a suppression line naming dedup_scan_against_stubs; a plain surfacing with no drop writes no log.
  • Full decision suites green: test_decision_scan + test_decision_scratch (73), inflight hook (12), capture hook (13). Ruff clean. Validated on Python 3.9.6.

The one drift-guard flake on hosts/claude/.claude-plugin/plugin.json is the known, pre-existing intermittent one (docs/bugs/008) — that file is untouched here and clean in the tree.

Kyarha and others added 3 commits July 17, 2026 10:03
… option 4)

#117 removed containment-based dropping on both recorded-corpus paths, but
deliberately kept `dedup_scan_against_stubs` dropping — leaving one silent
suppression the bug record's own residual 1 documents (a Tier-3 agent reversal
of an in-flight stub). That path was still indistinguishable from an empty scan
on disk.

Every drop in `dedup_scan_against_stubs` now appends one JSON line to
`.jig/decision-suppressions.log` — dropped candidate (quote/tier/who), the
covering stub, the raw containment score, and the call site. Additive only:
the drop itself is unchanged, and logging is fail-open (a broken sink never
changes what is suppressed) and opt-in via `project_dir` so pure-function
callers are untouched.

Containment gains a `containment()` measure that `is_contained` thresholds over,
so the score that decides a drop and the score written to the log share one home.

Corrects bug 011's overclaim ("no silent suppression remains to log") inline and
appends an `## Amendments` note; refinement-todo #255 gains an observability line.
The fix class stays deferred to the maintainer — this removes the silence, not
the residual. Hosts regenerated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
…ecord prose

Addresses PR review feedback on the bug 011 option-4 suppression logging:

- Log the dropped candidate's transcript `turn` (guarded like matched's), the
  owner's locator for the possibly-reversing statement the log exists to surface.
- Note in `suppression_log_path` that the log is append-only/unbounded by design
  (never read into context, clipped lines, git-ignored — owner prunes if needed).
- Restore the bug 011 Fix-class overclaim verbatim and annotate it with a
  footnote instead of rewriting it, per ADR-0010 closed-record discipline; move
  the correction into the footnote + existing amendment.
- Add unit coverage: turn is logged; the no-turn sentinel (-1) omits the key.
- Regenerate claude + codex hosts.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
…lity

Record the deferred option to narrow decision-suppressions.log to
agent-sourced drops (the only class that can hide a lost decision).
Not acted on now — kept the fix additive with the simple 'every drop
is logged' contract; revisit if the log proves noisy in practice or
when the flag-don't-drop mitigation is taken up.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
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