Skip to content

Add Sage (Scala) to community-supported clients - #3681

Merged
andy-stark-redis merged 1 commit into
redis:mainfrom
ghostdogpr:add-sage-scala-client
Aug 14, 2026
Merged

Add Sage (Scala) to community-supported clients#3681
andy-stark-redis merged 1 commit into
redis:mainfrom
ghostdogpr:add-sage-scala-client

Conversation

@ghostdogpr

@ghostdogpr ghostdogpr commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Adds Sage to the community-supported clients table. Scala currently has no client listed on the page, so this fills a language gap.

Sage is an actively maintained, Apache-2.0 Redis & Valkey client for Scala 3. It implements RESP3 natively (no wrapped Java client) and supports Redis 8+, cluster, transactions, sharded pub/sub, client-side caching, replica reads, and TLS.

Docs: https://ghostdogpr.github.io/sage/


Note

Low Risk
Documentation-only table row addition with no runtime or API impact.

Overview
Adds Sage as a community-supported Redis client for Scala on the Connect with Redis client API libraries page (content/develop/clients/_index.md).

The new row in the third-party clients table links to the ghostdogpr/sage GitHub repo and Sage docs, giving Scala a listing alongside other community clients. No other sections (official clients table, decision tree, language guides) are changed.

Reviewed by Cursor Bugbot for commit e2e2908. Bugbot is set up for automated code reviews on this repo. Configure here.

@CLAassistant

CLAassistant commented Jul 21, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ghostdogpr ghostdogpr changed the title Add Sage (Scala 3) to community-supported clients Add Sage (Scala) to community-supported clients Jul 21, 2026
@andy-stark-redis

Copy link
Copy Markdown
Contributor

Thanks for the suggestion, @ghostdogpr — and sorry for the wait on this one.

We've started running community client-library suggestions through a fixed checklist (maintenance, adoption, engineering quality, Redis feature coverage, documentation) so these decisions are consistent and we can explain them. Sage comes out well, and I'm recommending it for inclusion.

What stood out while we were verifying:

  • Redis feature coverage is complete for what we look for — RESP3, cluster with MOVED/ASK and cross-slot handling, TLS including mutual TLS, ACL auth, sharded pub/sub, and auto-pipelining — plus client-side caching, JSON, streams and functions.
  • The version compatibility statement is explicit and CI-backed. "Redis 8+ and Valkey 8+" in the README, the more precise RESP3/6.0+ detail in the FAQ, and integration tests that actually run against redis:8.8.0, valkey:9.1.0 and redis:6.2.
  • The test and release setup is stronger than most suggestions we see — an integration matrix across all five backends against real servers via testcontainers, cluster-failover and TLS/auth suites, tags mapping 1:1 to signed Maven Central releases, and substantive release notes each time.
  • The docs site is hand-written, not just generated Scaladoc — separate guides for configuration, pipelines/transactions, pub/sub, streams, client-side caching, observability and error handling.

Two notes, neither blocking:

  1. The project is young (first release June 2026) with essentially one active committer, so the parts of our checklist that measure track record and adoption are the only places it scored below full marks. That's a function of age rather than anything we found wrong, but it does mean we'll re-check the entry periodically, as we do for the rest of the community table.
  2. If you know of projects using Sage in production that you're able to name, that's genuinely useful evidence for us — Maven Central publishes no download figures and GitHub's dependents graph doesn't read build.sbt, so there's no signal we can measure for a Scala library.

One small suggestion for the project itself, take it or leave it: the getting-started guide is excellent, but the README has no inline install-and-connect snippet. A five-line "add this dependency, connect, set/get" block at the top would help people sizing Sage up straight from GitHub.

The table row itself is correctly formed and in the right alphabetical position, and the docs link points at the rendered site, which is what we want. I'll get this in front of the rest of the docs team and merge from our side.

