Skip to content

Record recurring errors on the tracked issue instead of filing again - #11

Merged
FlyLikeAPenguin merged 1 commit into
mainfrom
dedupe-recurring-errors
Aug 4, 2026
Merged

Record recurring errors on the tracked issue instead of filing again#11
FlyLikeAPenguin merged 1 commit into
mainfrom
dedupe-recurring-errors

Conversation

@FlyLikeAPenguin

Copy link
Copy Markdown
Owner

What changed?

An error whose root cause is already tracked no longer opens a second ticket. The investigation now returns is_duplicate + duplicate_of_url, and the pipeline posts a recurrence note on that issue instead of filing a new one — with the fingerprint, occurrence count, Datadog link, RCA doc link, and root cause.

Duplicates also skip the fix stage (the tracked issue owns that fix) and stay quiet on Slack.

Why?

A real case: an investigation identified an error as a duplicate of an existing epic, named the tracked issues and the open PR that fixes it, and explicitly recommended not attempting a fix. A brand new ticket was filed anyway.

Nothing in the pipeline could stop it. The investigation returned only is_actionable and is_fixable. The dedup instruction told the agent to set is_fixable=false — which gates the fix stage — while the tracker stage is gated on is_actionable alone. A duplicate of a real, unfixed bug is still actionable, so the ticket was always filed and the "already tracked" reasoning survived only as prose in the issue body.

is_duplicate is therefore deliberately independent of is_actionable; overloading is_actionable would have meant lying about whether the error matters. A duplicate claim with no issue URL is downgraded to a normal filing, since there would be nowhere to record the recurrence.

Validation

  • pytest — 64 passed, including 15 new tests in tests/test_duplicates.py covering the output contract, DB round-trip and migration, recurrence-note content, and pipeline routing (tracked → comment only, untracked → issue only, non-actionable → neither)
  • ruff check .
  • Documentation updated where behavior changed (CONTEXT.md, CHANGELOG.md)
  • No secrets, production logs, or private source code included

Risk and operations

  • Migration: two additive columns on investigations (is_duplicate, duplicate_of_url), applied by _migrate() on the next run. Verified against a copy of a live database; pre-existing rows default to 0/''.
  • New tracker capability: comment() added to the IssueTracker protocol and both backends. Any third-party tracker implementation needs it. GitHub's attach_pr now routes through it and picks up the --repo flag it was previously missing.
  • Behaviour change worth knowing: the agent's notion_page_url/linear_issue_url output keys are no longer read. Neither was in the documented output contract and both were overwritten by the pipeline. That overwrite also broke the Slack already-reported check — it compared the just-created URL against earlier runs, so it never fired. Duplicates are now suppressed directly instead.
  • Cost: unchanged. Duplicates are still investigated (that is how they are recognised); only the filing changes.

An error whose root cause already has an issue was filed as a brand new
ticket every time it recurred, even when the investigation had correctly
identified it as a duplicate and named the issue it belonged to.

Nothing in the pipeline could stop it. The investigation returned only
is_actionable and is_fixable; the dedup instruction told the agent to set
is_fixable=false, which gates the fix stage, while the tracker stage is
gated on is_actionable alone. A duplicate of a real, unfixed bug is still
actionable, so the ticket was always filed and the "this is already
tracked" reasoning survived only as prose in the issue body.

Give the investigation somewhere to put that conclusion: is_duplicate and
duplicate_of_url, deliberately independent of is_actionable. A duplicate
now gets a recurrence note on the existing issue via tracker.comment(),
skips the fix stage (the tracked issue owns that fix), and stays quiet on
Slack. A duplicate claim with no issue URL is downgraded to a normal
filing, since there would be nowhere to record the recurrence.

Also:
- add comment() to the IssueTracker protocol and both backends; GitHub's
  attach_pr now routes through it and picks up the --repo flag it was
  missing.
- stop reading notion_page_url/linear_issue_url from the agent's output.
  Neither was in the documented output contract and both were overwritten
  by the pipeline. Overwriting linear_issue_url also broke the Slack
  already-reported check, which compared the just-created URL against
  earlier runs and so never fired; duplicates are now suppressed directly.
- count an issue as created only when the tracker returns a URL.
@FlyLikeAPenguin
FlyLikeAPenguin merged commit a7fdf5e into main Aug 4, 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