You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#172 caps the bot at one AI response per ticket, ever. The stated intent was different: "a human owns the thread from the first response onward." Those are not the same rule, and the gap costs a real case.
The two rules, and where they differ
Scenario
"Answer once, ever" (shipped)
"Stay out once a human speaks" (intended)
Maintainer posts the solution, bot would follow up
silent ✅
silent ✅
Maintainer asks the reporter a question
silent ✅
silent ✅
Reporter adds a stack trace 30s later, no human has replied
silent ❌
answers ✅
The third row is the regression. The bot has spent its one turn on a question that was missing the detail that would have made the answer useful, and it cannot use the new detail. Nobody has been interrupted — there is no human in the thread yet — so the reason for staying quiet does not apply.
Why it shipped as a counter
The counter is a circuit breaker. It was the right call under time pressure: it is trivially verifiable, it cannot mis-fire, and it made both incidents impossible. A presence gate is the correct rule but has more moving parts, and getting it subtly wrong reintroduces public bot chatter.
Worth recording precisely because a hotfix can quietly become permanent product behaviour. In six months nobody will remember this started as a response to two Discord threads.
What a presence gate needs
The signal already exists. InboundHandler.isTeamMember resolves a platform user to a TeamMember via User.externalId + source → email, and it is still computed on every reply for status transitions. #172 removed it as a gate, and that removal was correct — it was pointed at the wrong question.
Wrong question: "did a team member send this message?" That is what it answered before, which is why a third party's follow-up still got an AI reply.
Right question: "has a team member spoken anywhere in this thread?" That is a property of the ticket, not of the message.
So the shape is roughly: on a reply, if any prior message on the ticket is from a team member, stay silent permanently; otherwise the AI may respond. That wants to live next to the existing re-answer gate in ai-response.ts rather than at the enqueue sites, since it depends on ticket history.
Open questions worth deciding rather than discovering
Does a human reply from the dashboard count? It persists as type: 'BOT', isAiGenerated: false, so it is distinguishable — but only if the check looks for it.
Should there be a cap anyway? A reporter who posts eight follow-ups before any human arrives could draw eight AI replies under a pure presence gate. A small ceiling, or a "no more than one response per N minutes" rule, may be wanted alongside.
Does "a human spoke" include a third party? A community member answering another community member is common in our Discord and is arguably exactly when the bot should stop.
#172 caps the bot at one AI response per ticket, ever. The stated intent was different: "a human owns the thread from the first response onward." Those are not the same rule, and the gap costs a real case.
The two rules, and where they differ
The third row is the regression. The bot has spent its one turn on a question that was missing the detail that would have made the answer useful, and it cannot use the new detail. Nobody has been interrupted — there is no human in the thread yet — so the reason for staying quiet does not apply.
Why it shipped as a counter
The counter is a circuit breaker. It was the right call under time pressure: it is trivially verifiable, it cannot mis-fire, and it made both incidents impossible. A presence gate is the correct rule but has more moving parts, and getting it subtly wrong reintroduces public bot chatter.
Worth recording precisely because a hotfix can quietly become permanent product behaviour. In six months nobody will remember this started as a response to two Discord threads.
What a presence gate needs
The signal already exists.
InboundHandler.isTeamMemberresolves a platform user to aTeamMemberviaUser.externalId+source→email, and it is still computed on every reply for status transitions. #172 removed it as a gate, and that removal was correct — it was pointed at the wrong question.So the shape is roughly: on a reply, if any prior message on the ticket is from a team member, stay silent permanently; otherwise the AI may respond. That wants to live next to the existing re-answer gate in
ai-response.tsrather than at the enqueue sites, since it depends on ticket history.Open questions worth deciding rather than discovering
type: 'BOT',isAiGenerated: false, so it is distinguishable — but only if the check looks for it.Decision owner
If "answer once, ever" is a deliberate product stance, say so and close this. If it was a hotfix, this issue is the path back.