andy-stark-redis added a commit that referenced this pull request Aug 14, 2026
First real run of the checklist (Sage/Scala, PR #3681) found three ways the
evidence-gathering step produces a confidently wrong score, and left the
question of where a scorecard should be stored unanswered. Both fixed here.

The traps, each verified rather than assumed:

- search.maven.org's solr index returned 0 hits for com.github.ghostdogpr:
  sage-core_3 while all seven published versions sat in the artifact store.
  A naive C2 check reads that as "not on the official registry" - an outright
  Fail on a project with clean release hygiene. repo1.maven.org's
  maven-metadata.xml is the authoritative store and it agreed with the tags
  1:1.
- GitHub's dependents graph doesn't parse build.sbt, so it reports 0 for any
  sbt project. Scored B2 Fail on the absence of positive evidence instead, and
  said which instrument was blind - the zero itself proves nothing.
- mvnrepository.com does expose a "Used By" count, and returns HTTP 403 to
  scripted requests. Checked before writing it in as a pointer; it would have
  been a source no re-run could reproduce.

Generalised into one rule at the top of the gathering step: a single index
returning zero is not evidence of absence, so confirm against the
authoritative store before any Fail that rests on a missing reading.

Also recorded that Maven Central and pkg.go.dev publish no download figures at
all, so B1 is unscoreable on the JVM and in Go and must be capped at Warn with
the gap named - otherwise every JVM client silently reads as poor uptake. Go
keeps B2 through pkg.go.dev's "Imported by" (verified: 17,374 for go-redis);
the JVM has no scriptable equivalent.

New section 6 settles storage. Not a file in this repo: readers expect a
checked-in file to be current and half a scorecard's facts are false within
months. On an accept it goes in the squash body of the commit that adds the
table row, because that commit touches the one line being justified - blame the
row, get the evidence. Trailers (Vetted:/Gaps:/Recheck:) keep the set
enumerable, since commit messages are otherwise unqueryable as a set. Declines
have no commit at all, so they live in the PR thread; the asymmetry is
deliberate.

Learned: the checklist's failure mode is not misjudging a project, it is
trusting one lookup - two of the three traps would have scored a criterion Fail
on a project that passes it.

Constraint: cap B1 at Warn on the JVM and in Go rather than scoring it down; no
download figure exists to apply a threshold to.
Constraint: under COMMIT_MESSAGES the squash body defaults to the contributor's
WIP commits, so an accept must merge with --body-file or the scorecard is lost.
Rejected: mvnrepository.com "Used By" for JVM dependents | HTTP 403 to scripted
requests, so a re-run can't reproduce it
Directive: keep non-criteria observations out of the scorecard and out of any
public reply - they carry no score and read as a judgement on the author.
Ticket: DOC-6973

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@andy-stark-redis andy-stark-redis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - thanks for your contribution @ghostdogpr !

@andy-stark-redis
andy-stark-redis merged commit ddb6789 into redis:main Aug 14, 2026
3 checks passed
@ghostdogpr

Copy link
Copy Markdown
Contributor Author

@andy-stark-redis thanks for the inclusion! Indeed it's a new library without many adopters yet. In fact, we recently migrated to it at my company (Devsisters, a mobile game company) and it went to production earlier this week, Sage is now serving tens of thousands of requests per second!

andy-stark-redis added a commit that referenced this pull request Aug 14, 2026
Fifth Bugbot round, and the first one that invalidates a score already
published rather than one that might mislead a future run.

Three parts of this file, written across three commits, instructed differently
for the same case. The traps section says a GitHub dependents zero for an sbt
project is no-signal and "not a Fail on its own". The scoring preamble says
missing evidence is "Warn at best". B2's Fail band, made explicit two commits
ago, says "0 dependents and none named". For a JVM client with no named
adopter, those produce Warn or Fail depending on which line the reader reaches
first - and B2 offered no band at all for an instrument that cannot measure.

Fixed as a precedence rule rather than a patch to B2, because the collision can
recur in any criterion: a Fail now requires positive evidence of the deficiency
from an instrument known to work for that ecosystem, and the rule explicitly
overrides any band whose wording would Fail on a missing or unmeasurable
reading. B2's bands now name the unmeasurable case in Warn and require a
working instrument for Fail.

Swept every other Fail band for the same hazard. B2 was the only one that could
fire on unmeasurability: A1/A3 rest on commit dates, A2 on releases from either
tags or a registry publish, C1 on the repo tree, C3 on the license and the
advisories API, D and E on documents - all obtainable. C2's "not on the
official registry" is the near miss, and the Maven index trap plus this rule
now cover it: a failed lookup is Warn, a confirmed absence from the
authoritative store is Fail.

Consequence for the record, stated rather than buried: Sage was scored B2 Fail
(0) in ddb6789 on reasoning this rule now forbids - no named adopters is
absence of a claim, and the only instrument available was blind to sbt. Under
the corrected checklist that criterion is Warn (1) and the total is 22/26 not
21/26. The verdict is unchanged at Recommend include, so the merged table row
stands, but a re-vet diffing against that scorecard will find a number the
current rules would not produce.

Learned: the fifth defect was not in a band, it was between three sections that
were each correct alone. Every earlier round hardened one row; this one shows
the checklist also needs reading as a whole, because a rule stated in the
preamble, an exception stated in the traps, and a band stated in a table can
each be right and still contradict. Reading order decided the outcome, and I
had already been warned about that by the second finding in this same file.

Constraint: in a scoring rubric, a Fail must rest on positive evidence of the
deficiency from an instrument known to work; an unmeasurable or missing reading
is a Warn with the blindness named. Absence of a claim is not evidence of
absence.
Constraint: where a cross-cutting rule and a per-row band can both apply, state
which wins. Two locally correct statements in different sections are a
contradiction the reader resolves by reading order.
Gaps: the Sage scorecard in ddb6789 records 21/26 with B2 Fail; the corrected
rules give 22/26 with B2 Warn, same verdict. Not amendable in place - the squash
commit is immutable - so a correction note on PR #3681 is the only reachable
fix.
Ticket: DOC-6973

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@andy-stark-redis

Copy link
Copy Markdown
Contributor

Correction to the scorecard in this PR's squash commit (ddb6789), recorded here because a commit message cannot be amended after the fact.

The checklist Sage was scored against has since been revised (#3814). One change affects this review: a Fail now requires positive evidence of the deficiency from an instrument that actually works for the ecosystem, and a missing or unmeasurable reading is a Warn with the blind instrument named. Sage's B2 (downstream usage) was scored Fail on the reasoning that no named adopters plus a zero from GitHub's dependents graph amounted to absence — but that graph cannot parse build.sbt, so it reports zero for any sbt project, and absence of a claim is not evidence of absence of usage.

Re-scored against the final checklist, B2 is Warn and the total is 22/26 rather than 21/26. The verdict is unchanged — Recommend include — so nothing about the decision or the table row changes. Every other criterion scores the same as it did on 2026-08-14.

Recording it so that a future re-check diffing against the original scorecard sees a number the current rules would actually produce.

andy-stark-redis added a commit that referenced this pull request Aug 14, 2026
Adds a `/vet-redis-client` skill: 13 criteria scored Pass/Warn/Fail out of 26,
thresholds for include / needs-discussion / decline, and three hard stops
(archived repo, no OSI license, open unpatched advisory) that override the
total. Only verifiable repo and registry facts count — reviews, blog posts,
project-published benchmarks and social popularity are excluded, because those
are the signals an author can manufacture and they are what makes a decline
hard to defend. Every score must cite a URL and the concrete fact, so a
reviewer can re-check it later.

The ticket asked for this to run as a label-triggered GitHub Action. That was
considered and rejected: suggestions arrive fewer than ten times a year, and at
that volume a model in CI buys little against an API-key secret, a cost line,
prompt-injection surface (the job would fetch a submitter-controlled README
with a token that can write) and score variance that defeats the point of a
fixed checklist. The skill is run by hand. The branch name predates that
decision.

The bulk of this PR is not the checklist but its arithmetic. Fourteen Bugbot
findings, all fixed, and every one was in the scoring logic rather than the
prose: bands that claimed a boundary value twice, bands that left a plausible
project matching nothing, a criterion disqualifying on a signal it did not
measure, and three sections that were each correct alone while instructing
differently for the same case. Three of the findings were caused by the
immediately preceding fix, because appending an "or" clause to a band is
locally correct and globally corrosive — a band's meaning is its boundaries
with the other two, so editing one silently edits two relationships. The
durable lesson is that a rubric emitting a score is code: its rows are a
partition, and reading them as English is what let all fourteen through.

Ecosystem gaps are recorded in the file because they each produce a wrong score
if trusted: Maven Central's search index lags behind the artifact store,
GitHub's dependents graph cannot parse build.sbt and so reports zero for any
sbt project, mvnrepository.com returns 403 to scripted requests, and neither
Maven Central nor pkg.go.dev publishes download figures at all.

First real use was Sage (Scala), merged in #3681 with its scorecard in the
squash commit body per the convention this skill introduces.

Learned: every defect here was in the scoring arithmetic, not the prose, and the technique that finds them is auditing each row as a partition then sweeping the rows next to it.
Constraint: a scoring rubric's bands must be mutually exclusive and exhaustive, qualitative rows included; where more than one still applies score the lowest, and mirror any alternative Pass route with explicit exclusions in every lower band or the tie-break kills that route.
Constraint: a Fail requires positive evidence of the deficiency from an instrument that works for that ecosystem; a missing or unmeasurable reading is Warn with the blind instrument named, since absence of a claim is not evidence of absence.
Constraint: adding a cross-cutting rule to a rubric means re-auditing every row against it in the same commit, or the unswept rows come back as the next round of findings.
Directive: record an accept in the squash body of the commit that adds the table row, with Vetted:/Gaps:/Recheck: trailers, forced via `gh pr merge --body-file` because this repo's COMMIT_MESSAGES setting otherwise discards it; declines have no commit and live in the PR thread.
Rejected: label-triggered GitHub Action running the checklist in CI | fewer than ten suggestions a year against a secret to provision, prompt-injection surface on submitter-controlled READMEs, and score variance
Gaps: the Sage scorecard in ddb6789 records 21/26 with B2 Fail; the final rules give 22/26 with B2 Warn and the same verdict, corrected in a note on #3681.
Recheck: nothing enforces the community table's freshness — the Sage entry's 6-month recheck is a trailer with no job behind it, and a cron over the mechanical criteria is the automation actually worth building.
Ticket: DOC-6973
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
EliShteinman added a commit to EliShteinman/docs that referenced this pull request Aug 17, 2026
Adds Sage (Scala) to the community-supported clients table; vetted 21/26 against the docs team's client checklist, recommend-include with no hard stop.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clients Client library docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants