Skip to content

fix(hooks): Drop advisory audit rows that repeat a recorded dedupe key - #19

Merged
ikorich merged 1 commit into
masterfrom
fix/dedupe-advisory-audit-rows
Aug 15, 2026
Merged

ikorich merged 1 commit into
masterfrom
fix/dedupe-advisory-audit-rows

Conversation

@ikorich

@ikorich ikorich commented Aug 15, 2026

Copy link
Copy Markdown
Member

Motivation

Every installed dev plugin registers its own copy of hooks/audit-tooluse.sh and hooks/audit-subagent.sh, and all of them fire on the same event. One tool call was recorded six times — twelve for subagent-stop, which fires twice per stop.

Measured over one five-hour multi-platform run: 2,265 of 2,837 audit rows (80%) were advisory duplicates. metadata.dedupe_key was already present and identical across every copy, and nothing consulted it — both hooks' headers promise that "the orchestrator's audit-dedup hook" reconciles them, but no such hook exists.

Found while stress-testing the corpflow pipeline across four platforms. Companion fixes: IGRSoft/corpflow#300.

Changes

  • Both audit hooks now check the tail of audit.jsonl for the row's dedupe_key before appending, and drop the row if it is already recorded.
  • Patch version bump; CHANGELOG.md, MEMORY.md and README.md version rows re-pointed at plugin.json (they had drifted a patch behind).

Test plan

Verified against a scratch audit log, driving the real hooks with real payloads:

  • Six plugin hooks, one tool call → 1 row written (was 6).
  • Three distinct tool calls × three plugins → 3 rows, one per distinct dedupe_key. No over-suppression.
  • Advisory hook then canonical corpflow hook, same key → 2 rows, and the canonical row (advisory=false) is present. The canonical row is never suppressed; worst case is 1 advisory + 1 canonical instead of 6.
  • --self-test passes on both hooks in all six plugins (12/12).
  • bash -n clean on all modified hooks.

Notes

A tail window (400 lines) rather than a whole-file scan: the duplicate copies fire within milliseconds of each other, so the key is always near the end, and a full-file grep would grow linearly with a log that reached ~2,800 rows in a single run.

This is a per-plugin reconciliation because it needs no cross-plugin coordination. If a central audit-dedup hook is ever added to corpflow — as the header comments assume — these checks become redundant but stay harmless.

…e key

Every installed dev plugin registers its own copy of these two hooks and all of
them fire on the same event, so one tool call landed in audit.jsonl six times —
twelve for subagent-stop, which fires twice per stop. A measured five-hour run
produced 2,837 rows of which 2,265 (80%) were advisory duplicates, and every
reader of the trail paid to parse them.

metadata.dedupe_key was already present and already identical across all copies;
nothing consulted it. Both header comments promise that the orchestrator's
audit-dedup hook reconciles these rows, but no such hook exists. Reconcile at the
point of writing instead: if the key is already in the tail of audit.jsonl, the
advisory row adds nothing.

The canonical orchestrator row is never suppressed — it is written by a different
hook carrying no advisory flag and performing no such check. Distinct events are
unaffected; only exact dedupe_key repeats are dropped.
@ikorich
ikorich merged commit d03c5a6 into master Aug 15, 2026
2 checks passed
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