# Runbook: Behavior Policy v2.1 **Version:** 2.1 **Date:** 2026-02-07 **Owner:** NODA1 Infra **Severity:** CRITICAL (affects all agent responses) --- ## 1. File Locations | File | Path | Purpose | |------|------|---------| | Behavior Policy | `gateway-bot/behavior_policy.py` | SOWA decision logic | | HTTP API (gateway) | `gateway-bot/http_api.py` | Webhook handler, computes gateway metadata | | Global System Prompt | `prompts/global_system_prompt_v2.md` | Policy document for LLM | | Tests | `tests/test_behavior_policy.py` | 39 unit tests | | Backup (policy) | `gateway-bot/behavior_policy.py.bak.*` | Timestamped backups | | Backup (http_api) | `gateway-bot/http_api.py.bak.*` | Timestamped backups | | Old policy (v1) | `gateway-bot/behavior_policy_v1.txt` | Reference only | --- ## 2. Quick Disable / Rollback ### Option A: Rollback to backup (fastest, ~10s) ```bash cd /opt/microdao-daarion # List backups ls -lt gateway-bot/behavior_policy.py.bak.* ls -lt gateway-bot/http_api.py.bak.* # Rollback cp gateway-bot/behavior_policy.py.bak.20260207_085440 gateway-bot/behavior_policy.py cp gateway-bot/http_api.py.bak.20260207_085440 gateway-bot/http_api.py # Restart gateway docker compose -f docker-compose.node1.yml restart gateway ``` ### Option B: Feature flag via ENV (no restart needed for next deploy) Add to `.env`: ``` BEHAVIOR_POLICY_VERSION=v1.1 ``` Then in `http_api.py`, wrap v2.1 logic: ```python if os.getenv("BEHAVIOR_POLICY_VERSION", "v2.1") == "v1.1": # Old behavior: bare mention responds payload_explicit_request = False # ... old call ``` > **Note:** Option B requires code change. Option A is preferred for emergency. ### Option C: Disable SOWA entirely (all agents respond to everything) ```bash # In http_api.py, force respond_decision = True # NOT RECOMMENDED for production — causes spam ``` --- ## 3. Run Unit Tests ```bash cd /opt/microdao-daarion python3 -m pytest tests/test_behavior_policy.py -v ``` Expected: `39 passed` If pytest not installed: ```bash pip3 install --break-system-packages pytest ``` --- ## 4. Run Live Tests (7 scenarios) All tests use `chat_id=0` (prober mode — no Telegram messages sent). ```bash # Test 1: Bare mention in group → should NOT respond curl -s -X POST http://localhost:9300/helion/telegram/webhook \ -H 'Content-Type: application/json' \ -d '{"update_id":999001,"message":{"message_id":1001,"from":{"id":12345,"first_name":"Test"},"chat":{"id":-100999,"type":"supergroup","title":"TestGroup"},"text":"@Helion","date":1738900000}}' # Expected: {"ok":true,"skipped":true,"reason":"bare_mention_public_topic"} # Test 2: Mention + question → should respond curl -s -X POST http://localhost:9300/helion/telegram/webhook \ -H 'Content-Type: application/json' \ -d '{"update_id":999002,"message":{"message_id":1002,"from":{"id":12345,"first_name":"Test"},"chat":{"id":0,"type":"supergroup","title":"TestGroup"},"text":"@Helion що таке Docker?","date":1738900001}}' # Expected: {"ok":true,"agent":"helion","prober":true,...} # Test 3: DM → always respond curl -s -X POST http://localhost:9300/helion/telegram/webhook \ -H 'Content-Type: application/json' \ -d '{"update_id":999003,"message":{"message_id":1003,"from":{"id":12345,"first_name":"Test"},"chat":{"id":0,"type":"private"},"text":"Привіт","date":1738900002}}' # Expected: {"ok":true,"agent":"helion","prober":true,...} # Test 4: Broadcast → should NOT respond curl -s -X POST http://localhost:9300/helion/telegram/webhook \ -H 'Content-Type: application/json' \ -d '{"update_id":999004,"message":{"message_id":1004,"from":{"id":12345,"first_name":"Test"},"chat":{"id":-100999,"type":"supergroup","title":"TestGroup"},"text":"увага всім! релізимо v2.0","date":1738900003}}' # Expected: {"ok":true,"skipped":true,"reason":"broadcast_not_directed"} # Test 5: Link only → should NOT respond curl -s -X POST http://localhost:9300/helion/telegram/webhook \ -H 'Content-Type: application/json' \ -d '{"update_id":999005,"message":{"message_id":1005,"from":{"id":12345,"first_name":"Test"},"chat":{"id":-100999,"type":"supergroup","title":"TestGroup"},"text":"https://github.com/project/pull/123","date":1738900004}}' # Expected: {"ok":true,"skipped":true,"reason":"media_or_link_without_request"} # Test 6: Question without mention → should NOT respond curl -s -X POST http://localhost:9300/helion/telegram/webhook \ -H 'Content-Type: application/json' \ -d '{"update_id":999006,"message":{"message_id":1006,"from":{"id":12345,"first_name":"Test"},"chat":{"id":-100999,"type":"supergroup","title":"TestGroup"},"text":"Хто знає чому падає сервер?","date":1738900005}}' # Expected: {"ok":true,"skipped":true,"reason":"not_directed_to_agent"} # Test 7: Mention + imperative → should respond curl -s -X POST http://localhost:9300/helion/telegram/webhook \ -H 'Content-Type: application/json' \ -d '{"update_id":999007,"message":{"message_id":1007,"from":{"id":12345,"first_name":"Test"},"chat":{"id":0,"type":"supergroup","title":"TestGroup"},"text":"@Helion поясни що таке SOWA","date":1738900006}}' # Expected: {"ok":true,"agent":"helion","prober":true,...} ``` --- ## 5. Verify After Restart ```bash # 1. Restart gateway docker compose -f docker-compose.node1.yml restart gateway # 2. Wait 10s sleep 10 # 3. Check health curl -s http://localhost:9300/health | python3 -m json.tool # 4. Check all agents loaded # Expected: 10 agents, all prompt_loaded=true # 5. Run agent ping curl -s -X POST http://localhost:9300/debug/agent_ping | python3 -m json.tool # 6. Check logs for errors docker logs dagi-gateway-node1 --tail 20 ``` --- ## 6. Monitor Policy Violations Check for `policy_violation` in logs: ```bash # Real-time monitoring docker logs -f dagi-gateway-node1 2>&1 | grep 'policy_violation' # Last 1000 lines docker logs dagi-gateway-node1 --tail 1000 2>&1 | grep 'policy_violation' # Count violations per agent docker logs dagi-gateway-node1 --tail 5000 2>&1 | grep 'policy_violation' | grep -oP 'agent=\w+' | sort | uniq -c | sort -rn ``` Log format: ``` 🚨 policy_violation=no_output_extra_text agent=helion chat_id=-100123 extra_text_len=45 extra_preview='Some unexpected text...' ``` --- ## 7. Key Contracts (Do Not Break) ### has_explicit_request formula ``` has_explicit_request = imperative OR (question_mark AND (is_dm OR is_reply_to_agent OR mentioned_agents not empty OR thread_has_agent_participation)) ``` ### thread_has_agent_participation - REQUIRED field - If platform cannot provide → `false` (fail-closed) - Gateway MUST always pass, even as `false` ### NO_OUTPUT contract - LLM must return exactly `NO_OUTPUT` or empty string - Any extra text after marker → logged as `policy_violation=no_output_extra_text` - Gateway suppresses sending to Telegram --- ## 8. Contacts - **NODA1 Admin:** @DaarionAdmin - **Infra:** SSH root@144.76.224.179 - **Monitoring:** Grafana :3030 / Prometheus :9090 --- **END OF RUNBOOK**