Approvals and operator commands shouldn't be case sensitive #64

Closed
opened 2026-09-29 16:26:23 +00:00 by dev-agent · 0 comments
Collaborator

Found on the live end-to-end run.

The approval pattern is ^approve(?:\s+(rev-\d+))?$ (nisse-dev/src/nisse_dev/gates.py:50), matched case-sensitively. Anything that doesn't match counts as rejection feedback, so Approve, which phone keyboards capitalise automatically, throws the plan away and triggers a re-plan: the opposite of what the operator meant, and it costs a planner call.

The operator commands in control.py are exact, case-sensitive matches too: status, stop, use <project>, start milestone <n>, next milestone, project complete. A capitalised one gets a hint or "busy" instead of acting, which is annoying but harmless, except Stop: it doesn't reach the cancel flag, so work keeps running.

Expected: match approvals and commands case-insensitively, ignoring surrounding whitespace and trailing punctuation (Approve., STOP!). The project name in use <project> keeps its case. Revision binding is unchanged: Approve rev-2 binds to rev-2, and a stale revision is still refused.

Safety: this only widens what counts as the same command. Sender checks come from the event (A4), not the text, and approval still needs the whole message to be the approve command, so a sentence that merely contains the word isn't an approval.

Tests: Approve and APPROVE rev-1 approve; Stop sets the cancel flag while work runs; Status reports; use Demo keeps Demo.

Related: #61 (approval flow), and the restart-question handling from #57, which already ignores case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE

Found on the live end-to-end run. The approval pattern is `^approve(?:\s+(rev-\d+))?$` (`nisse-dev/src/nisse_dev/gates.py:50`), matched case-sensitively. Anything that doesn't match counts as **rejection feedback**, so `Approve`, which phone keyboards capitalise automatically, throws the plan away and triggers a re-plan: the opposite of what the operator meant, and it costs a planner call. The operator commands in `control.py` are exact, case-sensitive matches too: `status`, `stop`, `use <project>`, `start milestone <n>`, `next milestone`, `project complete`. A capitalised one gets a hint or "busy" instead of acting, which is annoying but harmless, except `Stop`: it doesn't reach the cancel flag, so work keeps running. **Expected:** match approvals and commands case-insensitively, ignoring surrounding whitespace and trailing punctuation (`Approve.`, `STOP!`). The project name in `use <project>` keeps its case. Revision binding is unchanged: `Approve rev-2` binds to rev-2, and a stale revision is still refused. **Safety:** this only widens what counts as the same command. Sender checks come from the event (A4), not the text, and approval still needs the whole message to be the approve command, so a sentence that merely contains the word isn't an approval. **Tests:** `Approve` and `APPROVE rev-1` approve; `Stop` sets the cancel flag while work runs; `Status` reports; `use Demo` keeps `Demo`. Related: #61 (approval flow), and the restart-question handling from #57, which already ignores case. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
Sign in to join this conversation.