Skip to content

feat: add Chat v2 product authority operations - #709

Open
replghost wants to merge 136 commits into
feat/pvm-app-runtimefrom
feat/chat-v2-product-authority
Open

replghost wants to merge 136 commits into
feat/pvm-app-runtimefrom
feat/chat-v2-product-authority

Conversation

@replghost

@replghost replghost commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

Current repair qualification — 2026-10-02

  • Current source: 726ef76bcce42b91d664d753ac4225df0a093472. Canonical chat artifact-generation and Wasm revisions are this same commit. Prior main-integration baselines are retained: native bda6ac518c8cc59319491b12e4e23b96777375fd, frontend f4012c50c3400d1186c332ad2ae50298cefd153d.
  • Consumers: dotli #255 at 6ef2aa616b6e771c236a37f36743212472ad0b38. Complete matching SDK/host packages remain 0.23.0; codegen and Wasm were rebuilt canonically. Generated client bytes are unchanged. Production features: wasm-signing-host; separate testing bundle: wasm-signing-host,test-host.
Canonical artifact SHA-256
Client npm archive d8e759c51c8e49dd829efbd3d5227217aeac9bd8d9b8952397716fe8bdd8f95c
Client dist/generated/client.js 6c48f48837ceda0c80163dbbc208a365e44230fd55e4b472b634bb3ac2a77aa3
Host npm archive 8ecea2f14eecf6bdde983f04c1d28d1c7c6bffddef639d6a31cf5a7f38ec50b9
Browser signing Wasm 0f10b028409e4d17f6256f3f4fc08fec1fd9bf6a2102f19e77e2e91a567e4a6f
Local QA CLI e21b93f44979f8a46f5f066e1dca6259984334ff4f41dd1e71f09781b5402efa

Native correction and causal limits

Bulletin mortal signatures now anchor to a finalized checkpoint, while nonce/runtime state comes from the freshest available signing snapshot. A checkpoint at least 64 blocks behind is rejected before broadcast. Regression coverage verifies the actual signature with a newer nonce and older finalized checkpoint, and the expiry boundary. Existing transaction retries/deadlines are unchanged; no chain error is suppressed. The affected test fixture uses parking_lot::Mutex.

The former Seity Extrinsic marked as invalid run used noncanonical best-block anchors, but retained evidence lacks the signed bytes and typed pool reason. Fork-sensitive mortality was a real correctness hazard; it is not claimed as the conclusively proved cause of that historical failure. Prior hosted Factory/Genesis timeout causes also remain unproved. No broker/readiness workaround, prewarming, extra retry, or timeout increase was added.

Executed verification

  • Exact-head native CI: success, 25 successful jobs, 1 skipped (E2E (playground inside dotli)); job totals include control jobs. This is the CI workflow result, not an assertion that every advisory PR check or release credential is green.
  • Each of the five native variants passed 21 Bulletin RPC regression tests, all-target Clippy with -D warnings, CLI build, and canonical browser/testing Wasm packaging. Base full library: 1,246 passed.
  • All six frontend consumers passed configured build, typecheck and lint. The later frontend-only formatting correction passed targeted Prettier checks; it did not change runtime source or canonical native artifacts.
Local original sequence Tested frontend head Result, retries=0 Genesis after navigation Factory Submit
#238 0a24db4aa189adad7b93f9ff508c7949e39196ee 42 passed, 20 skipped; no failed/flaky cases 1107ms 9625ms 6057ms
#255 301a235ba13248ef4281e9e3d859919fb6cfbe06 42 passed, 20 skipped; no failed/flaky cases 1045ms 11023ms 13548ms
#287 d3dc8a41807c36b8bcdf001c47eccb9735305499 42 passed, 20 skipped; no failed/flaky cases 1029ms 6496ms 5530ms

The Chat/Seity tested heads above precede documentation-only formatting merges; their native/Wasm pins and runtime code are unchanged. Final hosted frontend results are recorded on the linked consumer PRs, separately from these exact-head local results.

Final hosted retest: failures remain

