feat(web): acknowledged shared tx publishing - #3727
Conversation
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## paul/feat/web-sdk-tutorial #3727 +/- ##
==============================================================
+ Coverage 77.80% 77.86% +0.05%
==============================================================
Files 1321 1325 +4
Lines 126142 126704 +562
Branches 10990 11047 +57
==============================================================
+ Hits 98149 98656 +507
- Misses 24890 24935 +45
- Partials 3103 3113 +10
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 1 file with indirect coverage changes 🚀 New features to boost your workflow:
|
Greptile SummaryThis change adds acknowledged browser publishing to shared robot transmit channels, with relay correlation and SDK receipt handling. Two command-delivery reliability problems were reproduced: Confidence Score: 3/5Not safe to merge until disconnect-state handling and post-delivery acknowledgement semantics are corrected. Focused executable checks reproduced both independent command-delivery failures with captured source and runtime output. The SDK check exercised the real session and transport lifecycle; the bridge check exercised the checked-out frame handler with both healthy and raising subscriber paths. Files Needing Attention:
What T-Rex did
|
| try: | ||
| self.outputs[ch].publish(result) | ||
| except Exception as e: | ||
| nack("publish_failed", e) | ||
| return |
There was a problem hiding this comment.
Out.publish() broadcasts the command before invoking local subscribers. If a subscriber then raises, this handler catches that error and returns PubNack(code="publish_failed"), despite the command already reaching both the transport and the subscriber. A client can retry what appears to be a definite rejection and execute a non-idempotent command twice. Subscriber errors after broadcast must not be represented as a failed publish.
Artifacts
Authored focused reproduction source
- Captures the executable harness that extracts and invokes the exact checked-out `_on_pub_frame` method while preserving broadcast-before-subscriber ordering, takeaway: the repro targets only the alleged failure path.
- The healthy run exited 0 with `transport_broadcast=['command-3727']`, `local_subscriber_delivered=['command-3727']`, and `publish_result_type=PubAck`, takeaway: normal delivery produces an acknowledgement.
- The raising run exited 0 with the same transport broadcast and local delivery but `publish_result_type=PubNack` and `publish_result_code=publish_failed`, takeaway: post-delivery subscriber failure is reported as a definite rejection.
89e4f57 to
b78600a
Compare
- Protocol v5 grows pub/pub_ack/pub_nack and error.requestId (no version bump: unknown messages drop, nothing misparses). New golden vectors pin the messages and the forwarded tx-frame shape on both sides. - ChannelSpec gains additive publish/requiredScope manifest fields with mirrored domain rules (invalid_publish, invalid_scope). Normalized manifests now always emit both, so the golden manifests changed (normalization idempotence forces it). - Channel(dir="tx", publish="shared") compiles: generated Out port, decoder resolved via the new resolve_decoder (registered @web_decoder or generic json.v1 for scalars/dicts/lists; dataclasses need an explicit decoder). text.json.v1 joins the built-ins. publish="exclusive" stays gated (W8). - The relay validates pub in spec order (watch, dup id, 32 KiB cap, policy, scope bypass for the synthetic local principal, per-viewer + aggregate token buckets at maxHz, pending count/byte caps), stamps provenance, and forwards the JSON as a tx data frame on the robot carrier. The forwarded id is a relay-authored token, translated back to the viewer's own id on ack, so viewer-chosen ids stay untrusted and cannot collide. - Pending settles exactly once: bridge ack/nack routed to the one live sender, publish_timeout via the reap sweep, robot_disconnected on robot death, silent release on viewer death. Counts land in /api/stats. - The bridge dispatches carrier tx frames from the ordered control queue, decodes with the resolved codec (PublishContext when the signature takes it), verifies the declared message type, calls Out.publish(), and only then acks on a robot-opened one-shot @control stream. Failures nack with bounded messages and never recycle the session. - SDK session.publish() -> Promise<PublishReceipt>: stable local rejection codes, bounded pending map, outcome "rejected" for definite failures vs "unknown" for connection loss/timeouts, and no automatic resend ever. Correlated errors bypass the hello handshake slot (they could previously unblock a hello() retry) and never touch the session error banner. - examples/chat-input/ is the end-to-end publish demo, pinned by a new chromium e2e in CI (test_publish_browser.py) plus a Python-viewer e2e.
b78600a to
8bd5bdf
Compare
No description provided.