Files
discord_bot/specs/SPEC-010-behavior.md
T

2.8 KiB

SPEC-010 — Human-behavior layer

The bot should feel like a considerate participant, not an instant wall of text: it decides whether to speak with a cheap classifier instead of trusting the main model's self-report, paces its replies, splits long answers, and sometimes just reacts. All knobs are per-deployment TOML; every feature degrades to the previous behavior when its knob is unset (config-off = v3.0.0 semantics).

BEH-01 — Classifier gates non-direct replies (coverage: test)

With classifier-model configured, every non-direct user message first passes a cheap classification call (reply yes/no, factual yes/no, optional reaction emoji). reply=false means no main-model call happens at all — this is the boreness suppressor and the butting-into-conversations fix (replaces trusting answer_needed alone; the envelope flag still applies afterwards as second gate).

BEH-02 — Direct messages bypass the gate (coverage: test)

Mentions and DMs never go through the classifier — someone addressing the bot always reaches the main model. Welcome and bot-initiated flows do not pass the gate either.

BEH-03 — Classifier failure fails open (coverage: test)

A failed or unparseable classification (API error, budget refusal) falls through to the main model. Availability beats savings; the budget gate still protects spend.

BEH-04 — Reply pacing is typing-proportional (coverage: test)

With typing-chars-per-second set (recommended 30), the typing indicator is held for len(part) / cps seconds per message part, capped at typing-max-seconds (default 8), before sending. Unset or 0 = no pacing (v3.0.0 behavior).

BEH-05 — Factual answers skip the artificial delay (coverage: test)

Messages the classifier tagged factual (opening hours, prices, addresses) are answered without the BEH-04 delay — utility beats theater exactly where users are waiting for information.

BEH-06 — Long answers are split (coverage: test)

Answers longer than split-threshold chars (default 1200) are split at paragraph (then sentence) boundaries into at most split-max-parts (default 3) sequential messages, each under the Discord 2000-char limit (which unsplit answers would crash into today). Attached images go with the last part.

BEH-07 — Sometimes a reaction is the reply (coverage: test)

When the classifier returns reply=false plus a reaction emoji, the bot adds that emoji to the user's message instead of staying fully silent. Zero main-model cost, human touch.

BEH-08 — Quiet hours stop bot-initiated posts (coverage: test)

Within quiet-hours = "HH:MM-HH:MM" (host-local, may wrap midnight) bot_initiated_allowed() is false: no boreness, later no scheduler posts. Replies to users stay unaffected — a guest asking at 23:30 still gets an answer.