The gap
Every FUNCTION subcommand — valid or not — is queued by MULTI and then
answered at EXEC with ERR unknown command 'FUNCTION', with the
arguments dropped from the message. Outside a transaction the same commands
work.
Measured (moon @ c5395188, --shards 1 and --shards 4, vs redis-server 8.6.1)
Raw socket, one fresh connection per case, MULTI / <cmd> / EXEC:
| command |
moon EXEC reply |
redis EXEC reply |
FUNCTION LIST |
*1 -ERR unknown command 'FUNCTION', with args beginning with: |
*1 *0 |
FUNCTION DUMP |
same |
*1 $<payload> |
FUNCTION STATS |
same |
*1 *[running_script …] |
FUNCTION BOGUS |
same |
*1 -ERR unknown subcommand 'BOGUS'. Try FUNCTION HELP. |
Top-level, the same binary answers correctly:
FUNCTION LIST -> *0
FUNCTION DUMP -> -ERR FUNCTION DUMP not supported in this release (Phase 101 limitation)
FUNCTION BOGUS -> -ERR unknown subcommand 'BOGUS'. Try FUNCTION HELP.
FUNCTION is the ONLY container with this behaviour. The other twelve
(ACL, CLIENT, COMMAND, CONFIG, MEMORY, MODULE, OBJECT, PUBSUB,
SCRIPT, SLOWLOG, XGROUP, XINFO) all execute correctly inside MULTI.
Why it matters beyond the wrong text
The MULTI queue gate documents its safety argument as queueable iff
dispatchable — it reads the same COMMAND_META dispatch reads, so a command
cannot become queueable-but-undispatchable. FUNCTION breaks that invariant:
COMMAND_META has it, so the gate queues it, but the EXEC executor cannot
reach the handler and falls back to the unknown-command path.
This is the moon#639 class — a family that runs through an intercept the
transaction executor cannot call — except that here the fallback lies about
the command existing rather than failing loudly.
Consequence for moon#670
moon#670 adds queue-time rejection of unknown container subcommands. FUNCTION
has to be excluded from that gate until this is fixed, because the gate's
notion of "known subcommand" and the executor's notion disagree for this one
container. The exclusion is fenced by a test rather than left as a comment
(tests/container_subcommand_parity_670.rs).
Found
Sweeping all 14 containers × valid and bogus subcommands, top-level and inside
MULTI, against a live redis-server 8.6.1 while implementing moon#670.
The gap
Every
FUNCTIONsubcommand — valid or not — is queued byMULTIand thenanswered at
EXECwithERR unknown command 'FUNCTION', with thearguments dropped from the message. Outside a transaction the same commands
work.
Measured (moon @
c5395188,--shards 1and--shards 4, vsredis-server 8.6.1)Raw socket, one fresh connection per case,
MULTI/<cmd>/EXEC:FUNCTION LIST*1-ERR unknown command 'FUNCTION', with args beginning with:*1*0FUNCTION DUMP*1$<payload>FUNCTION STATS*1*[running_script …]FUNCTION BOGUS*1-ERR unknown subcommand 'BOGUS'. Try FUNCTION HELP.Top-level, the same binary answers correctly:
FUNCTIONis the ONLY container with this behaviour. The other twelve(
ACL,CLIENT,COMMAND,CONFIG,MEMORY,MODULE,OBJECT,PUBSUB,SCRIPT,SLOWLOG,XGROUP,XINFO) all execute correctly insideMULTI.Why it matters beyond the wrong text
The
MULTIqueue gate documents its safety argument as queueable iffdispatchable — it reads the same
COMMAND_METAdispatch reads, so a commandcannot become queueable-but-undispatchable.
FUNCTIONbreaks that invariant:COMMAND_METAhas it, so the gate queues it, but theEXECexecutor cannotreach the handler and falls back to the unknown-command path.
This is the moon#639 class — a family that runs through an intercept the
transaction executor cannot call — except that here the fallback lies about
the command existing rather than failing loudly.
Consequence for moon#670
moon#670 adds queue-time rejection of unknown container subcommands.
FUNCTIONhas to be excluded from that gate until this is fixed, because the gate's
notion of "known subcommand" and the executor's notion disagree for this one
container. The exclusion is fenced by a test rather than left as a comment
(
tests/container_subcommand_parity_670.rs).Found
Sweeping all 14 containers × valid and bogus subcommands, top-level and inside
MULTI, against a liveredis-server 8.6.1while implementing moon#670.