Conversation
Add a shared event envelope, bounded actor diagnostics, and safe local observers. Map SQL and Durable Objects lifecycle telemetry without exposing application payloads. Keep exporter and error-logger failures outside durable work. Refs #42
CI audit reports high-severity WebSocket and TLS advisories for the existing Miniflare pin. Override only Undici 7.29.0 with its patched 7.29.1 release; regenerate the lockfile and verify the audit and Durable Objects suite.
|
This comment has been minimized.
This comment has been minimized.
Include broadcast outbox age and activation message correlation. Keep the\ncombined diagnostics category cap explicit and remove unnecessary broad\ntype annotations from telemetry delivery.
|
@greptileai Please review the current head, 7ede319. The existing summary still references the initial commit. The flagged explicit All current CI jobs pass. Please reassess the full diff and update the summary for this head. |
Persist effect positions within each source message and preserve legacy rows during schema upgrades. Reject null transmit arguments and refresh the parity contract for message reads, administration, and wake-up behavior.
|
@greptileai Please review the latest head after the parity audit fixes. Schema migration 14 persists effect positions so two transmits in one turn preserve staging order; existing rows keep their legacy tie-break. Null transmit arguments are rejected and shared fixtures cover them. The parity ledger now reflects message-result authorization and semantics, administration audit/redrive, reminders, and automatic wake-up. Please review the full diff and update the current-head summary. |
Keep JSON keys as own data properties during normalization, including reserved names, without changing object prototypes. Pin the contract with shared Ruby fixtures and actor persistence tests. Correct result retention and reminder limit documentation after the cross-runtime audit.
|
@greptileai Please review current head d9b6052. The latest fix preserves reserved JSON keys as own data properties without prototype changes, including byte limits and durable actor results. Shared fixtures pin the Ruby/JS contract; all six new regressions fail when the old serializer is restored. The full suite, Chromium, Cloudflare, build, types, and formatting pass. The ledger now records read-only query/projection guards, background result retention, and the existing reminder-name limit difference. Please review the full diff and update the current-head summary. |
Compare complete staged work around projections so draining one intent and staging another cannot bypass the read-only contract. Cover effect and commit-action replacement with terminal rollback regressions.
|
@greptileai Please review the latest commit c77d15a. Projection guards now compare complete staged work so an observable cannot drain and replace an intent with the same count. Effect and commit-action regressions fail under the prior guard and pass with the fix; 546 tests, static checks, and 60 Cloudflare tests pass. |
|
@greptileai Please review the latest commit 8380218. The new observable test now infers its return type, resolving the annotation finding. Static checks and both regression tests pass. |
Cover payload isolation, generated snapshot defaults, staged-work rejection, and configured UTF-8 byte limits. Share timeout telemetry fixtures with Ruby and assert activation generation metadata. Update the parity ledger and observability guide for the matching Ruby projection guards and yielding SQLite busy waits.
A parity audit found portable events with different fields in Ruby and JavaScript. Only the timeout event had a shared fixture, so no test found the difference. compatibility/telemetry-events.json now holds the attribute allowlist and the exact keys of each core SQL event. Both test suites read the same file. - Send ownerId on activation events and activationGeneration on commit action events, as Ruby does. - Send messageId and attempt on reminder.enqueued. - Send depth: null for a truncated mailbox sample. - Port the Ruby purity tests for each kind of staged work. - Correct the dead transmit retry docs, document the diagnostics authorization, and remove the unused compatibility/ruby.yml.
Ruby raises ArgumentError when observe or on has no block. JavaScript accepted a missing onEvent, then logged a TypeError for each event. Reject the call with TypeError before authorization, as Ruby does. Port the Ruby tests for the 1,000-observer limit and for observer removal on close. Each test failed when its guard was removed. Document both observer errors, the setup sample for each runtime, and the new activation event order. Remove the delivered observability section from the roadmap.
Ruby now publishes RBS types for portable events and diagnostics. Name them next to the matching JavaScript exports so the shared guide stays the same in both repositories.
Summary
Implement #42 with the shared portable event schema and actor diagnostics, and close the runtime drift found against Ruby #80.
__proto__through normalization, byte limits, actor state, and retained results, using shared Ruby/JS fixtures.[2, 1]; it now delivers[1, 2]even after a retry.compatibility/telemetry-events.jsonwith Ruby. Both suites check the attribute allowlist and the keys of each core SQL event against it. Activation events now sendownerId, commit action events sendactivationGeneration,reminder.enqueuedsendsmessageIdandattempt, and a truncatedmailbox.depthsample sendsdepth: null.actor_diagnosticsauthorization, and remove the unusedcompatibility/ruby.yml.onEventcallback withTypeErrorbefore authorization, as Ruby raisesArgumentErrorwithout a block. Port the Ruby tests for the 1,000-observer limit and for observer removal onclose().Examples
These snippets extend an application's existing configuration and registered
ShoppingCartactor.operatoris the current authenticated caller; the application's message and administration policies must authorize it.Send portable events and metric samples to your logger
Events include
schemaVersion, actor/message correlation, safe attributes, and metric samples. The same JSON fields work in Ruby and JS, including polling intervals in milliseconds. Arguments, state, results, and exception text are excluded; exporter failures do not fail actor work.Watch one actor and inspect its queues
Administration policies must allow
observeandinspectonactor_diagnostics. Each category exposessampled,truncated, andoldestAgeMilliseconds. Usecart.observe(...)for all of this actor's events. Observers are local to the SQL runtime's process; remote Durable Objects use host instrumentation.Recover a background result after losing the original handle
Assume
checkout({ orderId })returns{ orderId }. Enqueue it with a stable key:After a worker processes it, a later request can recover the result:
A completed result is
{ orderId: 42 }. Every read checks current authorization against the original operation and arguments.result()raises a persisted rejection or permanent failure;outcome()exposes the failure as data. The paired Ruby PR brings Ruby background results and read authorization into this same contract.Keep two transmits in staging order through retries
Inside an actor operation, stage two calls to its server twin's declared
appendoperation:With the transmit handler registered, the receiver applies
1before2, even if delivery of1initially fails. Migration 14 persists the staging position; random effect IDs no longer reorder calls from the same turn. The receiver deduplicates repeated envelopes.Diagnose why a synchronous call timed out
Filter
solid_objects.sync.timeoutevents to see whether an activation, an earliermessage, a paused actor, or database contention prevented progress. The Ruby and
JS SQL runtimes now retain the same fields and reason values. The Durable Objects
host sends no
sync.timeoutevent; itscalltimeouts reportwaitingOn: "unknown".For example, an event can include:
{ "name": "solid_objects.sync.timeout", "attributes": { "waitingOn": "activationHeld", "activationOwnerId": "worker-1", "activationGeneration": "7" } }Unknown activation fields are null. These are correlation fields, not metric labels.
Upgrade and boundaries
Run
runtime.install()before starting upgraded workers. Schema migration 14 addseffects.position. Legacy rows retain position zero and their existing ID tie-break; their original staging order cannot be reconstructed. New effects preserve staging order.Actor observers are process-local on SQL; Durable Objects uses host instrumentation and remote diagnostics. The shared event contract applies to the SQL runtimes; Durable Objects events carry fewer attributes. A truncated
mailbox.depthsample now sendsdepth: nullinstead of nodepthkey. Exporters remain optional. Diagnostics cap the combined queue category and return observations across queries.solid_objects.activation.startednow fires before theactivate()hook. Before, it fired after a successful hook. The newactivation.completedevent takes that meaning, andactivation.failedreports a failed hook. Ruby changes the same events in the paired PR. Move a subscriber that readsactivation.startedas a finished activation toactivation.completed.Both runtimes now retain JSON results for every delivery mode, reauthorize message reads, raise terminal errors from result reads, and expose those errors as data through outcome reads. Ruby adopts this contract in the paired PR.
Validation
pnpm run check,pnpm run format:check, and the full suite: 583 passed, 32 existing environment/adapter skips. Cloudflare suite: 60 passed.promise resolved "[Function]" instead of rejecting, forobserve()and foron()separately. Removing the 1,000-observer cap fails its test withexpected [Function] to be an instance of RangeError. Removing theclose()cleanup fails its test withexpected [...] to have a length of 1 but got 2.activation.started attributes: expected [ 'actorId', 'actorType', …(8) ] to deeply equal [ 'actorId', 'actorType', …(9) ], and the allowlist test failed because no allowlist was exported. Both pass after the fix.QueryMutatedState. Restoring the fix passes.private sink errorand passed after restoring isolation.Closes #42.