From adae9d50bdb7a7e5263a2778d9eca7ef5eced423 Mon Sep 17 00:00:00 2001 From: Reinhard Hatko Date: Thu, 17 Sep 2026 15:51:23 +0800 Subject: [PATCH 01/10] =?UTF-8?q?fix(deploy):=20follow=20DotNS=20ABI=20gen?= =?UTF-8?q?erations=20=E2=80=94=20bump=20bulletin-deploy,=20configure=20th?= =?UTF-8?q?e=20availability=20probe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deploys on paseo-next-v2 failed for every signer with "Contract execution would revert during startingPrice on POP_RULES". DotNS ships ABI *generations* redeployed behind the SAME contract addresses, rolled out per environment rather than per release. Generation v0.5.8-rc1 removed PopRules.startingPrice(); bulletin-deploy 0.15.0 only knows the older generation and calls it unconditionally. Since the addresses never change, no version diff of environments.json showed anything. - bump bulletin-deploy 0.15.0 -> 0.18.4 (probes the live generation at connect) - availability preflight: resolve the env's DotNS contract map from bulletin-deploy's environments.json and pass it, plus environmentId, to DotNS.connect(). It previously passed only `rpc`, so DotNS fell back to a default map whose POP_RULES has no code here — invisible until 0.16 added the generation probe, because the deploy path (runStorageDeploy) already passed `env` and resolved correctly. - config.test.ts: assert upstream ships that contract map, so a catalog change fails in CI instead of mid-deploy. Verified end to end: storage-and-dotns completes (Bulletin chunks uploaded, DotNS registered) where it previously reverted. Note: `pnpm typecheck` still reports a pre-existing error at playground.ts:509 (Option
owner vs contracts@0.10's HexString), unrelated to this change and tracked separately. --- .changeset/fix-dotns-generation-drift.md | 23 +++++++++++ CLAUDE.md | 10 ++++- package.json | 2 +- pnpm-lock.yaml | 10 ++--- pnpm-workspace.yaml | 2 +- src/config.test.ts | 16 ++++++++ src/utils/deploy/availability.test.ts | 14 +++++++ src/utils/deploy/availability.ts | 52 +++++++++++++++++++++++- 8 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 .changeset/fix-dotns-generation-drift.md diff --git a/.changeset/fix-dotns-generation-drift.md b/.changeset/fix-dotns-generation-drift.md new file mode 100644 index 00000000..f16c193d --- /dev/null +++ b/.changeset/fix-dotns-generation-drift.md @@ -0,0 +1,23 @@ +--- +"playground-cli": patch +--- + +Fix deploys failing with `Contract execution would revert during startingPrice on POP_RULES`. + +The DotNS contracts ship in ABI *generations* that are redeployed behind the same +contract addresses, and roll out per environment rather than per release. Generation +`v0.5.8-rc1` removed `PopRules.startingPrice()`, so the pinned `bulletin-deploy@0.15.0` +— which only knows the older generation and calls that function unconditionally — hit a +revert on paseo-next-v2 for every deploy, dev mode included. Because the addresses never +changed, this was invisible to any version diff of `environments.json`. + +Bumps `bulletin-deploy` to `0.18.4`, which probes the live generation at connect time and +supports all three. + +Also fixes the domain-availability preflight, which constructed `DotNS` and connected with +only an RPC URL. Without a contract map it fell back to built-in defaults whose `POP_RULES` +has no code on this network, so 0.16+'s generation probe failed with "No contract deployed +at this address". It now resolves the env's contracts from bulletin-deploy's own +`environments.json` and passes them (plus `environmentId`) to `connect()`, matching what the +deploy path already did. The divergence guard in `config.test.ts` now asserts that contract +map exists upstream, so a catalog change fails in CI rather than mid-deploy. diff --git a/CLAUDE.md b/CLAUDE.md index 2a531257..89f6d3a6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,9 +27,12 @@ These aren't self-evident from reading the code and have bitten us before. Treat - **`@novasamatech/*` resolves through `@parity/product-sdk-terminal@^0.6.2` (host-papp 0.8.11) — do NOT re-pin to 0.7.x, and do NOT slide back to 0.8.5.** The mobile app's Handshake V2 rewrite accepts ONLY the V2 pairing offer (SCALE discriminant 1); host-papp 0.7.x emits V1 (discriminant 0), which the phone rejects as the generic "Invalid QR code". There is no version-negotiation knob anywhere in the stack — compatibility is purely which host-papp version resolves. host-papp 0.8.6's `HandshakeSuccessV2` is a fixed 258-byte struct requiring `rootEntropySource` (RFC-0007); the matching mobile change merged as Android PR #754 (master `50dfcadb8`, 2026-06-05) and ships in builds v1.0.0-1231+. Phones on builds ≤ 1230 send the 226-byte body, which 0.8.6 cannot decode — pairing against an old phone fails at success-decode, and the remedy is updating the phone app, NOT downgrading host-papp (0.8.5's session key was broken without the local patch we deleted; see the patches bullet). 0.8.6 first moved stored SSO sessions/secrets to new `SsoSessionsV2` / `UserSecretsV2_*` storage keys with NO migration; **host-papp 0.8.7 renamed the session list again `SsoSessionsV2` → `SsoSessionsV3`** and added a required `deviceEncPubKey: Bytes(65)` field on the persisted session, also with no migration and no graceful-degrade (old blobs throw / are ignored at decode), so **every user must re-pair once after the 0.5.0 upgrade** (`playground logout` + `playground login`). `UserSecretsV2_*` is unchanged across 0.8.7. `clearLocalAppStorage()` deletes by `${DAPP_ID}_` prefix, so logout already covers `SsoSessionsV2`, `SsoSessionsV3`, and the orphaned secret blobs. `@parity/product-sdk-terminal@0.3.2` was the historical floor (its codec mirror matched the 0.8.6 `*V2` schemas). We pinned `^0.5.0` (June 2026): 0.5.0 bumps host-papp from `^0.8.6` to `^0.8.7` and updates the internal `createTestSession` codec mirror to the 0.8.7 `SsoSessionsV3` shape; the `./host` subpath we consume and every public signature are unchanged (0.5.0 is additive over 0.4.0's cache-only allowance probe helpers + `AllowanceError` re-export) — the frozen-vector tests (`auth.test.ts`, `signerMode*.test.ts`) pass unchanged across the bump. The statement-store patch is re-pinned to whatever version host-papp pins exactly (0.8.7 then, **0.8.11** now); pnpm fails the install loudly (`ERR_PNPM_UNUSED_PATCH`) if resolution drifts off a patched version (designed tripwire, not a bug). Stable 0.8.7 of the whole `@novasamatech/*` family publishes the same day as its prerelease line, so the `minimumReleaseAge` gate would otherwise pin us to the older `0.8.7-N` prerelease — `pnpm-workspace.yaml::minimumReleaseAgeExclude` opts the 0.8.7 family onto the stable line (drop those entries once the version ages past the window). polkadot-app-deploy's own subtree still pins `@parity/product-sdk-terminal@^0.4.0`, but its host-papp now DEDUPES onto our 0.8.7 (its `^0.8.6` range is satisfied by 0.8.7) — so the whole tree shares one host-papp/statement-store 0.8.7 and the patch covers it all; only `product-sdk-terminal` stays split (0.4.0 for pad, 0.5.0 for us). That dedup means pad's SSO-session probe now looks for `dot-cli_SsoSessionsV3.json` (which `playground login` DOES write) — still fully defused because we pass explicit auth/signers into polkadot-app-deploy in every mode (see the "Dev mode must pass EXPLICIT auth options" invariant). **As of July 2026 (#465) we pin `@parity/product-sdk-terminal@^0.6.2`, which moves the whole `@novasamatech/*` family (host-papp / statement-store / storage-adapter / host-api) to 0.8.11** (terminal 0.6.2 requires `host-papp@^0.8.9`, which resolves to the 0.8.11 line); the statement-store patch is re-pinned to `0.8.11` and `minimumReleaseAgeExclude` lists the 0.8.11 family. The truAPI switch (#464) landed only in `@parity/product-sdk-host` (now `0.14.1`, built on `@parity/truapi` instead of the former `@novasamatech/host-api` in-container transport); `product-sdk-terminal`'s SSO/pairing path STILL rides `@novasamatech/host-papp`, so the family stays in the tree until an upstream terminal moves SSO onto truAPI. `deviceEncPubKey` / re-pair-once semantics carry over unchanged from the 0.8.7 note above (0.8.9→0.8.11 are patch-level on the same session schema). - **`@polkadot-api/json-rpc-provider: ^0.2.0` override is load-bearing.** Removing it splits the lockfile across three versions of `json-rpc-provider` (`0.0.1`/`0.0.4`/`0.2.0`) — different PAPI 2.x transitive consumers ask for different versions. Forcing everyone onto `0.2.0` avoids subtle wire-shape divergence and reduces bundle/process memory. - **`@parity/dotns-cli` (pinned EXACT `0.8.0`) ships a broken publish manifest** declaring `"@polkadot-api/descriptors": "file:.papi/descriptors"` — a workspace path missing from the tarball. pnpm refuses; we redirect that sub-dep to `stubs/papi-descriptors-stub/` (an empty `{}` export) via the version-agnostic `@parity/dotns-cli>@polkadot-api/descriptors` override, so the stub carries across version bumps. dotns-cli's `dist/cli.js` is a fully-bundled Bun build, so the stub is functionally correct. The break persists through every published 0.6.x, `0.7.2`, AND `0.8.0` (verified: the `0.8.0` manifest still lists the `file:.papi/descriptors` dep — the `prepare` script generates `.papi/descriptors` locally but `files` is `["dist"]`, so the manifest keeps the unresolvable `file:` dep). The CLI consumes dotns-cli ONLY as the bundled `dist/cli.js` binary (auto-run on import under the `dotns` argv, see `src/dotns-cli-dispatch.ts`) — we import no dotns-cli TYPES, so a version bump is a pure binary refresh with no compile surface. Remove the override + stub only once `@parity/dotns-cli` republishes a clean manifest. -- **`bulletin-deploy` (formerly `@parity/polkadot-app-deploy`) is pinned to an explicit version (`0.15.0`), not `latest`.** A previous `latest` (0.6.8) had a WebSocket-heartbeat bug that tore chunk uploads down mid-flight. The pin avoids ever silently sliding onto a broken `latest`. When bumping, read release notes for changes to `deploy()`, DotNS methods, or the `DeployOptions` we use (`jsMerkle`, `signer`, `signerAddress`, `storageSigner`, `storageSignerAddress`, `mnemonic`, `rpc`, `attributes`). Newer releases now also export environment helpers (`loadEnvironments`, `resolveEndpoints`, etc.); we don't consume them — our env table lives in `src/config.ts::CONFIGS`. Do NOT downgrade below 0.8.3: 0.7.30-rc/0.8.0 changed storage routing to use the injected `signer` (so phone-mode chunk uploads would phone-sign and die with "message too big"), and 0.8.3 is the first release with the `storageSigner` slot-key escape hatch. The `0.8.3 → 0.9.0` bump (June 2026) was a code/API drop-in: index exports unchanged, `deploy()` signature unchanged, `DeployOptions` only additive, console log strings unchanged (so `src/utils/deploy/progress.ts`'s banner/`[N/M]` parser still matches), `storageSigner` routing precedence unchanged. It aligns polkadot-app-deploy onto `@novasamatech/host-papp@0.8.6` / `@parity/product-sdk-terminal@0.3.x` (collapsing the prior split tree onto our root line), and prefix-matches `dot-cli_SsoSessions*` in its SSO-session probe (still defused because we always pass explicit auth/signer/storageSigner). 0.9.0 also ships a `postinstall` (`patch-package || true`) bundling an `@novasamatech/sdk-statement@0.6.0` patch; we DENY that build script (`allowBuilds: polkadot-app-deploy: false` in `pnpm-workspace.yaml`) because our own pnpm patch on that exact package already applies the fix — pnpm 11 will hard-fail every `pnpm