Frontend PR Tests workflow Functional E2E
#238 success 79 passed 42 passed, 20 skipped
#185 success 89 passed, 3 skipped 41 passed, 1 flaky, 20 skipped
#255 success 89 passed, 3 skipped 42 passed, 20 skipped
#287 failure 85 passed, 4 failed, 3 skipped 42 passed, 20 skipped
#290 success 87 passed, 2 failed, 3 skipped 42 passed, 20 skipped
#291 failure 86 passed, 5 failed, 3 skipped 41 passed, 1 flaky, 20 skipped
  • PVM and JAM Genesis Hash still flaked after navigation: the product stayed pending for the helper's existing 20 seconds; the existing CI retry passed. The helper reports this timeout as error; it is not evidence of a chain rejection. Retained traces include People-chain/local development sockets but do not expose the Asset Hub gateway WebSocket exchange, so these new failures do not establish an upstream or broker cause.
  • Peer: two navigation product-render timeouts at 45 seconds. The existing threshold tolerates these, so its green workflow is not a clean functional suite.
  • Seity: cache-off RPC-gateway resolution timed out; two navigation renders timed out; another navigation case reported failure to connect to trusted provider paseo-bulletin-next-ipfs.polkadot.io. The zero-failure host-settings gate correctly failed.
  • JAM: cache-on reload and two navigation cases reported that same provider connection error; two more navigation cases timed out. The zero-failure host-settings gate correctly failed. These logs do not establish whether the underlying cause was provider availability, runner networking, CORS, or another transport failure.
  • All six final Static Analysis and hosted cold-start Performance workflows passed; all five native CI workflows passed. That does not clear the red functional gates, Genesis flakes, or Doom matrix. No additional CI rerun, timeout/retry increase, threshold relaxation, or speculative transport patch was made.

Doom: criterion corrected, backend matrix still unqualified

The user explicitly approved 35 FPS sustained over 30 seconds, with one frame of sampling-boundary tolerance: frames + 1 >= elapsedMs * 35 / 1000. This replaces the instantaneous FPS >= 35 sample; it is an acceptance-criterion change, not a runtime speedup. Runtime and displayed FPS are unchanged; raw samples are not rounded to force a pass. Update p95 <28.6ms, cold/warm first-frame limits <3,000/<1,000ms, audio and translation-cache checks remain. The revised official RPC benchmark passed once before the vendor replacement.

The later isolated matrix used the rebuilt base pair at frontend 238ab5fa739788b2eb948ba1f807a1876edbacad, with fresh owned Chrome profiles and no concurrent builds/E2E:

Backend Observed result Qualification
smoldot-direct 1,050 frames / 30,001.1ms; p95 17.7ms; cold/warm 202.9/152.8ms; audio/cache passed PASS under the approved criterion
smoldot-shared-worker 1,038 frames / 30,001.4ms = 34.5983854 FPS; p95 17ms; cold/warm 186.4/158.4ms; other checks passed FAIL: cadence deficit retained
rpc-gateway Warm-readiness helper timed out. Its null snapshot conflated missing frame, missing canvas and evaluation errors, and earlier cold/cadence values were not retained by that helper NOT QUALIFIED; iframe disappearance is not established

Distinct diagnostics found no presentation loss in a later instrumented 24-second shared-worker sample and observed a successful hidden RPC new-document reload. Neither diagnostic supersedes the failures or qualifies performance. No evidence-proved runtime fix, guest rebuild, speculative tuning, or further unchanged gate rerun was made. The original strict RPC failure and every new failure remain retained. Next causal capture must instrument the original early 30-second window and distinguish warm lifecycle states before proposing a runtime fix.

Retention and rollout boundary

Local verification used paseo-next-v2, the pinned host-playground fixture f56294cea4430163bf16ec068844b1327441073c, and existing private QA identities. All three corrected sequences paired on their first existing setup attempt. A prior local launch failure and a misconfigured Previewnet-product run (34 passed, 20 skipped, 8 Chain/Contract failures) are retained separately, not presented as reproductions of the hosted Genesis timeout. Private traces/auth/signers were not published.

