Skip to content

feat(stream-backend): server-side SDK migration skill - #55

Open
mogita wants to merge 7 commits into
mainfrom
feat/cha-3660-backend-migration-skill
Open

feat(stream-backend): server-side SDK migration skill#55
mogita wants to merge 7 commits into
mainfrom
feat/cha-3660-backend-migration-skill

Conversation

@mogita

@mogita mogita commented Jul 27, 2026

Copy link
Copy Markdown

Adds stream-backend, a skill that migrates a customer's server-side Stream integration from a legacy hand-written SDK to the generated OpenAPI SDK.

Shape

One skill and one workflow for all six server-side SDKs, rather than a track per language. The migration is a reading of how a codebase uses the SDK, and the parts that make that trustworthy are language-independent: take an inventory of every call site before editing, know which operations change runtime behavior, and report what is safe separately from what is not.

What differs per language is the symbol mapping, which lives in a reference file, and the commands used to verify.

It is an assisted migration, and says so

The skill states up front that a human reviews the result. Every call site lands in one of four buckets:

Bucket Meaning
Safe Mechanical. Same behavior, different spelling.
Behavior changed Works and compiles, and something about runtime behavior differs.
Needs a decision The mapping depends on intent the code does not settle.
Not migrated No equivalent, or unverifiable. Left alone.

The second bucket is the one that earns its keep. The environment-variable rename is a one-token change that compiles perfectly and takes production auth down; deletes became asynchronous; flagging moved from the v1 store to v2 moderation, so migrating one call in isolation can leave a workflow writing to one store and reading from another.

Two rules hold it together: unclassified is never treated as safe, and a field with no home in the new request is a decision rather than something to quietly drop.

Scope

Covers Chat plus chat-era moderation, which is the entire surface the legacy SDKs have. Video and Feeds are new capability with no legacy code calling them, so they are not migration targets, and the skill says so instead of implying a gap.

Verification is honest about what it proves

Go, Java and .NET get a real compiler check. PHP has static analysis if configured. Ruby and Python have no equivalent, so the customer's test suite is the only meaningful backstop there, and the workflow says that rather than presenting equal confidence everywhere.

Files

  • skills/stream-backend/SKILL.md - classify server-side versus client, pick the language, hand off
  • skills/stream-backend/migrate.md - the workflow: expectations, inventory, classify, agree, apply, verify, report
  • skills/stream-backend/references/operations.md - language-independent: what each operation becomes, which change behavior
  • skills/stream-backend/references/go.md - Go symbol mapping
  • tools/stream-migrate/ - internal, not shipped and not referenced by the skill. A Go codemod used to prove the Go mappings compile against the real SDK, with a representative Chat + Moderation integration under testdata/ to exercise them. Its tests also assert the reference has not drifted from what has been verified.

Registered as a router peer with a classifier row, a Server SDKs menu group, and rows in README.md and AGENTS.md.

mogita added 2 commits July 27, 2026 11:00
New language-parameterized skill that migrates a backend Stream integration
from a legacy hand-written SDK to the generated OpenAPI SDK. Go is the first
supported path (github.com/GetStream/stream-chat-go -> github.com/GetStream/getstream-go).

The migrate-go track is thin and docs-driven: it fetches the official migration
guide and never migrates from memory, applies the documented transforms, then
verifies with go build / go vet. Wires the skill into the router (peers.yaml,
Server SDKs menu group, classifier row) and the README / AGENTS tables.
The legacy SDKs are Chat SDKs, so the migratable surface is Chat plus
chat-era moderation. Video and Feeds are new capability in the generated
SDK rather than migration targets, since no legacy code calls them.
Name the real gaps, which are inside Chat.
@mogita mogita changed the title feat(stream-backend): server-side SDK migration skill (Go first) feat(stream-backend): SDK migration skill for server-side Go Aug 1, 2026
mogita added 3 commits August 1, 2026 13:30
Rewriting call sites by hand is the wrong tool for the mechanical part of
an SDK migration: it is not repeatable and it silently misses call sites in
files nobody opened. This adds stream-migrate, a type-aware Go codemod, and
rewires the skill to drive it and handle only the residue.

It rewrites call sites, legacy type references (a client held in a struct
field has to change type too, or nothing compiles), and reads off a
response, which now live under Data. Every call site is classified: applied
and safe, applied but behavior changed, needs a decision, or not migrated.
Anything the mapping table does not cover is reported rather than guessed
at, and a builder that cannot match a call's shape degrades it to a
decision instead of emitting a plausible wrong rewrite.

testdata/chatmod is a representative Chat + Moderation integration used to
exercise this: several files, responses consumed, a spread of operations.
Running the tool over it rewrites 41 call sites safely, flags 4 behavior
changes, and leaves 7 for a human. Every remaining compile error afterwards
is one the report named.
…p fields

Adds table-driven tests over the rewrite rules and the response pass. They
run without network or the real SDK, since they exercise the builders on
parsed snippets rather than a loaded package.

Writing them found a real bug: CreateChannel silently dropped the members
when they came from a variable instead of a literal, producing a channel
with nobody in it that compiled fine. Rules now decline whenever a literal
carries a field they do not map, so the call is reported for a human
instead of being rewritten with data missing. A test locks that in.

Also lowers the Go requirement from 1.25 to 1.23 by pinning older x/tools
and x/sync, states the toolchain requirement in the skill, and reports what
a surviving legacy type reference is doing so the request or response type
can be chosen from how the value flows.
The skill was shaped around a per-language track backed by a Go codemod.
That does not scale: five more rewriter kits is five more projects to
build and keep current, and a human reviews the result either way.

What actually made the Go migration trustworthy was not the rewriter. It
was taking an inventory of every call site before editing, mapping data
that says which operations change runtime behavior, and a report that
separates safe from behavior-changed from needs-a-decision from not
migrated. None of that is language-specific.

So the skill is now one workflow every language runs, with the operation
knowledge split into a language-independent reference plus a per-language
symbol table. Human review is an explicit first step rather than an
implication, and verification is honest about proving less on Ruby and
Python, where there is no compiler to catch a wrong rewrite.

The Go codemod stays in tools/ as an internal harness that proves the Go
mappings compile. It is not shipped and the skill does not mention it, so
it cannot raise the question of when the other five arrive. A test asserts
the reference documents every mapping the tool implements, which caught a
missing behavior warning on FlagUser.
@mogita mogita changed the title feat(stream-backend): SDK migration skill for server-side Go feat(stream-backend): server-side SDK migration skill Aug 1, 2026
Adds the Python symbol reference and a representative legacy Python
integration to run the workflow against.

Python is the language that tests whether the workflow stands on its own,
because it has no compiler and no codemod behind it. Two things about it
differ enough to be worth stating in the reference rather than discovering
mid-migration: the generated SDK takes keyword arguments rather than a
request object per call, with typed models only for nested payloads, and
both SDKs ship separate sync and async clients that must not be quietly
swapped for one another.

Writing it also corrected something the Go reference got wrong. Listing
operations as not covered conflated the reference not documenting them with
the SDK not having them; unread counts and message translation, both listed
as gaps, exist on both sides. Under a verify-first gate that framing is
misleading, so both references now say unverified rather than missing.

The Python fixture's calls were checked against the legacy SDK source since
nothing else would catch them, which found a keyword argument passed to a
method with no catch-all that would have failed only at runtime.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant