agent re-tagged the same ticket endlessly: loop detector
A guide to stopping agents from re-tagging the same ticket in an endless loop, in the business-apis-integrations category: idempotent tagging, change detection, and loop guards. Use when agents add the same tags repeatedly, tag operations never converge, or when building agent tagging automation. Not for tag taxonomy design, tag reporting, or manual tagging guidelines.
TL;DR
An agent that re-tags endlessly is applying tags without checking whether they are already there: each pass sees a ticket, decides it needs the tag, adds it (a no-op), and repeats. Make tagging idempotent and convergent: check current tags first, only write when something actually changes, and cap the passes. Tagging should reach a fixed point and stop.
The query
agent re-tagged the same ticket endlessly: loop detectorUse this when
- Agents add the same tags repeatedly
- Tagging runs never finish
- Ticket histories fill with tag events
- You are building tagging automation
Not for
- Designing the tag taxonomy
- Tag-based reporting
- Manual tagging best practices
- Tag permission design
Steps
1. Read current tags before deciding anything
Fetch the ticket's tags at the start of each tagging pass. Decisions made without reading current state re-apply what is already there. Read first is the whole fix in most cases.
Expected output: tagging decisions based on current tag state.
2. Write only when the tag set actually changes
Compute the desired tags, diff against current, and call the API only if the diff is non-empty. No-op writes are what fill histories and trigger webhooks; skipping them removes the loop's fuel.
Expected output: tag writes only on real changes.
3. Cap the number of tagging passes per ticket
A tagging job gets a small fixed number of passes (two or three). If it has not converged by then, something is wrong: stop and alert instead of looping. The cap turns infinite loops into bounded investigations.
Expected output: a pass cap with alert on non-convergence.
4. Detect oscillation between tag sets
If pass N wants tags A and pass N+1 wants tags B and pass N+2 wants A again, the logic is oscillating: two rules fighting. Log the desired set per pass; oscillation in the log means the rules need reconciliation, not more passes.
Expected output: oscillation detection from per-pass logs.
5. Make the tagging rules deterministic
Same ticket state must always produce the same desired tags. Non-determinism (model sampling, time-dependent rules) guarantees non-convergence. Deterministic rules reach a fixed point; anything else loops eventually.
Expected output: deterministic tagging rules.
Template: the checklist
Tag loop prevention:
[ ] Current tags read before each pass
[ ] Writes only on non-empty diffs
[ ] Pass cap with non-convergence alert
[ ] Oscillation detection from per-pass logs
[ ] Deterministic tagging rulesVariant phrasings
agent keeps adding same tag
Steps 1 and 2. Read first, write only on change.
tagging loop never converges
Steps 3 and 4. Cap passes, detect oscillation.
ticket tag events flooding history
Step 2. No-op writes are the flood; skip them.
Why it happens
Tagging agents get built as "look at ticket, decide tags, apply tags" with no memory between passes and no diff before writing. Each pass is stateless, so each pass does the full work including re-applying existing tags. The API accepts the redundant writes silently, webhooks fire on each one, and the history fills. The loop is statelessness plus silent acceptance.
Edge cases
- Tags removed by humans between passes: the diff naturally re-adds them. Decide whether human removals should stick (then respect them).
- Case sensitivity in tag comparison: "VIP" versus "vip" may diff forever. Normalize before comparing.
- External systems adding tags: another integration's tags appear in the diff. Scope the diff to tags the agent owns.
- Bulk retagging jobs: the same idempotency applies at bulk scale; a bulk job without diffs is a bulk loop.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_IqY1Q10JFsQyhH-qyRB-nA