Loading the parity record
Fetching the measured run — the pinned upstream oracle, every symbol and every case.
Fetching the measured run — the pinned upstream oracle, every symbol and every case.
Parity / Redis
Every number on this page was produced by running both implementations over the same cases: the real redis-server package pinned at 8.2.2 answers first, and its answer is the expectation the Go port is held to. Nothing is a hand-written expectation, so a new upstream release re-scores the port on its own. See Redis for the port's own documentation. Source: github.com/malcolmston/redis.
Not a generic diagram: every node below names an artefact of this harness — the pinned package it installed, the runner files it started, the case files it streamed, and the counts it wrote out.
| Case group | Cases | Match | Mismatch | Group parity |
|---|---|---|---|---|
| gaps | 23 | 0 | 23 | 0.0% |
| strings | 12 | 10 | 2 | 83.3% |
| sortedsets | 10 | 7 | 3 | 70.0% |
| errors | 9 | 9 | 0 | 100.0% |
| expiry | 7 | 7 | 0 | 100.0% |
| lists | 6 | 5 | 1 | 83.3% |
| bitmaps | 5 | 4 | 1 | 80.0% |
| hashes | 5 | 5 | 0 | 100.0% |
| keyspace | 5 | 5 | 0 | 100.0% |
| sets | 4 | 4 | 0 | 100.0% |
| streams | 4 | 3 | 1 | 75.0% |
| hyperloglog | 3 | 3 | 0 | 100.0% |
Every exported symbol of the upstream package, and what the port offers for it. The upstream list is derived mechanically, never from a README: redis-cli -p <ephemeral> COMMAND COUNT
(integer) 267
redis-cli -p <ephemeral> COMMAND LIST | grep -v '|' | sort # 267 names. A symbol with no case is untested, never a match.
| Upstream symbol | Go symbol | Status | Cases | Note |
|---|---|---|---|---|
| ACL | — | missing | — | not in the RESP dispatch table |
| APPEND | Store.Do("APPEND", …) | match | set-get-basic | |
| ASKING | — | missing | — | not in the RESP dispatch table |
| AUTH | — | missing | — | not in the RESP dispatch table |
| BGREWRITEAOF | — | missing | — | not in the RESP dispatch table |
| BGSAVE | — | missing | — | not in the RESP dispatch table |
| BITCOUNT | Store.Do("BITCOUNT", …) | match | bitmap-bitcount, bitmap-errors | |
| BITFIELD | — | missing | — | not in the RESP dispatch table |
| BITFIELD_RO | — | missing | — | not in the RESP dispatch table |
| BITOP | Store.Do("BITOP", …) | match | bitmap-bitop, bitmap-errors | |
| BITPOS | Store.Do("BITPOS", …) | differs | bitmap-bitpos, bitmap-errors | BITPOS nokey 0 replies 0 upstream (a missing key is an infinite run of zero bits) and -1 in the port |
| BLMOVE | — | missing | — | not in the RESP dispatch table |
| BLMPOP | — | missing | — | not in the RESP dispatch table |
| BLPOP | — | missing | — | not in the RESP dispatch table |
| BRPOP | — | missing | — | not in the RESP dispatch table |
| BRPOPLPUSH | — | missing | — | not in the RESP dispatch table |
| BZMPOP | — | missing | — | not in the RESP dispatch table |
| BZPOPMAX | — | missing | — | not in the RESP dispatch table |
| BZPOPMIN | — | missing | — | not in the RESP dispatch table |
| CLIENT | — | missing | — | not in the RESP dispatch table |
| CLUSTER | — | missing | — | not in the RESP dispatch table |
| COMMAND | — | missing | — | not in the RESP dispatch table |
| CONFIG | — | missing | — | not in the RESP dispatch table |
| COPY | — | missing | gap-rename-copy | not in the RESP dispatch table |
| DBSIZE | Store.Do("DBSIZE", …) | differs | stream-keyspace-invisible, flushall-dbsize | correct for all five stored types; does not count stream keys |
| DEBUG | — | missing | — | not in the RESP dispatch table |
| DECR | Store.Do("DECR", …) | match | incr-decr | |
| DECRBY | Store.Do("DECRBY", …) | match | incr-decr, decrby-llong-min | |
| DEL | Store.Do("DEL", …) | differs | stream-keyspace-invisible, exists-del, del-mixed-types | correct for all five stored types; cannot delete a stream key |
| DISCARD | — | missing | gap-transaction-discard | not in the RESP dispatch table |
| DUMP | — | missing | gap-dump-restore | not in the RESP dispatch table |
| ECHO | — | missing | gap-connection-commands | not in the RESP dispatch table |
| EVAL | — | missing | — | not in the RESP dispatch table |
| EVALSHA | — | missing | — | not in the RESP dispatch table |
| EVALSHA_RO | — | missing | — | not in the RESP dispatch table |
| EVAL_RO | — | missing | — | not in the RESP dispatch table |
| EXEC | — | missing | gap-transactions, gap-transaction-queue-error | not in the RESP dispatch table |
| EXISTS | Store.Do("EXISTS", …) | differs | stream-keyspace-invisible, exists-del | correct for all five stored types; replies 0 for a stream key |
| EXPIRE | Store.Do("EXPIRE", …) | differs | gap-expire-variants, expire-persist, expire-negative-deletes, expire-non-integer | the NX |
| EXPIREAT | — | missing | gap-expire-variants | not in the RESP dispatch table |
| EXPIRETIME | — | missing | gap-expire-variants | not in the RESP dispatch table |
| FAILOVER | — | missing | — | not in the RESP dispatch table |
| FCALL | — | missing | — | not in the RESP dispatch table |
| FCALL_RO | — | missing | — | not in the RESP dispatch table |
| FLUSHALL | Store.Do("FLUSHALL", …) | match | flushall-dbsize | |
| FLUSHDB | — | missing | — | not in the RESP dispatch table |
| FUNCTION | — | missing | — | not in the RESP dispatch table |
| GEOADD | — | missing | gap-geo | not in the RESP dispatch table |
| GEODIST | — | missing | gap-geo | not in the RESP dispatch table |
| GEOHASH | — | missing | gap-geo | not in the RESP dispatch table |
| GEOPOS | — | missing | gap-geo | not in the RESP dispatch table |
| GEORADIUS | — | missing | — | not in the RESP dispatch table |
| GEORADIUSBYMEMBER | — | missing | — | not in the RESP dispatch table |
| GEORADIUSBYMEMBER_RO | — | missing | — | not in the RESP dispatch table |
| GEORADIUS_RO | — | missing | — | not in the RESP dispatch table |
| GEOSEARCH | — | missing | — | not in the RESP dispatch table |
| GEOSEARCHSTORE | — | missing | — | not in the RESP dispatch table |
| GET | Store.Do("GET", …) | match | set-get-basic, set-empty-value | |
| GETBIT | Store.Do("GETBIT", …) | match | bitmap-setbit-getbit, bitmap-errors | |
| GETDEL | — | missing | gap-getdel-getex | not in the RESP dispatch table |
| GETEX | — | missing | gap-getdel-getex | not in the RESP dispatch table |
| GETRANGE | — | missing | gap-setrange-getrange | not in the RESP dispatch table |
| GETSET | Store.Do("GETSET", …) | match | getset | |
| HDEL | Store.Do("HDEL", …) | match | hash-delete-empties-key, hash-arity | |
| HELLO | — | missing | — | not in the RESP dispatch table |
| HEXISTS | Store.Do("HEXISTS", …) | match | hash-basics | |
| HEXPIRE | — | missing | — | not in the RESP dispatch table |
| HEXPIREAT | — | missing | — | not in the RESP dispatch table |
| HEXPIRETIME | — | missing | — | not in the RESP dispatch table |
| HGET | Store.Do("HGET", …) | match | hash-basics, hash-arity | |
| HGETALL | Store.Do("HGETALL", …) | match | hash-basics, hash-missing-key-replies | |
| HGETDEL | — | missing | — | not in the RESP dispatch table |
| HGETEX | — | missing | — | not in the RESP dispatch table |
| HINCRBY | — | missing | gap-hash-extras | not in the RESP dispatch table |
| HINCRBYFLOAT | — | missing | gap-hash-extras | not in the RESP dispatch table |
| HKEYS | Store.Do("HKEYS", …) | match | hash-basics, hash-missing-key-replies | |
| HLEN | Store.Do("HLEN", …) | match | hash-basics, hash-missing-key-replies | |
| HMGET | — | missing | gap-hash-extras | not in the RESP dispatch table |
| HMSET | — | missing | gap-hash-extras | not in the RESP dispatch table |
| HPERSIST | — | missing | — | not in the RESP dispatch table |
| HPEXPIRE | — | missing | — | not in the RESP dispatch table |
| HPEXPIREAT | — | missing | — | not in the RESP dispatch table |
| HPEXPIRETIME | — | missing | — | not in the RESP dispatch table |
| HPTTL | — | missing | — | not in the RESP dispatch table |
| HRANDFIELD | — | missing | gap-hash-extras | not in the RESP dispatch table |
| HSCAN | — | missing | gap-scan | not in the RESP dispatch table |
| HSET | Store.Do("HSET", …) | match | hash-basics, hash-arity, hash-empty-field-and-value | |
| HSETEX | — | missing | — | not in the RESP dispatch table |
| HSETNX | — | missing | gap-hash-extras | not in the RESP dispatch table |
| HSTRLEN | — | missing | gap-hash-extras | not in the RESP dispatch table |
| HTTL | — | missing | — | not in the RESP dispatch table |
| HVALS | Store.Do("HVALS", …) | match | hash-basics, hash-missing-key-replies | |
| INCR | Store.Do("INCR", …) | match | incr-decr, incr-errors | |
| INCRBY | Store.Do("INCRBY", …) | match | incr-decr, decrby-llong-min | |
| INCRBYFLOAT | — | missing | gap-incrbyfloat | not in the RESP dispatch table |
| INFO | — | missing | — | not in the RESP dispatch table |
| KEYS | Store.Do("KEYS", …) | differs | stream-keyspace-invisible, keys-glob | correct for all five stored types; never lists a stream key |
| LASTSAVE | — | missing | — | not in the RESP dispatch table |
| LATENCY | — | missing | — | not in the RESP dispatch table |
| LCS | — | missing | — | not in the RESP dispatch table |
Every case the harness streamed to both runners, with the exact upstream symbol and Go symbol it exercised. A deliberate, documented difference is a deviation and is counted apart from a mismatch.
| Case | Group | Upstream symbol | Go symbol | Status | Note |
|---|---|---|---|---|---|
| bitmap-setbit-getbit | bitmaps | SETBIT/GETBIT | Store.Do SETBIT/GETBIT | match | SETBIT returns the PREVIOUS bit and zero-extends the string |
| bitmap-bitcount | bitmaps | BITCOUNT key [start end [BYTE|BIT]] | Store.Do BITCOUNT | match | |
| bitmap-bitpos | bitmaps | BITPOS key bit [start [end [BYTE|BIT]]] | Store.Do BITPOS | mismatch | |
| bitmap-bitop | bitmaps | BITOP AND|OR|XOR|NOT | Store.Do BITOP | match | FLUSHALL at the end keeps binary results out of the dump; they are compared through BITCOUNT/STRLEN instead |
| bitmap-errors | bitmaps | SETBIT/GETBIT/BITCOUNT/BITPOS/BITOP | Store.Do (bitmap errors) | match | wrong bit values, bad ranges, unknown units and WRONGTYPE |
| wrongtype-list-ops-on-string | errors | WRONGTYPE | Store.Do (ErrWrongType) | match | only whether it errored is compared |
| wrongtype-hash-ops-on-list | errors | WRONGTYPE | Store.Do (ErrWrongType) | match | |
| wrongtype-set-ops-on-hash | errors | WRONGTYPE | Store.Do (ErrWrongType) | match | |
| wrongtype-zset-ops-on-set | errors | WRONGTYPE | Store.Do (ErrWrongType) | match | |
| wrongtype-string-ops-on-list | errors | WRONGTYPE | Store.Do (ErrWrongType) | match | SET replaces a key of any type; the read commands must all fail |
| wrongtype-string-ops-on-zset | errors | WRONGTYPE | Store.Do (ErrWrongType) | match | |
| arity-generic | errors | wrong number of arguments | Store.Do (ErrWrongArgs) | match | |
| unknown-command | errors | unknown command | Store.Do (ErrUnknownCommand) | match | |
| case-insensitive-command-names | errors | command names are case-insensitive | Store.Do (strings.ToUpper) | match | |
| expire-persist | expiry | EXPIRE/PERSIST/TTL/PTTL | Store.Do EXPIRE/PERSIST/TTL/PTTL | match | -1 = no expiry, -2 = no key |
| pexpire | expiry | PEXPIRE | Store.Do PEXPIRE | match | |
| expire-negative-deletes | expiry | EXPIRE key -1 | Store.Do EXPIRE key -1 | match | a past expiry deletes the key immediately |
| expire-elapses | expiry | SET .. PX | Store.Do SET .. PX | match | real 400ms sleep against a 120ms TTL |
| pexpire-elapses | expiry | PEXPIRE | Store.Do PEXPIRE | match | expiry applies to every value type |
| expire-non-integer | expiry | EXPIRE | Store.Do EXPIRE | match | |
| expire-other-types | expiry | EXPIRE | Store.Do EXPIRE | match | |
| gap-mset-mget | gaps | MSET/MGET/MSETNX | — | mismatch | not in the RESP dispatch table |
| gap-setex-setnx | gaps | SETEX/PSETEX/SETNX | — | mismatch | not in the RESP dispatch table |
| gap-getdel-getex | gaps | GETDEL/GETEX | — | mismatch | not in the RESP dispatch table |
| gap-setrange-getrange | gaps | GETRANGE/SETRANGE | — | mismatch | not in the RESP dispatch table |
| gap-incrbyfloat | gaps | INCRBYFLOAT | — | mismatch | not in the RESP dispatch table |
| gap-list-mutators | gaps | LSET/LINSERT/LTRIM/LREM/LPOS | — | mismatch | not in the RESP dispatch table |
| gap-lmove-lmpop | gaps | LMOVE/LMPOP/RPOPLPUSH | — | mismatch | not in the RESP dispatch table |
| gap-hash-extras | gaps | HINCRBY/HINCRBYFLOAT/HMGET/HMSET/HSETNX/HSTRLEN/HRANDFIELD | — | mismatch | not in the RESP dispatch table |
| gap-set-extras | gaps | SMOVE/SPOP/SRANDMEMBER/SMISMEMBER | — | mismatch | single-member sets keep SPOP/SRANDMEMBER deterministic |
| gap-set-store | gaps | SINTERSTORE/SUNIONSTORE/SDIFFSTORE/SINTERCARD | — | mismatch | not in the RESP dispatch table |
| gap-zset-extras | gaps | ZINCRBY/ZCOUNT/ZPOPMIN/ZPOPMAX/ZREMRANGEBY* | — | mismatch | not in the RESP dispatch table |
| gap-zset-lex | gaps | ZRANGEBYLEX/ZLEXCOUNT/ZREVRANGEBYSCORE/ZRANGESTORE/ZRANGE BYLEX | — | mismatch | not in the RESP dispatch table |
| gap-scan | gaps | SCAN/HSCAN/SSCAN/ZSCAN | — | mismatch | not in the RESP dispatch table |
| gap-rename-copy | gaps | RENAME/RENAMENX/COPY | — | mismatch | not in the RESP dispatch table |
| gap-transactions | gaps | MULTI/EXEC | — | mismatch | MULTI/EXEC are not reachable over RESP in the port |
| gap-transaction-discard | gaps | MULTI/DISCARD | — | mismatch | DISCARD rolls the queue back; EXEC outside MULTI is an error |
| gap-transaction-watch | gaps | WATCH/UNWATCH | — | mismatch | not reachable over RESP in the port |
| gap-transaction-queue-error | gaps | MULTI (queue error aborts EXEC) | — | mismatch | |
| gap-connection-commands | gaps | PING/ECHO/SELECT | — | mismatch | no connection-level commands in the port |
| gap-keyspace-extras | gaps | RANDOMKEY/TOUCH/OBJECT/UNLINK/SORT | — | mismatch | not in the RESP dispatch table |
| gap-expire-variants | gaps | EXPIRE NX|XX|GT|LT, EXPIREAT, EXPIRETIME | — | mismatch | the port's EXPIRE takes exactly two arguments |
| gap-geo | gaps | GEOADD/GEODIST/GEOPOS/GEOHASH | — | mismatch | not in the RESP dispatch table |
| gap-dump-restore | gaps | DUMP/OBJECT REFCOUNT | — | mismatch | DUMP of a real key embeds an RDB version, so only the nil case is scripted |
| hash-basics | hashes | HSET/HGET/HEXISTS/HLEN/HKEYS/HVALS/HGETALL | Store.Do HSET/HGET/HEXISTS/HLEN/HKEYS/HVALS/HGETALL | match | HSET returns the number of NEW fields; HKEYS/HVALS/HGETALL sorted on both sides |
| hash-delete-empties-key | hashes | HDEL | Store.Do HDEL | match | a hash with no fields stops existing |
| hash-missing-key-replies | hashes | HGETALL/HKEYS/HVALS/HLEN | Store.Do HGETALL/HKEYS/HVALS/HLEN | match | empty array / zero, never an error |
| hash-arity | hashes | HSET/HGET/HDEL | Store.Do HSET/HGET/HDEL | match | odd field/value counts are an error |
| hash-empty-field-and-value | hashes | HSET | Store.Do HSET | match | empty field names and values are legal |
| hll-basic | hyperloglog | PFADD/PFCOUNT/PFMERGE | Store.Do PFADD/PFCOUNT/PFMERGE | match | PFADD replies 1 only when the sketch changed |
| hll-cardinality-20 | hyperloglog | PFCOUNT | Store.Do PFCOUNT | match | small-cardinality estimates must agree exactly, not approximately |
| hll-empty-and-errors | hyperloglog | PFADD/PFCOUNT/PFMERGE | Store.Do (HLL errors) | match | PFADD with no elements still creates the key; non-HLL strings are WRONGTYPE |
| exists-del | keyspace | EXISTS/DEL | Store.Do EXISTS/DEL | match | EXISTS counts repeats, DEL returns how many were removed |
| type-of-every-kind | keyspace | TYPE | Store.Do TYPE | match | TYPE is a simple string; a missing key is 'none' |
| keys-glob | keyspace | KEYS pattern | Store.Do KEYS | match | results sorted on both sides |
| flushall-dbsize | keyspace | FLUSHALL/DBSIZE | Store.Do FLUSHALL/DBSIZE | match | |
| del-mixed-types | keyspace | DEL | Store.Do DEL | match | DEL works on every value type |
| list-push-pop | lists | LPUSH/RPUSH/LPOP/RPOP/LLEN/LINDEX/LRANGE | Store.Do LPUSH/RPUSH/LPOP/RPOP/LLEN/LINDEX/LRANGE | match | |
| lrange-bounds | lists | LRANGE | Store.Do LRANGE | match | out-of-range and inverted windows clamp to an empty array |
| list-pop-empties-key | lists | LPOP/RPOP | Store.Do LPOP/RPOP | match | an emptied list stops existing |
| list-arity-and-non-integer | lists | RPUSH/LPUSH/LRANGE/LINDEX/LLEN | Store.Do RPUSH/LPUSH/LRANGE/LINDEX/LLEN | match | arity errors and non-integer indexes |
| list-pop-with-count | lists | LPOP key [count] | Store.Do LPOP key count | mismatch | the optional count argument of LPOP/RPOP |
| list-duplicates-and-order | lists | RPUSH/LPUSH | Store.Do RPUSH/LPUSH | match | lists keep duplicates and insertion order |
| set-basics | sets | SADD/SREM/SCARD/SISMEMBER/SMEMBERS | Store.Do SADD/SREM/SCARD/SISMEMBER/SMEMBERS | match | SMEMBERS sorted on both sides |
| set-empty-removes-key | sets | SREM | Store.Do SREM | match | |
| set-algebra | sets | SINTER/SUNION/SDIFF | Store.Do SINTER/SUNION/SDIFF | match | an absent key behaves as the empty set; results sorted on both sides |
| set-arity | sets | SADD/SREM/SISMEMBER/SCARD/SMEMBERS/SINTER | Store.Do SADD/SREM/SISMEMBER/SCARD/SMEMBERS/SINTER | match | |
| zset-basics | sortedsets | ZADD/ZCARD/ZSCORE/ZRANK/ZREVRANK/ZRANGE/ZREVRANGE/ZREM | Store.Do ZADD/ZCARD/ZSCORE/ZRANK/ZREVRANK/ZRANGE/ZREVRANGE/ZREM | match | ZADD returns only newly added members; re-adding updates the score |
| zset-fractional-scores | sortedsets | ZADD/ZSCORE | Store.Do ZADD/ZSCORE | match | score reply formatting must match exactly |
| zset-infinite-scores | sortedsets | ZADD key +inf member | Store.Do ZADD key +inf member | mismatch | Redis prints infinite scores as inf / -inf |
| zset-large-scores | sortedsets | ZADD/ZSCORE | Store.Do ZADD/ZSCORE | mismatch | Redis never uses exponent notation in score replies |
| zset-ties-sort-lexically | sortedsets | ZADD/ZRANGE | Store.Do ZADD/ZRANGE | match | equal scores order by member lexicographically |
| zrange-bounds | sortedsets | ZRANGE/ZREVRANGE | Store.Do ZRANGE/ZREVRANGE | match | |
| zrangebyscore | sortedsets | ZRANGEBYSCORE | Store.Do ZRANGEBYSCORE | match | inclusive by default, ( makes a bound exclusive |
| zadd-flags | sortedsets | ZADD NX|XX|GT|LT|CH|INCR | Store.Do ZADD (flags) | mismatch | |
| zset-arity-and-errors | sortedsets | ZADD/ZSCORE/ZRANGE/ZREM | Store.Do ZADD/ZSCORE/ZRANGE/ZREM | match | |
| zset-empty-removes-key | sortedsets | ZREM | Store.Do ZREM | match | |
| stream-xadd-xlen-xrange | streams | XADD/XLEN/XRANGE | Store.Do XADD/XLEN/XRANGE | match | FLUSHALL last: the port keeps streams outside the keyspace, so only the steps are comparable here (see stream-keyspace-invisible) |
| stream-xadd-id-rules | streams | XADD (monotonic IDs) | Store.Do XADD | match | IDs must strictly increase; 0-0 and malformed IDs are errors |
| stream-xread | streams | XREAD | Store.Do XREAD | match | a stream with nothing newer replies nil |
| stream-keyspace-invisible | streams | XADD then TYPE/EXISTS/KEYS/DBSIZE/DEL | Store.Do (streams side registry) | mismatch | in the port streams live in a package-level registry outside the keyspace, so TYPE/EXISTS/KEYS/DBSIZE/DEL cannot see a stream key |
| set-get-basic | strings | SET/GET/STRLEN/APPEND | Store.Do SET/GET/STRLEN/APPEND | match | SET returns +OK, GET of a missing key is nil, APPEND creates the key |
| set-empty-value | strings | SET/GET | Store.Do SET/GET | match | the empty string is a real value, not an absent key |
| set-nx-xx | strings | SET key value NX|XX | Store.Do SET .. NX|XX | match | a rejected NX/XX SET replies nil, not an error |
| set-nx-and-xx | strings | SET key value NX XX | Store.Do SET .. NX XX | match | NX and XX together is a syntax error |
| set-ex-clears-on-plain-set | strings | SET key value EX | Store.Do SET .. EX | match | a plain SET discards the previous TTL |
| set-keepttl | strings | SET key value KEEPTTL | Store.Do SET .. KEEPTTL | mismatch | KEEPTTL retains the TTL across a rewrite |
| set-px | strings | SET key value PX | Store.Do SET .. PX | match | PTTL rounded up to whole seconds for determinism |
| set-ex-invalid | strings | SET key value EX seconds | Store.Do SET .. EX | mismatch | a non-positive or non-integer expire is an error and must not create the key |
| getset | strings | GETSET | Store.Do GETSET | match | GETSET returns the previous value, nil when absent |
| incr-decr | strings | INCR/DECR/INCRBY/DECRBY | Store.Do INCR/DECR/INCRBY/DECRBY | match | counters are stored as decimal strings |
| incr-errors | strings | INCR | Store.Do INCR | match | non-integer content and 64-bit overflow are errors |
| decrby-llong-min | strings | DECRBY/INCRBY | Store.Do DECRBY/INCRBY | match | negating LLONG_MIN is not representable and must be rejected |