Two conversation limits in the amoCRM bot had been broken since launch: AND instead of OR and a faulty branch were to blame
The Octery bot for amoCRM had two limits in its admin panel: a maximum number of replies and a nonsense threshold. Neither had worked from the start. The manager handoff condition used AND instead of OR, while the handoff branch wrote values to fields with incorrect names, causing subsequent steps to read the model's old response.
AI-processed from Habr AI; edited by Hamidun News
Imagine this: the numbers are there in the admin panel, the setting is saved and the interface looks exactly as it should. In reality, it does nothing. That is precisely how, on September 30, the team discovered that neither conversation-length limit worked in the Octery bot—and apparently neither had worked from the very beginning.
Octery replies to leads in amoCRM chats and hands the deal over to a manager. It has two limits. Max Messages determines how many replies the bot gives before calling in a human. Hard Stop Threshold determines how many consecutive meaningless messages it will tolerate: "aaa," "test," "???" or even output from an unrelated bot. Every such message costs a model call, so there is no point responding to them indefinitely.
Two errors that concealed each other
The handoff decision was made after the model responded, inside the processing pipeline. The condition consisted of three checks joined by AND. According to the settings' intended semantics, the limits are independent: a handoff should occur if the reply counter is exhausted or if a streak of meaningless messages reaches the threshold. With AND, the bot called a manager only when the customer simultaneously exhausted the message limit and sent nonsense several times in a row. That never happened.
The second error was in the branch that was supposed to run when the condition was met. It overwrote the response with "handing over to a manager" and set the intent to manager. But the values were written into fields whose names had been replaced by expressions: a value was inserted into the name field and remained there. On top of that, response delivery and logging read data not from this branch but directly from the parsed model response. Even if someone had changed AND to OR, the customer would still have received a regular response and the logs would have shown no trace of the handoff.
The first manual run would have exposed either error on its own. Together, they made the limits invisible.
Why nobody noticed
The logic lived in the pipeline configuration rather than in code. You cannot write a unit test for the configuration, run it in CI or review the change as a readable diff: it merely looks like someone "fixed the condition." Manually driving a live conversation all the way to the limit takes time, so routine checks never reached it. There was neither a positive nor a negative answer to the question, "Do the limits work?"
What was done
The decision was moved into the API as a separate pure function. The pipeline passes it the model response and two counters from the conversation state, while the function retrieves the limits from the company's settings itself, preventing the caller from supplying different values. It returns one final decision: text, intent and handoff reason. Every subsequent step reads only that result.
The formulas contain two off-by-one traps. The reply counter is measured before the current message: the bot gives exactly max_messages replies and then hands off. The nonsense streak includes the current message, as stated in the interface hint. If both conditions trigger, the message limit is recorded as the reason. If the phrase template is empty, the default phrase is sent. The change also removed a side effect: the old branch rated the message as "meaningless," corrupting analytics.
Tests derived from the specification
The behavior was first described as scenarios, then each scenario became a test—16 in total. Their names speak for themselves: "hands off on the Nth non-meaningful message in a row, counting the current one" and "a meaningful message breaks the non-meaningful streak." The "old AND case" test was retained deliberately: the only case in which the old condition ever triggered is now a special case of the new behavior.
Rollout risk and takeaway
The main risk is not technical. Companies with low limits will see the bot fall silent and call a manager for the first time. To them, this will look like a new feature rather than a fix. They are therefore being notified before activation, as a separate item in the rollout plan.
The practical takeaway for teams using no-code and low-code pipelines is straightforward: if a number is visible to customers in the interface, its behavior should have an automated test, and the test name should state the promise made to the customer. Business logic that affects revenue and the handoff of a customer to a human is better moved out of configuration and into code, where it can be reviewed in a diff and exercised in CI.
- May 30, 2026AI for Business: The AI Integrator Role and n8n Workflows
- Apr 28, 2026PSB shows how it deploys AI in the bank: chatbots, RAG and services for business
- Oct 13, 2026200 OK, but the client gets nothing: three n8n agent bugs from production
- Nov 12, 2026Plurai raises $13 million for a simulator that finds AI agent errors
Key Questions Answered
What are the key details on Two errors that concealed each other?
The handoff decision was made after the model responded, inside the processing pipeline. The condition consisted of three checks joined by AND. According to the settings' intended semantics, the limits are independent: a handoff should occur if the reply counter is exhausted or if a streak of meaningless messages reaches the threshold. With AND, the bot called a manager only when the customer simultaneously exhausted the message limit and sent nonsense several times in a row. That never happened.
Why nobody noticed?
The logic lived in the pipeline configuration rather than in code. You cannot write a unit test for the configuration, run it in CI or review the change as a readable diff: it merely looks like someone "fixed the condition." Manually driving a live conversation all the way to the limit takes time, so routine checks never reached it. There was neither a positive nor a negative answer to the question, "Do the limits work?"
What was done?
The decision was moved into the API as a separate pure function. The pipeline passes it the model response and two counters from the conversation state, while the function retrieves the limits from the company's settings itself, preventing the caller from supplying different values. It returns one final decision: text, intent and handoff reason. Every subsequent step reads only that result. The formulas contain two off-by-one traps.
Test Frontier LLMs & Autonomous Agents in One Workspace
Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.
The AI world, distilled — once a week
Seven stories that actually mattered, hand-picked. No noise, no reposts, no press releases.
Done! Check your inbox for a confirmation.