The first repair heads also exposed a README formatting failure (corrected by documentation-only commits) and a PVM cache-unit-test 5,000ms timeout. No cache runtime/test change, limit increase, or causal claim was made for that isolated timeout. Older in-flight runs superseded by the formatting correction remain recorded as cancelled, not passed.

No PR merge, force push, deployment, environment approval, SDK/npm/product/guest publication, or rollback was performed by this repair. JAM remains JAM-TEST-INSTANCE, never JAM-PUBLIC-DEVNET. The user-owned deploy: paseo.fyi label is retained; repair-triggered deployment runs 36970790399 and 36971286469 were cancelled before deployment. The earlier rollout audit is retained below: an older workflow deployed 56cea5d37577bf82684fb5c6b6e4ba81d2142938; this record does not claim live remained unchanged historically.

Historical integration qualification (superseded; retained verbatim)

Current main refresh and qualification — 2026-10-01

  • Current source: 6d97c7932f26cf190dd6c506ed5f4da110bada74. Native main bda6ac518c8cc59319491b12e4e23b96777375fd is integrated; the frontend stack includes dotli main f4012c50c3400d1186c332ad2ae50298cefd153d (merged chore(deps): bump postcss from 8.5.15 to 8.5.23 in /explorer #313). Histories and worktrees were preserved; pushes used fetched-head ancestry guards, never force.
  • Canonical chat artifact-generation revision: 08bddf36912d61fcfa76e4fb733fd585c6b22bca. Later native changes are test/docs/iOS-only, not SDK/Wasm inputs, so the artifact pin intentionally differs from the current head. Complete matching client and host packages remain 0.23.0, generated rather than hand-edited. Browser signing Wasm uses web-wasm-signing-host without test-host; testing Wasm is separate.
  • Browser consumers: dotli #255 at bb9ad3d8921c63cf62c98b9029289f458b1a67a2.
Canonical artifact SHA-256
Client npm archive d8e759c51c8e49dd829efbd3d5227217aeac9bd8d9b8952397716fe8bdd8f95c
Client dist/generated/client.js (not dist/index.js) 6c48f48837ceda0c80163dbbc208a365e44230fd55e4b472b634bb3ac2a77aa3
Host npm archive a725bcbd6ff17a92bea89bb11868a45b6b3fdb178cb037cb00da1c46105526c9
Browser signing Wasm 0778dfa5255092bbfc7607dc226d1fc9a2d2d0315ffb669258341fa307556485

Qualification

  • Frontend #255 exact-head Tests: functional 89 passed, 3 skipped; E2E 41 passed, 1 flaky, 20 skipped. Hosted E2E retained one flaky Chain → Chain Spec: Genesis Hash case: it failed on the first attempt and passed the existing CI retry. No retry setting was changed.

  • Current-head Core CI: 24 required jobs green — 22 passed, 2 path-filter skips. This includes core Swift/Android coverage, not a claim that full iOS application CI ran at this head. The separate existing release-signing-credentials advisory failure remains distinct from Core CI.

  • Local: Rust workspace: 2,267 passed across 29 suites, 21 ignored. Client/host SDK: 283/326 passed; local Swift and Android qualification passed. Canonical codegen and complete feature-specific package construction were qualified locally.

  • Browser/native proof: Actual canonical SDK Chat Initialize passed over the authenticated product port. Separate ChatIdentityAuthority Allow-once consent was required. After a full host reload and new Allow-once consent, public device metadata was identical. Evidence: main-refresh-native-chat.json. No published guest/product was created.

Retained cross-stack limits

  • The isolated strict Doom matrix is not fully green: RPC measured 34.54231433545555 FPS against ≥35 FPS. Direct smoldot measured 35.06721215581914 and shared-worker smoldot 35.48895899032775. All three passed p95/cold/warm/cache/audio criteria; warm runs used a new document and zero translation. No threshold, clock, timeout, or retry policy was weakened.
  • Latest local Seity E2E attempt: 41 passed, 20 existing skips, 1 Submit failure (Extrinsic marked as invalid). Two existing native broadcast attempts were validated then invalidated; none was found included in the inspected canonical range. [INFERENCE] Noncanonical mortality anchors may explain invalidation; the exact cause is not established and signed extrinsic bytes were not retained. The earlier Factory deadline failure is also retained: inclusion took 47,516ms against the unchanged 30s product deadline. A separate unchanged manual Factory attempt passed in 10.918s. These failures are not erased by other passing checks.
  • Evidence JSON/screenshots are retained beside the refresh worktrees; private browser profiles and throwaway harnesses were removed. No bearer references, keys, signing configuration, or .auth contents are included here.

This refresh authorizes no deployment, environment approval, PR merge, SDK/npm publication, or guest/product publication. Its QA writes were testnet-only.

All three refresh-triggered JAM Deploy runs were cancelled before rollout; final-head cancellation proof is for frontend dcdef40499119183aed82a39f784ef740d494341. No refreshed source head was deployed.

The live environment changed during qualification: older Deploy run 36945647296, attempt 3 was approved under GitHub account replghost, explicitly checked out baseline 56cea5d37577bf82684fb5c6b6e4ba81d2142938, and recorded deployment success at 2026-10-02 01:19:01 UTC. Its later published-product smoke failed. The operator/client/session behind that account is unproven; this qualification granted no approval and performed no rollback. The observed live content hash changed from 4a7caf047fb7f350c1833039b93ba634698a47c56f051b8c7fc0525d4c59a5c8 to 5882695ee20df5d24a6ed2feb9e997f176fe27ecf4eafe742fabb39eba92885f; these are content hashes, not Git SHAs, and their exact byte-level mapping to a source commit is unproven. Earlier revision/deployment records below remain historical evidence and do not override this current section.

Earlier source and qualification (superseded)

Head 4b241e8cfa7b6cdbc6ce90e56866087fc31331f6 includes main aa6ae62ca038bf4a6356edae8eb78e595d52ce24 through history-preserving merge commits. Client and host package manifests remain 0.23.0 with pending Changesets.

The branch includes the integrated main changes and preserves its feature boundary. Root and combined-stack canonical codegen and TypeScript qualification pass. This branch’s current-head Codegen CI job passes; its downloaded canonical output matches all 45 tracked generated files byte-for-byte. Full workspace/native qualification remains tracked by current-head CI.

Current-head core CI passes, including Rust workspace, default WASM bridge, Android compile/unit checks, and iOS Swift + WebKit. Full local workspace/native qualification was interrupted by workstation disk exhaustion; the full current-head core CI gate completes that qualification. Full iOS application CI also passes, including the in-tree core, application build, simulator preview, and tests. No PR was merged or approved, and no npm package was published. Deployment evidence below belongs to the explicitly named earlier revisions, not this source refresh.

Summary

Adds Chat-specific product authority above the generic PolkaVM host integration in #540. Chat cryptographic authority, device binding, request signing, sealing, and opening remain outside the generic host PR.

Authorization boundary

  • local product_device_chat now requires dedicated ChatAuthority consent instead of reusing IdentityDisclosure/username consent
  • local and SSO regression coverage exercises username-only grants, explicit denial, separate approval, cached approval, and revocation; real Bind and Seal/Open operations are used
  • get_user_id keeps its separate identity-disclosure permission; no legacy username grant is migrated into Chat authority
  • moves the secret-bearing pairing Success out of its box instead of cloning it
  • inherits the warning-free Wasm target boundary and CI fixture/provenance fixes from refactor(polkavm): isolate optional host composition #540

Stack and downstream artifacts

Based on #540, with main through c5158448f3c4575f40350017d466053d6b19dacb. Seity remains in #1001; peer transport remains a separate #1010 layer.

Earlier qualification evidence

Initial refresh qualification included 1,469 core tests, 324 SDK tests, native/WASM checks, license validation, and real browser rendering plus a canonical SDK handshake through the refreshed consumer. The codegen executable produced deterministic output across two independent executions. Canonical code generation and release wallet/testing WASM builds also pass for the current source.

At 437a46c5af88b3c4a962d763f8fa5732e9c48183, all PR checks pass, including core CI and full iOS CI. The full iOS run includes the persisted-store migration regression. Consumer checks are tracked in paritytech/dotli-community#255; the combined paseo.fyi deployment is qualified separately in paritytech/dotli-community#291. No on-device Chat message, wallet funding, or payment was performed for this refresh.

Native retests must build the matching TrUAPIHost and TrUAPIProvider artifacts from source; changing an SPM revision alone does not replace prebuilt SDK binaries.

The iOS combined store uses model 53, retaining both historical main and Chat model-49 variants. Real SQLite migration smoke checks passed from main model 49, Chat model 49, and main model 52, preserving payment amounts, owner identity, and native Coinage ledger payloads. The permanent migration regression passes in the app suite. This iOS-only correction does not change the vendored browser SDK artifacts.

The iOS test lane now retains xcresult, raw logs, and crash diagnostics on failure. Run 36654074336 reported 365 failures without a named assertion in its formatted log and did not retain its test result; its cause is not established. The current complete iOS run passes. Diagnostic retention does not weaken tests, change retry behavior, or establish a fix for that earlier failure.

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 10, 2026

@decrypto21 decrypto21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check ordering looks right everywhere. One substantive issue.

1. productDeviceChat reuses a permission meant for something much weaker

It gates on IdentityDisclosure (runtime.rs:576) — the same slot get_user_id uses for "show this product your username" (capabilities/account.rs:513). The key is product-scoped only (truapi-platform/src/lib.rs:1399), nothing marks which capability is asking, and truapi-platform/ has no diff here. But this call binds the wallet's Chat identity and grants a standing Seal/Open oracle against any peer key the product names.

  • Signing-host (host_core.rs:597, via frame_server.rs:177): only gate, since SigningHost::product_device_chat (signing_host.rs:995) checks only the session. A product with an older get_user_id grant gets Bind/Seal/Open with no prompt — reproduced on this branch (pre-seeded grant → proceeds, prompt count 0; no grant → Rejected).
  • Two-device SSO: sso_responder.rs:934 does prompt the first time, but shows "wants to know it's you" for identity binding plus an encryption oracle. Silent after that.

Worth a dedicated PermissionAuthorizationRequest variant with its own review copy, like the neighbouring AccountAccess. If the reuse is deliberate, the doc comment (truapi-platform/src/lib.rs:1029) and prompt copy should say so.

2. Minor

sso_pairing.rs:399 switches success: *success to (*success).clone() on a struct holding identity_chat_private_key. If that was for the new Drop impl, it isn't needed — box-deref-move compiles fine with Drop. Keeping the move avoids a second live copy.

# Conflicts:
#	rust/crates/truapi-codegen/tests/golden/wire_table.rs
#	rust/crates/truapi-server/src/host_logic/sso/messages.rs
#	rust/crates/truapi-server/src/host_logic/sso/messages/v1.rs
#	rust/crates/truapi-server/src/runtime/authority.rs
#	rust/crates/truapi-server/src/runtime/capabilities/account.rs
#	rust/crates/truapi-server/src/runtime/pairing_host.rs
#	rust/crates/truapi-server/src/runtime/pairing_host/sso_channel.rs
#	rust/crates/truapi-server/src/runtime/signing_host.rs
#	rust/crates/truapi-server/src/runtime/signing_host/sso_responder.rs
@github-actions github-actions Bot added the host-work Needs implementation in one or more host repos label Sep 10, 2026
replghost and others added 2 commits September 29, 2026 21:04
…n scope

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@replghost

Copy link
Copy Markdown
Contributor Author

Thanks. All seven addressed:

  1. Attachment capabilities. Rich frames no longer enter opened plaintext. open_history keeps them in the Host, so the product receives rich content only as rich_messages metadata. hop_history/attachments.rs now pins that the claim ticket and identifier never appear in HostNativeChatOpened.plaintext, which chat_device/rich.rs:2 describes.

  2. Shared caps. files, rich_messages and history_imports have per-peer quotas (512) under the shared 4096 bounds, so one contact at its quota is refused with StorageUnavailable while every other peer keeps working. Nothing is evicted: those records carry custody and the digests that recognise a redelivered frame. Each contact still has a lifetime bound; releasing records the product has persisted is recorded in the RFC as a planned extension.

  3. AllowOnce. An allow-once answer grants Chat authority for the rest of the wallet session and stores nothing. The signing host keeps the grant with the session, fenced by the activation generation like AutoSigning grants. The local and SSO entry checks reuse it without re-prompting, including from a new execution of the same product, and require_authorized honours it for PrepareAttachments and file/HOP work. A stored decision always wins, so a denial or revocation ends it. Covered on both paths by *_chat_allow_once_lasts_for_the_session_without_persisting.

  4. iOS payment sheet. The confirmation is no longer awaited inside SerialOperationQueue. prepare saves the .reviewing record and releases the queue, the review runs outside it, and a second queued step re-checks the record, saves the decision, re-previews and prepares. Concurrent retries share one review per operation until its decision is saved, and one caller's cancellation does not dismiss it for the others. pendingPaymentReviewDoesNotBlockOtherOperations shows views and denomination completing while a review is open.

  5. Wire-table parity. tests/wire_table_ts_parity.rs is restored from main, and the Rust CI job sets TRUAPI_REQUIRE_GENERATED_TS=1 again, with the generated TS from the codegen artifact.

  6. Unmatched Responses. Only a Response for a request this transport abandoned at its deadline is ignored silently. A Response carrying this transport's prefix for a request id it never sent is reported. Ids from another transport on the same connection, and a pending request's mismatched pair (already reported), are not reported again.

  7. Top-up stuck on Unknown. The claim engine records each entry as submitted before sending it. At finalized state, an entry this wallet never submitted, missing from both source and destination, was spent elsewhere: it is forfeited, the plan finishes, and the top-up reports PartialPayment { credited }, or InsufficientFunds when nothing was credited. An entry this wallet did submit stays retryable as before. When every source is already absent before any plan exists, the top-up returns InsufficientFunds without recording anything, so a later funding still claims. When only some are absent at that point, it stays Unknown: before any observation, unfunded and spent-elsewhere look the same on chain. Settling that case needs historical evidence that the coin existed at the memo's block, which is a follow-up in the chain adapter.

    One known limitation, recorded in the RFC: settlement is judged per installation. If two installations of the same wallet import the same top-up, the one that loses the race reports InsufficientFunds although the coins reached the wallet on the other device. Balances come from inventory and are unaffected; claim ownership across installations belongs with the multi-device wallet design.

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

This pull request touches an app, which is not built by default. Add a label for each build you want:

  • iOS simulator build, ios-simulator-build: builds the iOS app, runs its tests and attaches a build for the iOS Simulator on a Mac.
  • iOS device build, ios-device-build: attaches a signed build that installs on a registered iPhone or iPad.
  • Android build, android-device-build: attaches an APK that installs on an Android phone or an emulator.

Each starts as soon as it is added and follows the branch from then on.

# Conflicts:
#	js/packages/truapi-host/src/wasm-module.ts
#	rust/crates/truapi/src/runtime/authority.rs
#	rust/crates/truapi/src/runtime/signing_host.rs
#	rust/crates/truapi/src/runtime/signing_host/sso_responder.rs
#	rust/crates/truapi/src/runtime/statement_store_rpc.rs
# Conflicts:
#	android/truapi-host/README.md
#	js/packages/truapi-host/src/test-support.ts
#	rust/crates/truapi-client/src/generated.rs
# Conflicts:
#	rust/crates/truapi-codegen/tests/deterministic_emit.rs

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation github_actions Pull requests that update GitHub Actions code host-android Touches the Android host tree host-ios Touches the iOS host tree host-work Needs implementation in one or more host repos javascript Pull requests that update javascript code rfc rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants