Skip to content

ci(sdk): wire binary-compatibility-validator — committed .api dumps + blocking apiCheck gate - #2730

Merged
ThomasGorisse merged 2 commits into
mainfrom
claude/2723-binary-compat
Jul 16, 2026
Merged

ci(sdk): wire binary-compatibility-validator — committed .api dumps + blocking apiCheck gate#2730
ThomasGorisse merged 2 commits into
mainfrom
claude/2723-binary-compat

Conversation

@ThomasGorisse

Copy link
Copy Markdown
Member

Closes #2723.

What & why

The SDK had no public-API surface tracking — a signature change in sceneview, arsceneview or sceneview-core shipped silently unless a reviewer happened to notice. For an AI-first SDK whose llms.txt promises exact signatures, that is the doc-drift bug class at the binary level (shortlist #2642 item 4).

This wires Kotlin's binary-compatibility-validator 0.18.1 into the root build, commits the initial .api dumps, and adds a blocking apiCheck CI gate.

Changes

  • build.gradle + gradle/libs.versions.toml — apply BCV 0.18.1 at the root; apiValidation {} scopes validation to the three published library modules and ignores samples/demos + sceneview-web.
  • Committed .api dumpssceneview/api/sceneview.api (3221 lines), arsceneview/api/arsceneview.api (2436), sceneview-core/api/sceneview-core.api (1522). Verified non-empty and meaningful: they contain Scene, ARScene, every node type (ModelNode, CameraNode, LightNode, …), and the shared commonMain core surface (animation/collision/math/geometry).
  • .github/workflows/ci.yml — new API compatibility job (./gradlew apiCheck), BLOCKING, same tier as Unit tests, path-gated on android (which includes sceneview-core/**). Not advisory: a red apiCheck fails the PR via the CI Gate aggregator.
  • CONTRIBUTING.md — new "Public API changes" section: apiDump → commit the .api diff → the public-API delta is reviewable; tied to the llms.txt invariant.
  • changelog.d/2723-binary-compat-validator.mdAdded.
  • .claude/scripts/check-doc-drift.sh — note-only comment: the .api diff is a deterministic future signal it could consume (no coupling today, per the issue).

Gradle task results (local, macOS)

  • ./gradlew apiDump → BUILD SUCCESSFUL (generated all three .api files).
  • ./gradlew apiCheck → BUILD SUCCESSFUL on the fresh dumps. Log confirms the klib path is skipped as designed: klibApiCheck SKIPPED, iosX64ApiBuild SKIPPED.
  • ./gradlew :sceneview:compileReleaseKotlin :arsceneview:compileReleaseKotlin apiCheck (pre-push rule) → BUILD SUCCESSFUL.
  • check-workflow-scripts.sh → OK; test-check-doc-drift.sh → 7 passed, 0 failed; ci.yml parses as valid YAML.

Differential proof — the gate BITES

Temporarily added a public function to sceneview-core commonMain and ran apiCheck:

> API check failed for project sceneview-core.
  +	public static final fun temporaryGateProbe2723 (J)D
  You can run :sceneview-core:apiDump task to overwrite API declarations

apiCheck failed (non-zero exit), named the exact new symbol, and told the author how to fix it. Reverted the change → apiCheck BUILD SUCCESSFUL again. So a public-signature change with a stale committed dump is a hard CI failure.

Scope / honest exclusions

  • Validated (JVM surface): sceneview, arsceneview, sceneview-core. sceneview-core is KMP — its jvm("android") target dump already captures the entire shared commonMain public API, so the common surface is covered.
  • sceneview-web excluded: JS-only KMP module published to npm, not Maven. Its single js(IR) target has no JVM/bytecode surface for the JVM-based validator; its API is validated separately at the JS layer.
  • Native/JS klib ABI validation disabled (klib { enabled = false }, the default): still experimental, and the iOS native klibs are not buildable on the ubuntu-latest runner that hosts apiCheck. Tracked as a follow-up once it stabilises and a macOS CI leg can host it.

⚠️ Auto-merge deliberately NOT armed

This PR changes the CI contract (adds a new blocking gate + commits generated artifacts that a reviewer should eyeball). It should go through the review-fanout at the orchestrator level rather than fire-and-forget auto-merge.

ThomasGorisse and others added 2 commits July 16, 2026 17:16
… blocking apiCheck gate

Closes #2723.

The SDK had no public-API surface tracking: a signature change in
sceneview, arsceneview or sceneview-core shipped silently unless a
reviewer happened to notice. For an AI-first SDK whose llms.txt promises
exact signatures, that is the doc-drift bug class at the binary level.

- Apply Kotlin binary-compatibility-validator 0.18.1 at the root build,
  scoped via apiValidation {} to the three published library modules
  (sceneview, arsceneview, sceneview-core). Samples/demos and the
  npm-published JS-only sceneview-web module are ignored.
- Commit the initial apiDump output: sceneview.api (3221 lines),
  arsceneview.api (2436), sceneview-core.api (1522).
- Add a BLOCKING `API compatibility` job to ci.yml (same tier as unit
  tests, path-gated on `android`) running `./gradlew apiCheck`.
- CONTRIBUTING.md → "Public API changes": apiDump → commit the .api diff
  makes the public-API delta reviewable; ties to the llms.txt invariant.
- Note-only check-doc-drift.sh interplay (.api diff is a deterministic
  future signal; no coupling today).

JVM surface only: sceneview-core's jvm("android") dump already captures
the shared commonMain API. Native/JS klib ABI validation stays disabled
(experimental + not buildable on the ubuntu CI runner) and is documented
as a follow-up.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
…ording, apiCheck in local gates (#2730)

- CONTRIBUTING.md + build.gradle: the sceneview-web exclusion claimed its
  API 'is validated separately at the JS layer' — no such automated gate
  exists (only the hand-written sceneview-web.d.ts). Reworded honestly,
  pointing at shortlist #2642 item 12 (.d.ts drift gate) as the follow-up.
- CLAUDE.md: 9th entry in the 'Quality gates (must pass before any push
  to main)' list — public-API ABI must match the committed .api dumps.
- pre-push-check.sh: new [11/11] apiCheck step (steps renumbered /10 ->
  /11) so the documented local pre-push gate actually catches an ABI break
  before CI does; failure output points at apiDump for intentional changes.

Verified: bash -n clean, ./gradlew -q apiCheck exit 0 on this branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ThomasGorisse

Copy link
Copy Markdown
Member Author

Review-fanout verdict: MERGE_AFTER_WARNINGS → warnings fixed → auto-merge armed

4/4 reviewers, 0 confirmed ERRORs, breakingApi=false (code/doc: PASS_WITH_WARNINGS · security/impact: PASS).

Both warnings fixed in the follow-up commit:

  • Overstated "validated separately at the JS layer" (CONTRIBUTING.md + the build.gradle exclusion comment): no automated JS ABI gate exists — reworded to the honest reality (hand-written sceneview-web.d.ts, no gate yet) with a pointer to shortlist SDK ideation round 2026-07-10 — shortlist 18 items en 2 vagues (input pour l'orchestrateur SDK) #2642 item 12 as the tracked follow-up.
  • New blocking CI gate absent from the local checklists: CLAUDE.md Quality gates gains entry 9 (ABI matches committed .api dumps), and pre-push-check.sh gains a real [11/11] apiCheck step (steps renumbered) — the documented local pre-push flow now catches an ABI break before CI does, with an actionable apiDump hint on failure.

Re-verified: bash -n clean, ./gradlew -q apiCheck exit 0 on the branch.

@ThomasGorisse
ThomasGorisse enabled auto-merge (squash) July 16, 2026 15:29
@ThomasGorisse
ThomasGorisse merged commit 843223f into main Jul 16, 2026
13 checks passed
@ThomasGorisse
ThomasGorisse deleted the claude/2723-binary-compat branch July 16, 2026 15:49
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.

ci(sdk): wire binary-compatibility-validator — committed .api dumps + blocking apiCheck gate

1 participant