feat(truapi): Pocket modality RFC and protocol spec - #609
feat(truapi): Pocket modality RFC and protocol spec#609valentinfernandez1 wants to merge 9 commits into
Conversation
The committed Swift bindings gain the Pocket value types and the updated custom-renderer observer checksum from `make uniffi`. The playground coverage test enumerated every Worker-pinned service as "Chat"; Pocket is Worker-pinned too, so it now checks the Chat service by name. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
@lore-bot-app review |
|
Reading the diff and checking what the record says. Back in a few minutes. |
There was a problem hiding this comment.
TL;DR
Adds the Pocket RFC, a four-method Pocket trait (wire ids 198 to 211) with stub host defaults, and moves the renderer node types out of chat. 0 blocking, 4 minor. One of the minor items needs a sequencing decision against the open codec-2 wire cutover (#357).
Summary
The PR lands the Pocket modality as a draft RFC plus its protocol surface. truapi gains api/pocket.rs (list_subscribe, remove_card, action_subscribe, host-initiated card_render), v01 payload types, versioned wrappers with encoding tests, and latest re-exports. CustomRendererNode and friends move from v01/chat/custom_renderer.rs to v01/renderer.rs with the wire encoding unchanged. The generated dispatcher and wire table pick up the new service, the schema hash changes, ProductRuntimeHost gets an empty impl Pocket that answers Unavailable and empty streams, and ProductRuntimeControl::render_pocket_card mirrors render_custom_message. iOS bindings are regenerated, the playground chat test is scoped to Chat, and a changeset bumps @parity/truapi and @parity/truapi-host minor. The RFC follows the repo's rfc skill: unnumbered file, _index.md untouched, status: draft, required sections present. The diff contains no instructions addressed to the reviewer.
What the record says
- Scarcity is the third privileged card. The tracking issue settled that Scarcity joins Humanity and Balance as permanently present and non-removable, layout still open. The RFC matches. #563
- Pocket was explicitly deferred out of the manifest RFC. The product-manifest RFC discussion marked Pocket as needing a redesign and named the Apple Wallet style "add a card on demand" use case. The deeplink add flow here is the first written answer to that. paritytech/triangle-js-sdks#174
- Precedent for landing a trait with stub defaults before any host backs it. The Funding RFC did the same: trait plus empty host impl returning unavailable. #339
- The wire table is mid-redesign. #357 splits the frame discriminant into trait and method bytes and renumbers per trait under codec 2. It is open and was active today. #351 and RFC 0028 (#557, #572) describe the same cutover. This PR allocates flat ids in the table #357 replaces. #357 , #351 , #557
- Id collisions with downstream extensions have happened before. triangle-js-sdks derives ids from the vendored truapi table and keeps local extension ids in
wireTable.extensions.ts; a truapi bump once failed on overlaps. Lore does not index the current extension file, so I cannot confirm 198 to 211 are free there. paritytech/triangle-js-sdks#245 , #350 - Chat identifier bounds were retrofitted after the modality shipped. #453 and #430 added normalization, screening, and payload caps for chat ids and payloads. Pocket's ids and action payload start without any. #453 , #430
- The CLI question is still open. #523 asks how to exercise worker-backed Pocket without a host shell and wants the CLI to report served modalities at startup. This PR leaves the CLI answering
Unavailable. #523 - Release 2 tracking lists Pocket manifest declarations as an untracked gap and splits Pocket work into a v2 tracker. #591 , #594
- Owners per Lore: pgherveou, valentinfernandez1, filvecchiato, johnthecat.
Concerns
- Wire ids 198 to 211 are allocated in a table that #357 is about to replace.
rust/crates/truapi/src/api/pocket.rs:31,45,66,86and bothwire_table.rsfiles. Whichever PR merges second has to renumber and regenerate. Not a defect here, but the order should be agreed before merge so one of them does not ship a wire contract that lives for a single release. render_pocket_cardis unreachable from any host.rust/crates/truapi-server/src/host_core.rs:1172. Unlikerender_custom_message, it is not exposed innative.rsorwasm.rs, and there is noPocketPlatformseam in truapi-platform the way Chat hasChatPlatform(truapi-platform/src/lib.rs:2771) and Locale hasLocaleHost(lib.rs:2728). Soimpl Pocket for ProductRuntimeHost {}atruntime.rs:2920cannot be backed by iOS, Android, or a JS host without editing truapi-server. The Funding precedent accepted this shape, so this is a scope statement rather than a bug, but the PR description should say the seam is a follow-up.- No bounds on
card_id,action_id, or the action payload.rust/crates/truapi/src/v01/pocket.rs:8,48-53. The RFC callscard_id"a lowercase label" but gives no charset or length, andpayload: Option<Vec<u8>>has no cap. Chat gotnormalize_chat_identifierand a 256 KiB custom payload cap only after hosts diverged (#453). The RFC's Wire surface section is the place to fix these before a second host implements them. - RFC text disagrees with its own snippet on id allocation.
docs/rfcs/pocket-modality.md:129says ids start after "the highest allocated on main at draft time (194)", then uses 198. The highest is 197 (locale_subscribe receive). Small, but it is the spec.
Questions for the author
- Does this land before or after #357? If after, will Pocket take a trait byte with methods 0 to 3, and is the flat allocation here throwaway?
- Is a
PocketPlatformseam plus native and wasm exposure ofrender_pocket_cardthe next PR, and is iOS the first consumer given its hard-coded Humanity, Balance, and Scarcity cards? - Should
card_idreuse the chat identifier normalization rules, and should the face action payload get an explicit cap in the RFC? - Has anyone checked triangle-js-sdks
wireTable.extensions.tsfor local ids in 198 to 211?
Next: reply on #357 sequencing, since that decides whether the ids in this PR are final.
🤖 Reviewed by Lore (Parity knowledge base) · 50 agent turns · 446.5s · knowledge as of 2026-09-07
Resolve the conflicts main's #551 and #617 introduced: - #551 untracked the generated Rust dispatcher, wire table and iOS Swift bindings. Accept the deletions; they are regenerated on demand and the Pocket wire entries come back from `scripts/codegen.sh`. - #617 moved most trait impls out of runtime.rs. Take main's structure and re-apply the two Pocket additions on top: `Pocket` in the `truapi::api` import, and the stub impl next to `impl Chat`, where main keeps the worker-modality impls.
check-rfc.yml holds a newly added RFC to the shape of the template: it needs `title` and `owner` in the frontmatter, a `## Summary`, a `## Motivation`, and a design section. The Motivation went missing while trimming the document, so the gate failed on it. State the gap the RFC closes: RFC 0024 declares `includes.pocket` and expects a card, and nothing says which cards a product may back, how one enters the collection, or who can take it out. Also drop the "what this RFC adds" self-reference from the summary, which the rfc skill's style rules cut.
Tracking issue: #563
What this defines
Pocket is a collection of product-backed cards owned by the host. A product cannot add a card on its own. The user follows a Pocket deeplink and approves a host dialog that shows the card as it will look. Both the user and the owning product can remove a card. Humanity, Balance and Scarcity are privileged and removable by nobody.
Also defined: the
-/pocket/addand-/pocket/opendeeplinks, thepocket.cardslist in the Worker manifest, and the Widget launch for an expanded card.Faces are drawn through the Unified Renderer (#633) on its
PocketCardcontext. Worker lifetime is the Worker Lifecycle (#632) reference count, one reference per visible face. Both are cited as merged, so this should merge after them.Protocol surface
pocket.list_subscribepocket.remove_cardWorker execution only. Pocket starts at 206 rather than 198 because the product SDK's
host-apipackage appends its own methods after the last truapi id and holds 198 to 205 downstream. #357 retires flat ids whichever order the two land in.card_idreuses chat'snormalize_chat_identifierandCHAT_FIELD_MAX_BYTESrather than declaring its own bounds. Action ids and payloads belong to the renderer.Scope
RFC and crate-level spec only. The trait ships with default bodies, so a host with no Pocket surface answers
remove_cardwithUnavailableand endslist_subscribewith an empty Interrupt frame.Runtime behaviour, the host platform seam, native bindings and the CLI host follow in the "Implementation, rust-core" task of #563.