From 1591abb03d593be1ebd785c6d8f4ffb30a67dad0 Mon Sep 17 00:00:00 2001 From: adenueltech Date: Sat, 17 Oct 2026 21:54:23 +0100 Subject: [PATCH 1/2] docs: explain how is_compatible differs between vault-registry and access-lease/subscription (#115) Add a "Version compatibility checks" section to docs/CONTRACTS.md that contrasts the two is_compatible variants: vault-registry takes a caller- supplied version and compares major.minor with the compiled version, while access-lease and subscription take no argument and require the stored version to equal the compiled version exactly. Includes signatures, failure cases, worked examples and when to use each, and links it from the Versioning convention. Closes #115 Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/CONTRACTS.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/docs/CONTRACTS.md b/docs/CONTRACTS.md index b439ddb..dbc52c2 100644 --- a/docs/CONTRACTS.md +++ b/docs/CONTRACTS.md @@ -22,7 +22,7 @@ storage or error codes must update this file in the same pull request. | `init` | One-time. A second call fails with `AlreadyInitialised` — it can never overwrite the admin. `init` does not require the admin's signature, so deploy and init in the same pipeline run. | | Admin rotation | `set_admin(new_admin)` on `access-lease` and `subscription`, gated by the current admin. | | Upgrades | `upgrade(new_wasm_hash)` — admin-only; storage is preserved. | -| Versioning | `get_version()` returns the version recorded at `init` (crate version); `is_compatible(...)` detects stale deployments. | +| Versioning | `get_version()` returns the version recorded at `init` (crate version); `is_compatible` differs between contracts — see [Version compatibility checks](#version-compatibility-checks). | | Errors | Every fallible entrypoint returns `Result<_, Error>`; codes are stable and never renumbered. | | Events | Defined as `#[contractevent]` types (so they appear in the contract spec and generated bindings). Topics start with a fixed symbol; data is a single value. Unit tests (`events_have_documented_shape`) pin the wire format. | | Cross-contract calls | Contracts in this workspace are **independent**: none of them performs a cross-contract call to another SynapsVault contract. Each contract validates only its own inputs and trusts the admin/backend to supply consistent identifiers. See [Cross-contract trust model](#cross-contract-trust-model). | @@ -37,6 +37,45 @@ storage or error codes must update this file in the same pull request. | **Buyer / Subscriber** | Holds leases/subscriptions; a subscriber can cancel their own subscription. | | **Anyone** | All read-only entrypoints (`get`, `list`, `is_valid`, `is_active`, …) are permissionless. | +### Version compatibility checks + +`is_compatible` has the same name in every contract but answers a **different +question** in `vault-registry` than in `access-lease` and `subscription`. Do not +call them interchangeably. + +| | `vault-registry` | `access-lease`, `subscription` | +|---|---|---| +| Signature | `is_compatible(version: String) -> bool` | `is_compatible() -> bool` | +| Input | A version string **supplied by the caller** | None — reads the version **stored in the contract** | +| Compared against | The running WASM's compile-time version | The running WASM's compile-time version | +| Rule | `major.minor` prefixes are equal (patch is ignored) | Exact string equality (`major.minor.patch`) | +| Returns `false` when | The input is empty, longer than 32 bytes, or has a different `major.minor` | No version is stored (never initialised), or the stored version differs in any component | +| Question it answers | "Is a client/tool built against `version` compatible with this registry?" | "Does this deployment's stored state match the code now running?" | + +Examples, assuming the compiled version is `0.2.1`: + +| Call | Result | +|---|---| +| `vault-registry::is_compatible("0.2.0")` | `true` — same `0.2` | +| `vault-registry::is_compatible("0.3.0")` | `false` | +| `access-lease::is_compatible()` with stored `0.2.0` | `false` — patch differs | +| `access-lease::is_compatible()` with stored `0.2.1` | `true` | + +How to use them: + +- **vault-registry** — call it off-chain with the version your client, SDK or + indexer was built for (for example the version recorded in + `deployed/contract-ids.env`). It does not look at storage, does not depend + on `init`, and is unaffected by `upgrade`/`migrate`. +- **access-lease / subscription** — call it after a deployment or upgrade to + detect a stale deployment. It returns `false` right after `upgrade` (the + stored version is not updated by `upgrade`) until the admin runs `migrate`, + and `false` on a contract that was never initialised. + +Because the rules differ, a patch-only upgrade makes `access-lease` and +`subscription` report `false` until `migrate` runs, while `vault-registry` +keeps accepting clients on the same `major.minor`. + ### Cross-contract trust model SynapsVault contracts are deployed and operated as a set but are **not wired From 8cfb9f6034fe6a379a6ae9d6fa027264239a6502 Mon Sep 17 00:00:00 2001 From: adenueltech Date: Sat, 17 Oct 2026 22:38:51 +0100 Subject: [PATCH 2/2] docs: note that vault-registry is_compatible rejects non X.Y.Z versions (#115) Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/CONTRACTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CONTRACTS.md b/docs/CONTRACTS.md index dbc52c2..dfffbee 100644 --- a/docs/CONTRACTS.md +++ b/docs/CONTRACTS.md @@ -49,7 +49,7 @@ call them interchangeably. | Input | A version string **supplied by the caller** | None — reads the version **stored in the contract** | | Compared against | The running WASM's compile-time version | The running WASM's compile-time version | | Rule | `major.minor` prefixes are equal (patch is ignored) | Exact string equality (`major.minor.patch`) | -| Returns `false` when | The input is empty, longer than 32 bytes, or has a different `major.minor` | No version is stored (never initialised), or the stored version differs in any component | +| Returns `false` when | The input is empty, longer than 32 bytes, not of the form `X.Y.Z` with numeric components (e.g. `"0.1"`, `"0.1."`, `"0.1.2.3"`), or has a different `major.minor` | No version is stored (never initialised), or the stored version differs in any component | | Question it answers | "Is a client/tool built against `version` compatible with this registry?" | "Does this deployment's stored state match the code now running?" | Examples, assuming the compiled version is `0.2.1`: