Skip to content

ci: interface-sync guard for frontend Candid declarations#403

Draft
marc0olo wants to merge 1 commit into
mainfrom
dx/interface-sync-guard
Draft

ci: interface-sync guard for frontend Candid declarations#403
marc0olo wants to merge 1 commit into
mainfrom
dx/interface-sync-guard

Conversation

@marc0olo

Copy link
Copy Markdown
Member

Draft — first of three PRs for #402 (DX: canister-integration helpers + interface-contract enforcement).

What

Adds a CI guard that fails if the frontend's generated Candid declarations (idlFactory + types under frontend/ic_vetkeys/src/declarations) drift from the canister .did files.

  • Pin the bindgen version in make_did_bindings.sh — an unpinned npx @icp-sdk/bindgen resolves to whatever is latest and emits spurious diffs on cosmetic changes (confirmed: 0.3.0 → 0.4.0 adds doc-comments with no interface change).
  • SKIP_EXTRACT_CANDID=1 mode — regenerate declarations from the committed .did without rebuilding from Rust source, so the guard depends only on the pinned bindgen + committed .did (no wasm/candid-extractor toolchain, fast and reproducible).
  • .github/workflows/interface-sync.yml — regenerate + git diff --exit-code.

Why

The frontend SDK bundles a fixed idlFactory; if a .did changes and the declarations aren't regenerated, nothing currently catches it. This closes that seam.

The Rust ↔ Motoko backend contract is already enforced behaviorally — the Motoko canister is compiled to wasm and the Rust canister's integration tests run against it (backend/mo/canisters/*/Makefile, backend-motoko.yml). So this guard deliberately targets only the otherwise-unguarded frontend ↔ canister seam.

Verification (local)

  • Guard passes today: regenerating from committed .did with pinned bindgen yields no diff.
  • Negative test: perturbing a .did makes the guard fail as intended; reverting restores green.

Sequencing

First of three (recommended A → B → C):

  • A (this): interface-sync guard.
  • B: Rust macro to generate the EncryptedMaps canister endpoints (dogfooded by the reference canister).
  • C: Motoko mixin equivalent (feasibility proven: moc 1.9.0 compiles mixins and emits their endpoints into the Candid interface).

Follow-up noted (not in this PR)

The committed .did files are slightly stale vs. Rust sourcemake extract-candid now emits domain doc-comments the committed artifacts predate (interface shape unchanged). Refreshing them (and optionally guarding source→.did) is left as a separate change to keep this guard reproducible and toolchain-light.

🤖 Generated with Claude Code

…r .did

Part of #402. The frontend SDK bundles generated Candid declarations
(idlFactory + types) that must track the canister .did files; nothing
currently fails CI if a .did changes and the declarations aren't
regenerated. This adds an interface-sync guard:

- Pin the bindgen version in make_did_bindings.sh so regeneration is
  reproducible (an unpinned `npx` resolves to whatever is latest and
  produces spurious diffs on cosmetic bindgen changes).
- Add a SKIP_EXTRACT_CANDID=1 mode that regenerates declarations from the
  committed .did without rebuilding it from Rust source, so the guard
  depends only on the pinned bindgen + committed .did (no wasm/extractor
  toolchain needed).
- Add .github/workflows/interface-sync.yml: regenerate and fail on any
  diff in src/declarations.

The Rust <-> Motoko backend contract is already enforced behaviorally
(the Motoko canister wasm is run against the Rust canister's integration
tests), so this guard focuses on the otherwise-unguarded
frontend <-> canister seam.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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