DOC-6823 make dependent data-type examples runnable in the interactive CLI#3604
Open
andy-stark-redis wants to merge 28 commits into
Open
DOC-6823 make dependent data-type examples runnable in the interactive CLI#3604andy-stark-redis wants to merge 28 commits into
andy-stark-redis wants to merge 28 commits into
Conversation
…ractive CLI
Removes the try_it="false" opt-out from the zrank and zadd_lex examples so the
"Try it" button and on-page terminal can run them. zrank is made fully
self-contained: its CLI session and every client tab first recreate the
post-deletion {Norem 10, Royce 10, Prickett 14} state, so ZRANK/ZREVRANK return
0/2 in a cold database. Adds the two missing Lettuce overrides (async + reactive)
under local_examples/client-specific so all ten language tabs tell the same story.
The dependency only ever bit the external Try-it button (fresh DB) and isolated
single-step runs — the on-page terminal shares one session per page and auto-runs
snippets top-to-bottom, so the chained tutorial already worked there. The built-in
needs_prereq replay was no help for these two steps because it replays only the
set-level prereq (the original six-racer ZADD), whereas zrank/zadd_lex depend on
the mutated three-racer state left by zremrangebyscore; hence the explicit recreate
rather than needs_prereq. The recreate has to sit inside the STEP_START block to
show in the client tab (Go keeps its setup outside the markers). zadd_lex was left
reset-free on purpose: in a cold sandbox its first ZADD reports 6 added rather than
the documented 3, but it runs without error and every later line is correct, which
is preferable to cluttering the lexicographic example with a reset.
Learned: self-containment matters only for the Try-it button / isolated runs, not the shared-session on-page terminal
Directive: don't add a state reset to the zadd_lex CLI example — the cold-sandbox 6-vs-3 ZADD count is an accepted cosmetic diff, not a bug
Directive: the Lettuce reactive SortedSetExample exists only as a local_examples override — push it to redis/lettuce so their CI covers it
Ticket: DOC-6823
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Contributor
Removes try_it="false" from the setnx_xx example and prepends a recreate so it's self-contained for the "Try it" button and isolated single-step runs. Simpler than the sorted-set zrank fix: the only precondition is that bike:1 exists, and SET always returns OK, so a single re-establishing SET suffices — no DEL and no run-order-dependent output line. Adds the two missing Lettuce string overrides (async + reactive). All eleven client examples for this set (redis-cli plus 10 libraries) were run against a live Redis via build/example-test-harness and pass with their in-file assertions. Directive: the Lettuce string overrides duplicate upstream — push them to redis/lettuce so their CI covers them Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds build/example-test-harness: given an example set, it runs each client's local_examples source file against a live throwaway Redis on localhost:6379, using each library's real in-file assertions, and prints a pass/fail matrix. Covers all 11 client tabs (python, node, go, jedis, lettuce async+reactive, c#, php, ruby, rust sync+async). Built to verify the DOC-6823 self-containment edits and reusable for the rest of the try_it="false" backlog — adding an example set is one src_path() case block. Dev-only tooling, not part of the Hugo build; cached projects (work/) and logs (results/) are gitignored. Toolchain versions and the trickier setup notes live in the README. Constraint: the harness FLUSHes before each run — point it only at a scratch Redis Learned: redis-rs is now 1.x (flushall is absent in 0.27); Surefire's default pattern skips *Example classes so the POMs add an explicit include; C# and PHP examples need their repo's test base classes stubbed Directive: add a src_path() case block per new example set Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… CLI Removes try_it="false" from the hmget and hincrby examples and prepends a recreate (DEL bike:1 + HSET of the full bike object) so each runs standalone. Unlike zadd_lex (where only a count differed), the cold-sandbox output here was entirely wrong — hmget returned all nils and hincrby returned 100 instead of 5072 — so the recreate is required, not cosmetic. Adds the missing Lettuce async HashExample override (a reactive one already existed locally). Wires hash_tutorial into build/example-test-harness. The Lettuce reactive file needed care: its hmget Mono shared a single Mono.when(...) with the set_get_all reads, so a DEL-based recreate inside that group would race the concurrent hget/hgetall on the same key. Pulled hmget out to block sequentially after the reads. All 11 client examples for this set were run against a live Redis via the harness and pass. Learned: a DEL-based recreate inside a reactive Mono.when races sibling reads on the same key — sequence it, don't group it Directive: the new Lettuce async HashExample override duplicates upstream — push it to redis/lettuce so their CI covers it Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ve CLI Removes try_it="false" from the seven dependent timeseries examples (madd, get, range_filter, agg, agg_align, comp_add, del) and prepends a recreate to each so it runs standalone. Every example uses explicit timestamps, so the recreates are fully deterministic — each CLI sequence was run against live Redis and reproduces the documented output exactly (e.g. agg's 1.95/2.10/1.78 buckets, comp_add's empty→(0,75), del's sample counts). Applies the matching recreates to the redis-py client and wires time_series_tutorial into build/example-test-harness. Only the leading DEL count is cosmetic (shown as the top-to-bottom value), same accepted diff as zrank. Out of scope but noted: the redis-py harness run surfaced a pre-existing staleness in create_compaction (not opted out) — it asserts the old list-of-lists TS.INFO `.rules` format, but redis-py 8.0.1 returns a dict, and the upstream redis-py doctest has the same stale assertion. Left for a redis-py-side fix. Learned: timeseries examples use explicit timestamps, so recreates are deterministic; TS.INFO memoryUsage / `.rules` are display/version-dependent, not the assertion basis for the opted-out steps Directive: don't "fix" the leading DEL counts in these examples — cosmetic cold-sandbox 0-vs-N, the accepted diff established by zrank Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Applies the same seven recreates (madd, get, range_filter, agg, agg_align, comp_add, del) to the go-redis timeseries example so each client tab matches the CLI. Verified end-to-end via build/example-test-harness (go test, all Example Output blocks pass) — go-redis has no equivalent of the redis-py `.rules` version-skew, so the full file runs clean. Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Creates local overrides for the three upstream-only timeseries clients (jedis, node-redis, NRedisStack) with the same seven recreates as the CLI/python/go steps, completing client-tab parity across all five rendered timeseries clients. Adds NRedisStack + bumps StackExchange.Redis to 3.0.0 in the harness dotnet project (the C# timeseries example uses db.TS()); confirmed the bump doesn't regress the earlier C# examples. Verification via build/example-test-harness: Go, Jedis, and C# full files pass end-to-end. Jedis timeseries needs jedis 8.x (RedisClient) whereas the other jedis examples use 5.x UnifiedJedis, so the harness pom stays 5.2.0 and jedis timeseries was verified via a one-off 8.x bump. Python and Node full-file runs are blocked by pre-existing, out-of-scope version staleness in non-opted-out steps (redis-py `.rules` dict; node float precision on query_multi's mGet) — the recreates in those files are validated via the shared redis-cli sequences run earlier. Learned: timeseries client examples span client-library generations — jedis TS uses RedisClient (8.x) while other jedis examples use UnifiedJedis (5.x), so no single harness pin runs both; NRedisStack 1.6 forces StackExchange.Redis >= 3.0.0 Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removes try_it="false" from the smismember example and prepends a recreate (DEL bikes:racing:france + SADD bike:1 bike:2 bike:3) so it runs standalone. Validated via redis-cli: SADD->3, SISMEMBER bike:1->1, SMISMEMBER bike:2/3/4->1,1,0. Client-tab parity (10 local clients + a lettuce-async override) still to follow. Directive: don't "fix" the leading DEL count — cosmetic cold-sandbox 0-vs-1, the accepted diff established by zrank Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Brings the ten sets client tabs into line with the CLI snippet by adding the
DEL + SADD recreate to each smismember step, so the "Try it" button and any
isolated single-step run land in the {bike:1, bike:2, bike:3} state the reads
expect. Go was left untouched: its per-function ExampleClient_smismember
already recreates the set outside the STEP markers, which is the established
Go pattern. The Lettuce async tab had no local override at all (it rendered
straight from the upstream redis/lettuce source), so it is created here as a
faithful 1:1 async translation of the reactive override. All eleven clients
pass the example-test-harness, which now carries a sets_tutorial block.
Learned: the reactive recreate cannot live inside the shared Mono.when() with the reads — a DEL there races the sibling reads on the same key, so it is blocked sequentially first; async thenCompose chains are ordered, so the recreate sits safely inline
Constraint: keep the Lettuce-reactive smismember recreate out of Mono.when() and .block() it before the reads
Directive: local_examples/tmp/lettuce-async/SetExample.java is a docs-only override with no upstream counterpart — push it to redis/lettuce so their CI covers it
Ticket: DOC-6823
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removes the try_it="false" opt-out from the geosearch example. Rather than the zrank-style in-snippet recreate, geosearch is wired with the built-in prereq mechanism: geoadd is marked prereq="true" and geosearch needs_prereq="true", so the "Try it" button replays the three-station GEOADD before running GEOSEARCH. This is the correct, lighter tool here because geosearch depends only on the base add, not on any mid-sequence mutation (the reason zrank/smismember needed an explicit recreate). It also matters because geo_tutorial has no local overrides at all — every client tab renders straight from the upstream client repos — so a recreate would have meant creating five new override files; needs_prereq needs none. Validated against redis 8: fresh DB, replay geoadd, then the documented GEOSEARCH WITHDIST output (1.8523 / 1.4979 / 2.2441) matches. Learned: needs_prereq is the right fix when a step depends only on the set's base add; reserve the in-snippet recreate for steps that depend on a mid-sequence mutation (delete/trim) which needs_prereq cannot reproduce Rejected: zrank-style in-snippet recreate for geosearch | would have forced five new local client overrides since geo_tutorial is upstream-only, where needs_prereq requires none Gaps: verified at the redis-cli level and against the proven sets sadd/sinter shortcode pattern; did not build the Hugo site to click the rendered Try-it button Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o.when The reactive string tutorial composed all five steps with Mono.when(setAndGet, setnx, setxx, mset, incrby).block(), which subscribes the cold publishers concurrently. Four of them mutate bike:1 (SET/SETNX/SET XX/MSET), so setnx's "value is unchanged" read and the setxx/mset writes raced each other and could fail assertions intermittently under the harness. Replaced the concurrent when() with a sequential setAndGet.then(setnx).then(setxx).then(mset) .then(incrby) chain — deterministic, and matching how the async override sequences with per-step join() and how the sets reactive override blocks per step. Bugbot 3544441638 flagged this; its other two findings on this PR (async allOf "race", node harness "missing dep") were false positives — async del fires on-call and is dispatch-ordered on one connection, and the redis npm metapackage hoists @redis/time-series transitively. Learned: only read-only steps are safe to combine under a shared reactive Mono.when; steps that mutate the same key must be sequenced or they race each other's reads Constraint: in the Lettuce reactive doc overrides, never combine key-mutating steps under one Mono.when() — sequence them (.then chain or per-step .block()) Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… score bounds The Lettuce async/reactive and Jedis sorted-set examples passed Double.MIN_VALUE as the lower bound of ZRANGEBYSCORE/ZREMRANGEBYSCORE to mean -inf. But Double.MIN_VALUE is Java's smallest *positive* value (~4.9e-324), so the range was really ~0..N, not -inf..N. It happened to print the documented output here because every score is >= 6, but it silently drops zero/negative scores and teaches a pattern readers copy. Both Jedis and Lettuce serialize Double.NEGATIVE_INFINITY to the "-inf" the CLI example uses, so that is the correct constant. Bugbot 3550287458 flagged the two Lettuce files (new on this branch); the identical Jedis instance predates the branch (DOC-6057, 2569d4b) and is folded in here so all three sorted-set client tabs agree. Harness PASS for jedis, lettuce-async, and lettuce-reactive. Learned: Double.MIN_VALUE is the smallest positive double, not -inf; an unbounded lower score bound must be Double.NEGATIVE_INFINITY, which both Jedis and Lettuce emit as "-inf" Constraint: score-range lower bounds that mean -inf use Double.NEGATIVE_INFINITY, never Double.MIN_VALUE Directive: don't reintroduce Double.MIN_VALUE-as-(-inf) here; it was copied from the pre-existing jedis example, so check all three sorted-set client files together Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eate+load prereq Enables the interactive CLI on the document-database quickstart's two term queries (query_single_term, query_exact_matching) by merging the create_index and add_documents steps into one prereq block (FT.CREATE + the ten JSON.SETs) and marking the queries needs_prereq. search_quickstart had no local client overrides (all upstream) and the two steps are separate in every client, so the merge is delivered as five local overrides that delete only the boundary STEP markers between create_index and add_documents -- behaviour-identical to upstream (only comment lines moved). The wildcard query is deliberately left opted out: FT.SEARCH "*" has no SORTBY, so its order is version-dependent (on Redis 8.8 it is bicycle:0,1,2,5,4,9,6,3,8,7 and the documented output is already stale), and enabling its Try-it button would promise a reproducible ordering we cannot guarantee. Verified on Redis 8.8: no async index-population race, and both term-query prereq replays return the exact documented documents. Learned: on Redis 8.8, JSON indexing kept up with back-to-back FT.CREATE + 10x JSON.SET + FT.SEARCH (no async-population race), so needs_prereq alone seeds the term queries reliably -- no settle/retry needed Constraint: the merged create_index step must contain BOTH the FT.CREATE and the document load; the two term queries depend on it through needs_prereq Rejected: enabling the wildcard query's Try-it button | FT.SEARCH "*" has no SORTBY, so its result order is RediSearch-version-dependent and unreproducible against the static documented output Directive: the five search_quickstart overrides are marker-only merges of the upstream client sources -- if you re-sync from upstream, re-apply the create_index/add_documents STEP merge rather than hand-editing the code Recheck: wildcard result order + the documented output are RediSearch-version-specific (checked on 8.8) Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Each of the two sections on the geoindex page is now a single self-contained clients-example box that creates its index, adds its JSON documents, and runs its query, so the interactive CLI works with no prereq wiring. Self-contained was chosen over a shared "create both indexes" prereq because each query returns a single deterministic result (no SORTBY/ordering issue) and because the client sources keep the two index creations non-adjacent -- a shared prereq would have forced relocating create_gshape_idx in four overrides, whereas each section's three steps are already consecutive, so the merge is marker-only. Delivered as four local overrides (redis-py/go-redis/jedis/nredisstack; there is no node-redis upstream for this page) that delete only interior STEP markers. Verified on Redis 8.8: each box runs standalone on a fresh DB and returns the documented product:46885 (GEO) / shape:4 (GEOSHAPE). Learned: geoindex's two FT.SEARCH queries each return a single deterministic doc (no multi-result ordering issue), so full create+add+query self-contained boxes work with no prereq/needs_prereq Rejected: a shared "create both indexes" prereq block | the client sources keep the two index creations non-adjacent, so it would force relocating create_gshape_idx in 4 overrides, whereas self-contained per-section needs only marker-only merges Directive: the four geoindex overrides are marker-only merges of the upstream client sources -- re-apply the per-section STEP merge if you re-sync from upstream, don't hand-edit the code Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…li URL limit) The external "Try it" button passes commands as base64 in the redis.io/cli URL, which caps at roughly 8192 bytes. The document-database create+load set (FT.CREATE + ten long JSON.SET descriptions) base64-encodes to ~8.6 KB -- over the cap -- and the two term queries inherit that size through needs_prereq, so all three interactive blocks are now try_it="false". Note the raw CLI text is only ~6 KB: the limit bites at the base64/URL layer, not the typed-command layer. The on-page terminal (one shared session, run top-to-bottom) still executes them, and the prereq/needs_prereq wiring is kept so the button can be re-enabled if the limit is ever raised. A repo-wide audit of all 559 interactive clients-example blocks (accounting for the needs_prereq prepend) found this is the only page over the limit. Learned: the Try-it button's size limit is on the base64 URL payload (~8192 B), not the raw CLI text -- doc-database's raw commands are ~6 KB but base64 to ~8.6 KB, and needs_prereq blocks inherit their prereq's payload size Constraint: keep try_it="false" on the document-database create_index + term-query blocks while the create+load payload base64s to over ~8192 bytes Directive: the prereq/needs_prereq wiring on this page is kept on purpose despite try_it="false" -- re-enable the button by removing try_it="false" only if the redis.io/cli payload limit is raised Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oad sizes Scans every interactive clients-example block and flags any whose external "Try it" button payload (base64 of the JSON command array, including the needs_prereq prepend) exceeds the redis.io/cli ~8192-byte URL limit. Exits 1 if any are over, so it can gate CI. Found and fixed document-database as the sole offender in this PR; this makes the check repeatable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…re-enable button Trims the two most verbose, un-queried bicycle descriptions (bicycle:6 WattBike, bicycle:7 Secto) so the create+load Try-it payload drops from ~8.6 KB base64 to ~7.1 KB (87% of the ~8192 limit). The three interactive blocks (the create_index prereq and the two term queries) therefore get try_it re-enabled -- the explicit try_it="false" is removed. Only descriptions that NO query touches were trimmed. The client override files carry hidden query steps (not shown on the page) that search "basic" (bicycle:5), "analytics" (bicycle:3), and "mountain" (bicycle:2/8/9, asserted total==3 with a BM25 equal-score tie between bicycle:2 and bicycle:9). Those docs are left intact; bicycle:6/7 are neither queried nor "mountain" docs, so the corpus-sensitive BM25 assertions still hold. Verified by running the redis-py override (the query superset) against Redis 8.8: EXIT 0, mountain total==3, bicycle:2==bicycle:9 tie, all fuzzy/scorer/aggregation asserts pass. The same trimmed text is applied across the markdown (JSON.SET command + wildcard static output) and all five client overrides. build/check_tryit_payloads.py now reports 0 over. Learned: trimming a doctest description only breaks something if that exact text is queried; the hidden search_quickstart steps depend on "basic"/"analytics"/"mountain" plus a BM25 total==3 and an equal-score tie among the mountain docs, so trimming the un-queried outliers is safe (confirmed on Redis 8.8) Constraint: keep "basic" in bicycle:5, "analytics" in bicycle:3, and "mountain" in bicycle:2/8/9 (the total==3 + equal-score BM25 assertions depend on them) when editing these descriptions Directive: the same description text must stay identical across the markdown JSON.SET command, the wildcard static output, and all five client overrides -- edit all six together Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nt-database button
The real redis.io/cli cap is ~4094 bytes on the HTTP request line ("Request Line
is too large (7163 > 4094)"), not 8192 on the payload as first assumed -- roughly
half. The document-database create+load is ~7.2 KB base64 even after trimming two
descriptions, so its three interactive blocks go back to try_it="false" (the
on-page terminal still runs them). build/check_tryit_payloads.py now models the
request line (base64 + ~40 B scaffolding) against a 4094 limit instead of 8192,
and re-auditing found document-database is still the only page OVER; the
json_tutorial blocks on data-types/json/path.md sit at 87-98% (near but under).
Learned: the redis.io/cli "Try it" cap is ~4094 bytes on the HTTP request line (base64 payload + ~24-40 B of GET/query scaffolding), not 8192 on the payload -- a 10-JSON-document create+load can't fit without gutting the descriptions
Constraint: keep document-database's create_index + term-query blocks try_it="false" until the create+load base64 payload is under ~4054 bytes
Gaps: json_tutorial (data-types/json/path.md) has ~12 interactive blocks at 87-98% of the 4094 limit -- pre-existing, under the cap today, but one edit from breaking; not changed here
Ticket: DOC-6823
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…overrides
Cursor Bugbot flagged 6 issues across the search_quickstart and geoindex client
overrides added in this PR. All are pre-existing defects in the upstream client
examples that we inherited by copying them into local_examples -- the STEP-marker
merge and description trims did not introduce them; they surface now only because
Bugbot reviews these files for the first time. Fixes:
- node search_quickstart: "// REMOVE END" -> "// REMOVE_END" (the typo left the
REMOVE region open, stripping everything after it).
- C# search_quickstart: bicycle:0 (Jigger) Condition "used" -> "new" to match the
page and every other client; the aggregation only asserts the group count (3),
so no ripple -- just corrected the stale output comment (and jedis's identical
stale used-5/new-4 comment) to new-5/used-4.
- C# geoindex: GEOSHAPE query given an explicit .Dialect(2) -- the WITHIN operator
is a syntax error on the server-default dialect 1 (verified on Redis 8.8).
- jedis geoindex: geom index addPrefix("shape") -> "shape:" for consistency with
the documented PREFIX and the other clients.
- C# geoindex: debug prints after shape:2 / shape:4 fixed to gmJsonRes2 / gmJsonRes4.
- jedis search_quickstart: wrapped the bare aggregation assertEquals in
REMOVE_START/END, matching every other assert in the file.
Learned: creating local_examples overrides by copying upstream client files pulls their latent defects into our repo and review scope; Bugbot then flags them as "new" though they predate the copy -- budget an upstream-quality pass when localizing example files
Directive: these fixes should also land upstream (redis/node-redis, redis/NRedisStack, redis/jedis) since the overrides are otherwise faithful copies
Ticket: DOC-6823
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pact, UTF-8)
Bugbot correctly flagged that the checker used default json.dumps (spaces after
',' and ':', plus \uXXXX escapes), while the site's Try-it button base64s
JSON.stringify output, which is compact and keeps real Unicode. The mismatch
overstated payload sizes and could mis-flag near-limit blocks. Switched to
separators=(",", ":") + ensure_ascii=False + UTF-8 bytes, matching
btoa(unescape(encodeURIComponent(JSON.stringify(cmds)))). This also tightened the
calibration: document-database's create_index is now b64=7126, and the observed
"Request Line is too large (7163 > 4094)" implies ~37 B of GET/HTTP scaffolding --
matching the checker's conservative --overhead 40.
Learned: to size the Try-it button payload accurately, match the browser serialization exactly (JSON.stringify = compact separators + real UTF-8), not Python's default json.dumps; the ~40 B overhead is the full HTTP request line (GET + target + HTTP/1.1), confirmed against the observed 7163
Ticket: DOC-6823
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…usage The module doc and usage example still described an ~8192-byte payload cap and --limit 8192, but main() defaults to 4094 (the HTTP request-line limit). Running the script as documented would have used a limit ~2x the real redis.io/cli constraint, letting oversized Try-it URLs pass. Docstring now matches the code: ~4094 on the request line, base64 must be <= ~4054, --limit 4094 --overhead 40. Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removes the historical "early guess of 8192" parenthetical so nothing in the tool still names 8192 as a cap; the request-line limit (4094) is now the only figure mentioned. Closes the last thread in the checker-doc consistency churn. Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…erride
The jedis Bicycle constructor is (brand, model, ...), but bicycle:9 passed
("ThrillCycle", "BikeShind"), indexing brand/model inverted versus the docs and
every other client (brand=BikeShind, model=ThrillCycle). Pre-existing upstream
defect; the other clients use named fields so were unaffected. No query asserts
on bicycle:9's brand/model, so the swap is safe.
Ticket: DOC-6823
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…arness muxer Addresses two Bugbot findings plus a defect surfaced while verifying them: - C# search_quickstart used PascalCase JSON paths ($.Brand, @model:Jigger) while the docs CLI and every other client use lowercase, so data loaded via the documented JSON.SET would not match the C# index/queries. Lowercased the field identifiers throughout (data props, schema paths + aliases, query fields, result-key access); the "Count" reducer alias is untouched. Verified: the C# example PASSES the harness on Redis 8.8. - Harness dotnet stub GetCleanDatabase connected a new ConnectionMultiplexer per call and never disposed it; now it retains one and disposes it in Dispose(). - (found via verification) geoindex redis-py imported the pre-8 path redis.commands.search.indexDefinition, gone in redis-py 8 (renamed index_definition, which the sibling search_quickstart file already uses). Users copying the tab got ImportError. Fixed; geoindex python now PASSES. Wired search_quickstart + geoindex into the harness: python, go, dotnet PASS for both. Two known non-blocking gaps documented in run.sh: jedis needs a jedis 8.x pom (RedisClient API vs the shared 5.2), and node search_quickstart's wildcard assertion is RediSearch-version-order-dependent (test-only, not docs-visible). Learned: the wildcard-ordering fragility we kept opted-out in the docs also bites the node client's REMOVE-block assertion (documents[0].id) on Redis 8.8 -- a no-SORTBY FT.SEARCH "*" is version-order-dependent everywhere it's asserted Directive: the C#/py/jedis fixes are pre-existing upstream defects in faithful copies -- land them upstream too (redis/NRedisStack, redis/redis-py, redis/jedis) Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The harness mapped geoindex/search_quickstart (and, pre-existing, time_series) to jedis examples that use the jedis RedisClient API, but pom-jedis.xml pinned 5.2, so those rows failed at compile — the matrix implied a runnable jedis client that wasn't (Bugbot 3552419502). jedis 7.5.3 (latest stable) ships BOTH RedisClient and the older UnifiedJedis, so a single shared-pom bump fixes it without a per-example pom. Verified every jedis row now PASSES on Redis 8.8: ss/set/hash/ sets/time_series (UnifiedJedis) + search_quickstart/geoindex/time_series (RedisClient). Only remaining harness gap is node search_quickstart's version-order-dependent wildcard assertion (test-only, not docs-visible). Learned: jedis RedisClient (the newer client) is available from jedis 7.x, not only 8.x, and 7.5.3 keeps UnifiedJedis too -- so one pom serves both old and new examples; my earlier "one-off 8.x bump for TS jedis" note was wrong (5.2 simply lacked RedisClient, and the TS pass had been a manual work-dir edit) Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The drive loop ran redis-cli flushall ignoring its exit status, so a failed flush (Redis down, wrong host, permissions) would let examples run against leftover keys and pass/fail unpredictably (Bugbot 3552481065). Added a fail-fast ping check at startup and made the per-client flushall abort with a clear message if it fails, rather than testing against stale state. Verified a normal run (Redis up) is unaffected. Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion) The go FT.CREATE indexed only brand/model/description, omitting the price (NUMERIC) and condition (TAG) fields that the docs CLI and the jedis/python/C# examples define, so the go tab taught an incomplete index and numeric/tag queries against it would not behave like the tutorial (Bugbot 3552548341). Added the two fields. go's own steps only query @model/@brand/wildcard, so it still passes; the fix is for cross-client consistency and correctness. Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 903c0d0. Configure here.
…ero on FAIL Two Bugbot findings: - node search_quickstart's wildcard REMOVE-block assert checked result.documents[0].id == "bicycle:0", but FT.SEARCH "*" has no guaranteed order, so it failed on Redis 8.8 (3552632694). Changed it to assert result.total == 10, which is what the "retrieve all documents" step actually demonstrates and is order-independent. node search_quickstart now PASSES, closing the last known harness gap. (The identical line in query_single_term is a single @model:Jigger result, so its docs[0] check is fine and untouched.) - run.sh recorded FAIL in the summary but always exited 0, so it couldn't gate CI (3552632685). Added `exit 1` when any client FAILed (0 otherwise). Verified: a clean run exits 0. Learned: FT.SEARCH "*" ordering is unspecified — assert result counts/sets, never documents[0], for wildcard steps (this is the same fragility that keeps the docs wildcard opted-out) Ticket: DOC-6823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Note: the "Try it" button is intentionally disabled in the document database quickstart because the example was too long to pass to the interactive CLI. All other examples are thought to be CLI-friendly now.
What
Makes dependent sorted-set and string examples self-contained so the interactive "Try it" CLI can run them, and adds a harness that verifies every client tab.
Sorted sets (
data-types/sorted-sets.md)zrank— fully self-contained: CLI session + all client tabs recreate the post-deletion{Norem 10, Royce 10, Prickett 14}state;try_it="false"removed.zadd_lex— button-enabled without a recreate (cold-sandboxZADDreports 6 vs the documented 3 — accepted cosmetic diff; runs without error).SortedSetExamplenever existed upstream.Strings (
data-types/strings/_index.md)setnx_xx— self-contained via a single re-establishingSET bike:1 Deimos(noDELneeded;SETis unconditional-OK).try_it="false"removed. Adds the two Lettuce string overrides.Test harness (
build/example-test-harness/, dev-only tooling)local_examplessources against a throwaway Redis using each library's in-file assertions; prints a pass/fail matrix. Reusable for the rest of the backlog (onesrc_path()block per new set).Verification
Both example sets were run across all 11 clients (redis-cli + Python, Node, Go, Jedis, Lettuce async/reactive, C#, PHP, Ruby, Rust sync/async) against a live Redis — 22/22 pass with real assertions.
Follow-ups
redis/lettuceso their CI covers them.try_it="false"opt-outs (timeseries, hashes, sets, geospatial) follow thezranktemplate; the FT.SEARCH ones (document-database, geoindex) need a separate SORTBY/index-ready rewrite.🤖 Generated with Claude Code
Note
Low Risk
Changes are documentation, example sources, and optional build tooling; no production runtime or auth paths are modified.
Overview
Adds CI-oriented tooling for interactive docs:
build/check_tryit_payloads.pyscansclients-exampleblocks and fails when the redis.io/cli Try it URL would exceed the ~4094-byte request-line cap (includingneeds_prereqprepends), andbuild/example-test-harness/runslocal_examplesper language against a scratch Redis with in-file assertions.Docs make examples runnable without relying on earlier steps: many data-type pages drop
try_it="false"and prepend setup CLI (DEL/HSET/ZADD/etc.) so each block stands alone. Geospatial usesprereq/needs_prereqforGEOADD→GEOSEARCH. Geoindex merges multi-step flows into fewer blocks. Document database merges index creation andJSON.SETinto one prereq block, shortens two bicycle descriptions, keeps external Try it off (try_it="false") with an HTML comment explaining the URL limit, and marks query steps withneeds_prereq="true".Client examples gain matching setup in Python, Ruby, PHP, Rust, Go (timeseries), new geoindex and search_quickstart sources, and Lettuce async/reactive sorted-set/string examples aligned with the doc changes.
Reviewed by Cursor Bugbot for commit e815e44. Bugbot is set up for automated code reviews on this repo. Configure here.