Conversation
16 failing -> 0 failing
Take the Swift branch's scenario-based event-registry-frames fixture; Kotlin conformance test now drives the client from it.
2 failing -> 2 failing (red tests for the ordering contract)
…127) Declarations mutate and send from the client dispatcher, the ack captures its snapshot synchronously, and a lock keeps deltas out of a snapshot in flight. 2 failing -> 0 failing
V3RON
left a comment
There was a problem hiding this comment.
Request changes (posted as a comment: GitHub refuses request-changes on your own PR): 1 blocker, 0 should-fix.
Spec: issue #127 plus the ordering contract in packages/native/fixtures/README.md.
Fix first: an event declared from a connection listener during the ack goes out as a delta before the snapshot that then wipes it.
| scope.launch { sendSnapshotSafely() } | ||
| // The event snapshot is the declarations as they stand at ack time; declarations made | ||
| // after it go out as deltas behind it. | ||
| val eventSnapshot = if (heldSession?.acceptsEventRegistry == true) eventRegistry.snapshotWireJson() else null |
There was a problem hiding this comment.
Blocker: a declaration made while the ack is handled is sent as a delta before the snapshot, and the snapshot then erases it on the daemon.
setClientState(active) and emitSessionChange run listeners synchronously on the dispatcher before this line. A listener that declares an event, e.g. Appduct.addListener { if (it is AppductEvent.SessionChange) Appduct.registerEvent("x", "d") }, enqueues the upsert coroutine ahead of the sendSnapshotSafely launch below, and this snapshot is taken before that coroutine has upserted. The dispatcher then runs the upsert first: state is active and the session accepts, so the delta is sent; the snapshot follows without x. The daemon's registry.snapshot replaces the whole map, so x is gone from appduct events ls until the next resume. A registerEvent call from another thread that lands between the continuation starting and the launch below hits the same order.
Reproduced on this head with a scratch test: client.addSessionChangeListener { _, _, _, _ -> client.registerEvent(event("from_listener")) } then connectAndAck(eventRegistry = true) sends [event_registry_delta:from_listener, event_registry_snapshot:[]]. This breaks the fixtures README contract (snapshot before any later delta).
Fix direction: gate deltas on a per-ack "snapshot sent" flag that the snapshot task sets, and read the event registry inside that task (under sendLock) instead of here.
…#127) 2 failing -> 0 failing; core-noop gains registerEvent, unregisterEvent and AppductEventDescriptor
V3RON
left a comment
There was a problem hiding this comment.
Approve (posted as a comment: GitHub blocks approving your own PR): 0 blocker, 0 should-fix. Spec: issue #127 via the PR's criteria table.
Round 1's ordering blocker is fixed: a declaration or removal made while an ack is handled lands in that ack's snapshot and sends no delta; the event registry suite passed 25 of 25 reruns and the two new tests fail on 6dca660 without the fix.
…he-swift-sdk' into issue-127-add-registerevent-to-the-kotlin-sdk
…he-swift-sdk' into issue-127-add-registerevent-to-the-kotlin-sdk
…he-swift-sdk' into issue-127-add-registerevent-to-the-kotlin-sdk
…he-swift-sdk' into issue-127-add-registerevent-to-the-kotlin-sdk
Closes #127
Stacked on #143 (issue #124); base is that branch.
What changed
The Kotlin core gets
Appduct.registerEvent(name, description, payloadSchema)returning anEventRegistration. After every ack carryingevent_registry: true, resume included, the client sends anevent_registry_snapshot; later declarations and disposals send upsert and remove deltas. With no flag nothing is sent. Thecore-noopfacade mirrors the API. Addsfixtures/event-registry-frames.json(snapshot, empty snapshot, upsert and remove deltas), which the Swift slice (#126) also adds in the same shape.Acceptance criteria
event-descriptors.jsonFixturesConformanceTestevent-descriptors fixtureAppductEventRegistryTestsnapshot, empty snapshot, resume ack testsAppduct registerEvent ... its registration removes itan ack without the flag sends no event frames,a resume ack without the flag ...the frames sent match every vector in event-registry-frames fixtureE2E evidence
Target: Android emulator (Pixel API 35, Android 15, arm64),
playground-native/android, commit 09ede49, this branch's daemon (isolated state dir, port 9611). The playground was temporarily patched, not committed, to callAppduct.registerEventforcart.item_added(with a payload schema) andcheckout.done(without).Smoke: SMOKE_OK (
throwing_toolreturnedtool_execution_error, exit 72)Feature:
After backgrounding (HOME) and foregrounding the app,
events lsandevents ls --name cart.item_added --jsonreturned the same declarations. The session stayed active throughout, so this shows persistence across background/foreground, not a new socket resume.Checklist
CHANGELOG.mdhas an entry underUnreleasedpackages/native/android/README.md,website/.../install/android.mdx)index.ts; no new directnode:*I/O outside an adapterdocs/ARCHITECTURE.mdunaffectedOut of scope
fixtures/README.mdstill says the event descriptors fixture is asserted by TypeScript only and does not describeevent-registry-frames.json; it is #124's file, so left for the stack to reconcile with #126.Status
Implement: done (5/5 green) Review: round 2, approve E2E: pass (Android, playground-native) Ready: yes