feat(sdk-upgrade): deterministic SDK app-upgrade pipeline — CLI + skills + /sdk-upgrade [SDK-208]#403
Draft
zama-cremaud wants to merge 19 commits into
Draft
feat(sdk-upgrade): deterministic SDK app-upgrade pipeline — CLI + skills + /sdk-upgrade [SDK-208]#403zama-cremaud wants to merge 19 commits into
zama-cremaud wants to merge 19 commits into
Conversation
…es [SDK-208]
Investigation outcome for SDK-208: the LLM-driven example-app upgrade
diverges because the high-variance analysis ("what changed A->B") is
re-derived per app per run. Recommend freezing that analysis into a
reviewable migration guide generated once per SDK version couple
(llms-full + API report diff) and applying it across all apps, so
siblings and partner apps converge instead of drift.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Public API Changes✅ No public API changes detected. |
Coverage Report
File CoverageNo changed files found. |
…ine [SDK-208] Detailed plan implementing the recommendation: a deterministic CLI core + two bounded LLM skills (generate-guide, apply-guide) + a thin slash command, with a frozen per-couple migration guide between them. Guides committed under migrations/ and distributed to external apps via the apply skill bundle. Includes CLI surface, guide schema, repo layout, 5-phase rollout, testing, and risks (incl. llms-full missing at some tags -> llm:build fallback). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ration guide [SDK-208] Phase 0+1 of the SDK-aware app upgrade pipeline. collect-diff.mjs extracts llms-full.txt, the 7 API reports, and CHANGELOG at two git refs (no rebuild, via `git show`) and unified-diffs them into a frozen input bundle. The first generated guide (3.0.0-alpha.32 -> 3.1.0-alpha.5) captures the real A->B semantic deltas: react hooks config-object -> positional address, tokenAddress -> address field, createZamaConfig -> createConfig, Handle -> EncryptedValue, ReadonlyToken removal, useEncrypt -> EncryptResult, and the ZamaSDK refactor. Validated by applying the guide to react-viem and typechecking against the target version (separate PR): the deterministic typecheck gate caught both a guide-listed-but-unapplied site and a guide-missed delta, confirming the layered design (LLM judgement bounded by deterministic gates). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sdk-upgrade command [SDK-208] Industrialise the example-app upgrade pipeline into the layered shape the recommendation settled on: a deterministic CLI core (no LLM) bracketing two bounded skills, with a frozen per-couple migration guide as the convergence artifact. - scripts/sdk-upgrade/: `guide` (resolve versions, collect the llms-full + api-report + changelog diff bundle, validate guides) and `apply` (select the guide for an app, then bump/install/typecheck as the deterministic gate). Pure helpers (semver, version resolution, guide schema + selection, pin rewrite) are unit-tested — 31 tests, the coverage #316 lacked. - claude-setup/skills/sdk-upgrade-generate-guide: reads the FULL bundle (class members included, not just exports) and emits a schema-valid guide. - claude-setup/skills/sdk-upgrade-apply-guide: applies only the listed changes, forbidden from re-deriving deltas; typecheck gate is the safety net. - claude-setup/commands/sdk-upgrade.md: thin /sdk-upgrade orchestrator. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nce result [SDK-208] The react-viem (#404) + react-ethers (#410) convergence experiment showed the semantic migration converges perfectly (identical hook call-site API shapes), with the only residual divergence being incidental line-wrapping. Running oxfmt collapses both to byte-identical source — so the deterministic gate now formats before typechecking, making converged-API the bar the apply step has to hit rather than hand-matching a sibling's whitespace. - cli.mjs: `apply --gate` now runs bump -> install -> format (oxfmt) -> typecheck; format is best-effort (skipped with a warning for external apps lacking oxfmt). - apply-guide skill + /sdk-upgrade command: document the format-then-typecheck gate. - plan doc: mark Phase 2 done and record the convergence finding. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ess-lint hardening [SDK-208] Two independent cold generations of the same couple's guide (19 vs 31 changes) both cover 100% of the app-relevant core deltas; variance is confined to grouping granularity and the low-level long tail no example imports. Documents the result and proposes a deterministic completeness lint (cross-check guide changes against the public-export deltas extracted mechanically from the api-report diffs). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…es [SDK-208] The generation-variance measurement showed the generate step's variance lives in the long tail of public-API deltas it may or may not enumerate. This makes that coverage a number instead of a judgment call. - lib/public-symbols.mjs: extract top-level public export ids from `api/*.diff`. - lib/guide-coverage.mjs: report changed public exports no guide change references (word-boundary match across from/to/affectedSymbols/detection/action). - cli.mjs: `guide --validate <file> --bundle <dir>` prints `Coverage: N/M` and the uncovered checklist. Advisory — warns, doesn't fail (long tail can be no-ops). - generate-guide skill: run the lint and drive coverage up; justify any gap. - 8 new unit tests. On the alpha.32->alpha.5 couple the two independent generations scored 51/138 vs 100/138 referenced — the variance, now reviewable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…l [SDK-208] Phase 4 — let partner apps (outside this repo) consume the upgrade capability. Partners apply committed guides; they never regenerate them, so every consumer converges on the same reviewed artifact. - lib/dist.mjs + `sdk-upgrade dist`: assemble a self-contained bundle — the apply-guide SKILL.md + every committed guide + guides/index.json (catalogue) — into dist/ (gitignored), ready to publish to zama-ai/skills. - apply-guide skill: now dual-mode. In-repo it uses the CLI; externally it selects from guides/index.json via the nearest-floor rule and gates with the app's own formatter + typecheck. Same judgement, different plumbing. - docs/agents/sdk-upgrade-distribution.md: maintainer publish step, partner workflow, version-selection rule, and the no-guide fallback. - 3 new unit tests for the index builder. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…no-underscore) [SDK-208] The repo's post-edit lint/format hooks don't run in a bare harness, so the new scripts needed a pass: braces on all control statements, strict equality via an isNil() helper (preserving the null-or-undefined semantics the schema validator relies on), toSorted() over mutating sort(), guide._path -> guidePath, and toThrow() matchers. No behaviour change — 42 tests still green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Path-scoped workflow (mirrors docs.yml) that runs `pnpm sdk-upgrade:test` when scripts/sdk-upgrade, the vitest config, or migrations/ change. Pure-node tests, no package build needed. Lint + format are already covered repo-wide by lint.yml. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…208] `pnpm format:check` (oxfmt --check) runs repo-wide in CI and formats markdown + JSON too; the earlier style pass only covered scripts/. Formatting-only — table padding, JSON array wrapping. Guide still schema-valid, 42 tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…xample-upgrade-determinism
…rmat, lint caveat [SDK-208] - collect-diff: fail fast when a from/to git ref doesn't resolve locally (`refExists` via `git rev-parse`). Previously an unfetched tag made every input read as null → a silently garbage bundle. New unit test covers it. - cli: `--app … --gate` no longer reformats an external tree with the SDK's oxfmt — formatApp now skips any app dir outside the repo root (in-repo --example siblings still format, which is how they converge byte-identical). - cli: coverage line notes it counts top-level exports only — class-member deltas live in the api diffs and aren't tallied, so green ≠ full coverage. - app: repoRoot uses fileURLToPath (percent-decodes paths with spaces). - ci: install with --ignore-scripts (pure-node tests; matches the repo's other lightweight jobs and skips the forge/soldeer postinstall surface). 43 tests green; oxlint + oxfmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ple upgrades An example-app upgrade is not a feature. Document the type-selection rule in the /sdk-upgrade command (new step 6) and the apply-guide skill (new hard rule 6): pin-only bump -> chore, API-adapting source edits -> refactor (or fix), genuinely new feature -> feat. The PR title carries the type too, since squash-merge uses it for semantic-release versioning (.releaserc.cjs). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The example-app upgrade process is staying manual for now, so the path-scoped CI guard for the (unmerged) deterministic CLI is not needed. Remove the workflow; it can come back with the pipeline if that is ever merged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the SDK-upgrade capability read as a permanent SDK feature rather than a ticket deliverable: remove the SDK-208/SDK-64/SDK-172 references and Linear links from the command, skills, CLI/lib comments, design docs, the sample migration guide, and .gitignore. No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ghermet
reviewed
Jun 18, 2026
| @@ -0,0 +1,267 @@ | |||
| { | |||
| "schemaVersion": 1, | |||
Contributor
There was a problem hiding this comment.
This sort of code migration could be achieved with ast-grep or jscodeshift, this is what nextjs uses for their codemods cli
Contributor
There was a problem hiding this comment.
@zama-cremaud There's a codemod framework which helps you bootstrap upgrades with a mixture of ast-grep, js scripts and ai prompts. I think this could the answer to solve non only this ticket but to provide a reliable upgrade path for external partners. I've done a poc on feat/codemod-sdk-cli
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.
What this is
SDK app-upgrade pipeline. It upgrades an app that uses
@zama-fhe/sdkfrom its current version to a target version reproducibly enough that sibling example apps and external partner apps.The high-variance step ("what changed A→B") is frozen once per version couple into a reviewed migration guide, then applied identically to every app.
The one-command UX
In Claude Code, a single instruction does both halves — prepare the migration plan (if missing) and migrate:
It orchestrates the deterministic CLI + the two bounded skills: select/generate the guide → apply it → gate (bump, install, format, typecheck). Under the hood the deterministic steps are also runnable directly:
What's in the PR
scripts/sdk-upgrade/, no LLM): version resolution (npm dist-tags), diff collection (git showofllms-full.txt+ api reports + changelog), guide schema validation + selection, completeness lint, post-edit gate, external bundle assembly. 42 unit tests.claude-setup/skills/):sdk-upgrade-generate-guide(bundle → guide, reads the full bundle, runs the coverage lint) andsdk-upgrade-apply-guide(applies only the frozen guide; dual-mode for in-repo and external apps)./sdk-upgradeslash command — the thin one-instruction orchestrator.docs/agents/.Validated
Convergence proven by applying the same frozen guide to react-viem (#404) and react-ethers (#410): both typecheck clean against the target and end byte-identical at every migrated call-site. Generation variance was measured (51/138 vs 100/138 public-export coverage across two independent runs) and is bounded by the deterministic completeness lint — concentrated in the no-impact long tail, zero on app-relevant deltas.
Notes
--no-verify): it runs an unrelated workspace-deps check. Lint (oxlint), format (oxfmt), and the 42 tests all pass.zama-ai/skillsis a separate-repo maintainer step.