Chief question replies: resolve bound choices in Rust (ask-6ef2624788)

Merged
TE
2d ago
+520-0

This PR adds reply resolution and numbered-prompt rendering only. A reply to an existing question becomes a precise option selection without treating arbitrary text or a reaction as permission approval. This adds a pure cmux-conversation::question_reply seam: deterministic numbering across question items, exact option text matching (case/whitespace normalized), and explicitly bound tapbacks.

The prompt retains the original request/question IDs and full question snapshot. Resolution returns WrongThread, Stale, Ambiguous, or UnboundTapback when the reply cannot safely identify a choice; unmatched text never becomes a guessed Other answer. Numeric labels that collide with another displayed number are ambiguous. The result carries the original session, permission, item and option IDs and does not mutate or consume the question.

The caller must authenticate the sender, reread the current pending question, and atomically validate/commit a complete answer through the existing owner. Multi-item and multi-select replies return one selection for the caller to accumulate. Free-text/Other submission remains outside this option-selection seam. No transport, sending, permission proof, approval RPC, Feed mapping, or native UI is added here.

Leo-ask: ask-6ef2624788

oh stuff yeah actually we should be able to surface permissions/multiple choice related things inside chief... idk if y'all have researched dot/grokbot but those are def thng to look into

This preserves #22747 and #22941: no new Chief approval gates, no inferred person provenance, and no relayed permission allow. An offered option literally named “Allow” is still only a question selection, never authorization. The separate native question bridge and adopted #33385 own their existing paths. #28846's Feed mapping is untouched.

Validation: 14 new behavioral tests cover stable rendering, all numbered options across harnesses/items, identity retention, duplicate text and numeric collisions, stale/replaced/closed requests, wrong threads, explicit tapback binding, and no guessed approval. Exact-head fleet tests and strict clippy passed: 26 tests, including all 14 new tests, zero failures; cargo clippy --locked -p cmux-conversation --all-targets -- -D warnings passed. Run 41614121649 tested 0587cae2b97024a14cf6b93a7de984750c7ebe86, snapshot 97c736d86d7eb36ce3247b9a1d936652fe60cb7d, matching tree 5c4598fe26f051362fd092a3752309840756db63, exit 0. The broader clippy job completes strict clippy but fails its panic baseline ratchet in untouched acpmux indexing/string-slice counts and cmux-host/cloud/github_status.rs:112; those source trees and the baseline are byte-identical to base. rustfmt, git diff --check, and prepush-gate.py passed. The broad verify-local.py reports unchanged localization debt and a missing CmuxDeviceHub workspace group already present in base a8d0ea061a9a094e4689f90f6767da08fea0eb65; no affected files or their checks changed.

Remaining work is tracked in #33560 and follows separately: rich-text cleanup, flexible reply forms, connector-envelope freshness and reaction-removal handling, Unicode matching, explicit multi-select completion, and input bounds. This PR claims none of those.

Prior art: #30170, #27016 and #23847 read and acknowledged; their behavior is preserved. This is a library seam only, so it adds no action, default, CLI/MCP surface, or visual variant. Product integration and end-to-end Messages evidence belong to the separate wiring work.
🤖 Generated with Codex

Agent session: agent session