Repository navigation
Conversation
Adds a fully-generated Ruby control-plane client to the contract-driven SDK fleet, taking it from 7 to 8 languages. Generated from the single OpenAPI spec by the pinned openapi-generator v7.11.0, committed in-repo, and enforced by the existing zero-drift + parity gates. - sdks/config/ruby.yaml: faraday library, gem `beater_client`, module `BeaterClient`, hideGenerationTimestamp for deterministic output. - sdks/clients/ruby: committed generated client. - sdks/conformance/ruby: live conformance program (health + createDataset + listTraces round-trip) modeled on the Python harness; wired into e2e-clients-live.sh and surface-manifest.json. - Drift/parity gates moved 7 -> 8: regen-sdks.sh LANGS, check-sdk-parity EXPECTED_GENERATED, check-contract-sync + self-test, feature-matrix checker, sdk-contract workflow step names, and the canonical docs. Also adds an opt-in local-JAR backend to regen-sdks.sh (BEATER_OPENAPI_GENERATOR_JAR): the generator runs via a local JVM instead of the Docker image, producing byte-identical output (verified against the existing clients). Docker stays the default so CI is unchanged; this only removes the hard Docker-Hub dependency for environments where the registry is unreachable. Verified: scripts/check-contract-sync.sh (8 SDKs, zero drift), check-sdk-parity-contract.py, check-feature-matrix-contract.py, and the contract-sync self-test all pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsWPsZsDkwGnhGTCZhMkep
Adds a fully-generated PHP control-plane client, taking the contract-driven fleet from 8 to 9 languages. Generated from the single OpenAPI spec by the pinned openapi-generator v7.11.0, committed in-repo, and enforced by the existing zero-drift + parity gates. - sdks/config/php.yaml: invokerPackage Beater\Client, composerPackageName beater/client, hideGenerationTimestamp for deterministic output. - sdks/clients/php: committed generated client (composer package beater/client). - sdks/conformance/php: live conformance program (health + createDataset + listTraces round-trip) via a Composer path repository; wired into e2e-clients-live.sh and surface-manifest.json. Test-time vendor/ and composer.lock are gitignored. - Drift/parity gates moved 8 -> 9: regen-sdks.sh LANGS, check-sdk-parity EXPECTED_GENERATED, check-contract-sync + self-test, feature-matrix checker, sdk-contract workflow step names, and the canonical docs. Verified: scripts/check-contract-sync.sh (9 SDKs, zero drift), parity + feature-matrix + self-test gates, and a live PHP conformance round-trip against beaterd (health ok, createDataset -> Dataset, traces.list -> PageRunSummary). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsWPsZsDkwGnhGTCZhMkep
Adds a fully-generated C#/.NET control-plane client, taking the contract-driven fleet from 9 to 10 languages. Generated from the single OpenAPI spec by the pinned openapi-generator v7.11.0 (`csharp` client generator, httpclient library, net8.0), committed in-repo, and enforced by the zero-drift + parity gates. - sdks/config/csharp.yaml: packageName Beater.Client, targetFramework net8.0, library httpclient. packageGuid is pinned and hideGenerationTimestamp is set so the generated .sln/.csproj is deterministic (verified: two regenerations are byte-identical). - sdks/clients/csharp: committed generated client (ships the standard VS .gitignore for bin/obj). - sdks/conformance/csharp: live conformance program (health + createDataset + listTraces round-trip) that project-references the generated client; wired into e2e-clients-live.sh (SKIPs cleanly where the .NET toolchain is absent) and surface-manifest.json. - Drift/parity gates moved 9 -> 10: regen-sdks.sh LANGS, check-sdk-parity EXPECTED_GENERATED, check-contract-sync + self-test, feature-matrix checker, sdk-contract workflow step names, and the canonical docs. Verified: scripts/check-contract-sync.sh (10 SDKs, zero drift), parity + feature-matrix + self-test gates. Live conformance runs in CI where the .NET SDK is present. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsWPsZsDkwGnhGTCZhMkep
Completes the common-language fleet at 11 generated clients. Generated from the single OpenAPI spec by the pinned openapi-generator v7.11.0 (`kotlin` generator, jvm-okhttp4 + moshi), committed in-repo, and enforced by the zero-drift + parity gates. - sdks/config/kotlin.yaml: groupId ai.beater, artifactId beater-client-kotlin, package ai.beater.client.kotlin, hideGenerationTimestamp for determinism. - sdks/clients/kotlin: committed generated client. - sdks/conformance/kotlin: live conformance program via a Gradle composite build that includeBuilds the generated client; adds okhttp to the consumer classpath (the client's API constructors expose okhttp3.Call.Factory in a default parameter). Wired into e2e-clients-live.sh and surface-manifest.json. - Drift/parity gates moved 10 -> 11: regen-sdks.sh LANGS, check-sdk-parity EXPECTED_GENERATED, check-contract-sync + self-test, feature-matrix checker, sdk-contract workflow step names, and the docs (ARCHITECTURE.md reconciled to 11 throughout). Verified: scripts/check-contract-sync.sh (11 SDKs, zero drift), parity + feature-matrix + self-test gates, and a live Kotlin conformance round-trip against beaterd (health ok, createDataset -> Dataset, traces.list -> PageRunSummary). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsWPsZsDkwGnhGTCZhMkep
Extends the tag-triggered release pipeline to publish all 11 generated clients. The four new languages plug into the existing "wired now, secret-gated" pattern: each target no-ops with a clear SKIP message until its registry token is added as a repo secret. - scripts/publish-sdk.sh: new ruby (gem build + gem push), php (Packagist is git-tag driven, with an optional update-hook ping), csharp (dotnet pack + nuget push), and kotlin (gradle publish to OSSRH, same creds as Java) arms. Generated-only clients are versioned at generation time, so no extra stamping is needed. - scripts/regen-sdks.sh: add gemVersion to the release version properties so a tagged release actually stamps the Ruby gem version (verified: gemVersion=0.2.0 -> lib/beater_client/version.rb VERSION = '0.2.0'). - .github/workflows/release.yml: extend the publish matrix to ruby/php/csharp/ kotlin and pass the new secrets (RUBYGEMS_API_KEY, NUGET_API_KEY, PACKAGIST_USERNAME, PACKAGIST_API_TOKEN; Kotlin reuses OSSRH_*). - sdks/README.md: document the language -> registry -> secret mapping. Verified: bash -n on both scripts, release.yml parses as YAML, publish-sdk.sh --validate-version, and each new arm prints its SKIP/tag note when run without secrets. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsWPsZsDkwGnhGTCZhMkep
The Kotlin conformance runs sdks/clients/kotlin as a Gradle composite included build, which writes a .gradle/ cache into that directory. Six cache files were accidentally committed with the Kotlin client; because regen-sdks.sh wipes and regenerates sdks/clients/kotlin (which never contains a .gradle cache), the committed cache made `regen-sdks.sh --check` report drift. Remove the tracked cache and add `sdks/**/.gradle/` to .gitignore (alongside the existing `sdks/**/build/`) so it cannot be re-committed. Verified: scripts/regen-sdks.sh --check now reports zero drift across all 11 clients. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsWPsZsDkwGnhGTCZhMkep
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…sion guard, consumer docs Applies the findings from the multi-agent review of the 7→11 SDK fleet, in one pass. Publishing (blocker + hardening): - Kotlin `gradle publish` was a silent no-op: the generated build.gradle only applies `maven-publish` with no publication/repository/signing, so it uploaded nothing yet reported success. Add `sdks/config/maven-central.init.gradle` (kept out of the regenerated client tree so it can't drift) that wires a real MavenPublication + OSSRH repository + in-memory GPG signing at publish time. Verified: `gradle --init-script … tasks` now registers `publishMavenJavaPublicationToOSSRHRepository`. The kotlin arm invokes the client's pinned wrapper and gates on OSSRH_USERNAME + OSSRH_PASSWORD + SIGNING_KEY, skipping cleanly (no false success) when any is absent. - Gate the java and kotlin arms on OSSRH_PASSWORD (not just OSSRH_USERNAME). - release.yml passes SIGNING_KEY, SIGNING_PASSWORD, OSSRH_URL. Generation: - regen-sdks.sh now asserts the local generator JAR is exactly v7.11.0 (BEATER_OPENAPI_GENERATOR_JAR) — a mismatched generator would silently emit divergent clients and break the zero-drift guarantee. Repo hygiene: - .gitignore: ignore sdks/**/bin/ and sdks/**/obj/ (the C# conformance leaves .NET build output under sdks/clients/csharp when it builds via ProjectReference). Docs — client-friendly + accuracy: - sdks/README.md: add a "Quickstart (for consumers)" section — per-language install command, import/namespace, and a link to each generated client's own README, plus a host+auth snippet and a note that clients default to http://localhost (spec is pre-1.0, no servers block). - Fix stale "7 SDKs" counts the review caught: ARCHITECTURE.md, docs/sdk-platform-architecture.md, docs/architecture-status.md, GOVERNANCE.md, SECURITY.md, and .github/PULL_REQUEST_TEMPLATE.md → 11. Verified: check-contract-sync.sh (11 SDKs, zero drift), parity, feature-matrix, contract-sync self-test, docs-walkthrough, and the Kotlin publish-task registration all pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsWPsZsDkwGnhGTCZhMkep
…taging, .NET 8 pin Addresses the follow-up (round 2) review of commit 076e40c. Docs correctness: - sdks/README.md quickstart: the Python snippet set cfg.api_key["ApiKeyAuth"], but the spec declares no securitySchemes, so the generated clients never send an auth header — the line was misleading. Remove it and add an explicit note that auth is not modeled in the contract yet (adding servers + securitySchemes in crates/beater-api is the follow-up that makes it work across all 11 clients). Publishing honesty (Maven Central path): - Drop the baked-in default OSSRH_URL (the legacy s01.oss.sonatype.org host is sunset); OSSRH_URL is now required and the kotlin arm skips cleanly without it. - Document in the init script + README that `publish` uploads SIGNED artifacts to a STAGING repo — a release still needs a close+release / Central Portal promotion, so a green release means "staged", not necessarily "live on Central". - release.yml: pin .NET 8 via actions/setup-dotnet@v4 (first-party, pins-gate-safe) so the csharp `dotnet pack -c Release` (net8.0) doesn't break when the runner's default SDK moves. Left as intentional follow-ups (user infra / contract decisions, shared with the pre-existing java arm): automated Central close+release promotion, and adding servers/securitySchemes to the OpenAPI for real SDK auth. Verified: bash -n, action-pins gate, release.yml YAML, feature-matrix, docs-walkthrough, and the Kotlin init script still registers publishMavenJavaPublicationToOSSRHRepository with OSSRH_URL set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsWPsZsDkwGnhGTCZhMkep
|
Non-author review (automated): release-safe & MERGE-READY, but push back on the 4 new languages. Release safety (the critical question) — SAFE, no auto-publish on merge: Blocking concern (minimalism): the 4 new languages (Ruby, PHP, C#, Kotlin) are added with no stated demand — this is the one thing that violates the no-speculative-code discipline. They're generated-only (low marginal maintenance, symmetric with C/C++), but they add 4 registry-publish paths + 4 CI toolchains for languages with no known users. Please either (a) provide the demand signal, or (b) drop them — the diff is cleanly split into 4 per-language commits, so landing the 7-client hardening now and deferring the 4 languages behind real demand is trivial and preferred under "more code != better." Nits: local generation used the JAR path (not Docker) — confirm the first |
|
Non-author review — APPROVE, pending rebase 🔁 (reviewer subagent did not author this PR)
|
|
Coordination note for the next agent turns: the ecosystem root now has a compatibility/uniformity control plane ( Please make the next sequence of work compatible with that pipeline before expanding feature scope. Focus on the repo-local migration queue: latest stable Rust target, Rust 2024/MSRV alignment, package/license/repository metadata, storage policy, thin-binary architecture, generated-contract discipline, package sync, and E2E capability hooks. Backward compatibility is not required pre-adoption; prefer the clean uniform breaking migration over shims/aliases. From the ecosystem root, use |
|
Migration priority escalation: this PR still does not appear to be the Tempera uniformity migration we need. Next agent sequence should treat ecosystem migration as first-priority work before continuing feature scope. If this PR cannot be cleanly converted, open a new PR from this repo with a title like:
Required first slice:
Do not delete migration queue items until this repo passes the relevant ecosystem checks. The source of truth is |
|
Closing this to reduce conflicting SDK/API surface work while the ecosystem API contract gate lands in jadenfix/ecosystem#2. This PR is currently The SDK fleet work should be recut after Palette's OpenAPI is migrated to that target shape, so generated clients are not immediately invalidated by the contract migration. This is a coordination close, not a rejection of the SDK direction. |
What does this PR do?
Grows the contract-driven SDK fleet from 7 to 11 fully-generated
"Stainless-style" clients by adding Ruby, PHP, C#/.NET, and Kotlin, and
wires real publishing for every new registry. Each new language is added
end-to-end — generator config, committed generated client, live conformance
program, and lockstep updates to every drift/parity gate — through the existing
sdks/openapi/beater-api.json → sdks/clients/<lang>/pipeline. The existing 7clients and the hand-written Layer-2 ergonomic/instrumentation SDKs are
untouched.
Delivered as 6 focused commits (one per language + publishing + a drift fix):
feat(sdks): wire real publishing for Ruby, PHP, C#/.NET, and Kotlinfix(sdks): stop committing the Kotlin composite-build gradle cacheType of change
Contract checklist (required)
/v1endpoint, request/response type, spankind, or attribute — the OpenAPI spec is byte-identical to
main; this PRonly adds new language targets to the generation pipeline.
scripts/regen-sdks.sh— all clients regenerate cleanly (now 11,not 7; the count is updated across gates and docs in this PR)
cargo xtask regen-spec(n/a — spec unchanged)cargo xtask regen-semconv(n/a — conventions unchanged)scripts/check-contract-sync.shpasses locally (no drift): "No drift:API, 11 SDKs, MCP tools, docs, and conventions are all in sync."
Tests
cargo build --workspace/cargo test --workspace— not run; noRust source in
crates/changed. The contract gate did compile+runcargo test -p beater-api --test openapi_coverageandcargo xtask regen-semconv, both green.cargo clippy --workspace --all-targets— not run (no Rust source changed).sdks/conformance/{ruby,php,csharp,kotlin}liveconformance programs (wired into
e2e-clients-live.sh+surface-manifest.json), and thecheck-contract-syncself-test updated.Verified locally:
scripts/check-contract-sync.sh(11 SDKs, zero drift),check-sdk-parity-contract.py,check-feature-matrix-contract.py, thecontract-sync self-test, and live conformance against a running
beaterdforRuby, PHP, and Kotlin (
health ok → createDataset → traces.listround-trip).Notes for reviewers
meaningful sense (one spec → one ergonomic, tag-grouped package per language via
pinned openapi-generator v7.11.0). This PR extends that; it is not a generator
swap. The 4 new languages are generated-only (like C/C++ today) — no Layer-2
ergonomic package — so
EXPECTED_ERGONOMICstays at 5 and onlyEXPECTED_GENERATEDmoves 7 → 11.EvaluatorKinddiscriminator change. utoipa 5.5 rejectsdiscriminatoron an internally-tagged enum with inline variants, and it turnedout unnecessary — all 4 new generators handle the discriminator-less
oneOf,and C++ already patches it via the existing reproducible-patch mechanism.
BEATER_OPENAPI_GENERATOR_JAR(opt-in) added toregen-sdks.sh. Dockerstays the default (CI unchanged); setting this env var runs the same pinned
7.11.0 JAR via a local JVM, producing byte-identical output (verified against
the existing ts/go clients). It removes the hard Docker-Hub dependency for
restricted networks. The 4 new clients were generated this way — the first
sdk-contractCI run (Docker path) is the real cross-check; identical output isexpected.
dotnettoolchain in the dev env). Generation is verified deterministic (two
regenerations byte-identical;
.sln/.csprojGUID pinned).release.yml+publish-sdk.sh) now covers all 11 languagesand no-ops with a clear
SKIPuntil each token is added as a repo secret. Newsecrets needed to actually publish:
RUBYGEMS_API_KEY,NUGET_API_KEY,optionally
PACKAGIST_USERNAME/PACKAGIST_API_TOKEN(Kotlin reusesOSSRH_*).🤖 Generated with Claude Code
Generated by Claude Code