Joel rejected emoji reactions as the operator action API (2026-07-19).
Labeled inline keyboard buttons on outbound DMs publish
message/action.requested with kind: callback and stable learner-flow.*
action ids; the callback_query owner answers, authorizes, resolves
flowId, verifies the declared action, then publishes. Legacy reaction
consumer stays until the live Seen canary passes.
joelclaw notify send now accepts --kind memory|alert|digest|ask|receipt,
passed through the Redis envelope and honored by the gateway compat shim
(invalid kinds are rejected instead of guessing a lane). Without --kind,
low/normal-priority sends are inferred as digest, which the Telegram
digest-lane classifier may silently suppress — that suppressed a
Joel-requested message twice on 2026-07-18. Operator-lane kinds
(ask/alert/memory) always deliver. CLI next_actions now point at otel
delivery verification instead of the ignored --telegram-only flag;
skills/messaging documents the flag and the verify rule.
Also lands the in-flight contract-v2 reaction-actions work from a
concurrent session (MessageAction schema in message-contract, telegram
adapter action messages, notify context.actions passthrough, inbound
reaction callback normalization) — entangled in the same files and
committed together deliberately.
81 tests pass across message-contract, chat-sdk, chat-sdk-inbound, sdk;
tsc clean. Live on flagg since 2026-07-18 (gateway restarted, CLI
rebuilt, kind=ask delivery confirmed via notify.compat_v2.confirmed).