Skip to content

Add UTS tests for LiveObjects path-based API - #2219

Merged
sacOO7 merged 26 commits into
mainfrom
uts-liveobjects
Jul 23, 2026
Merged

Add UTS tests for LiveObjects path-based API#2219
sacOO7 merged 26 commits into
mainfrom
uts-liveobjects

Conversation

@paddybyers

@paddybyers paddybyers commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Translates portable UTS test specs from specification/uts/objects/ into 290 working ably-js TypeScript tests
  • Covers PathObject, Instance, batch operations, LiveCounter/LiveMap CRDT internals, ObjectsPool sync state machine, RealtimeObject lifecycle, value types, and subscriptions
  • 19 test files: 14 unit (270 tests), 4 integration (15 tests), 1 proxy fault injection (5 tests)
  • 1 test pending (LiveMap#clear() not yet implemented in ably-js)

Test plan

  • All 290 tests pass locally: npx mocha --no-config --require tsx/cjs 'test/uts/objects/**/*.test.ts' --timeout 60000
  • CI passes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • PathObject.instance() now returns an Instance wrapper for primitive values (not just live objects).
  • Bug Fixes
    • LiveObjects pool cleanup no longer deletes the root object.
    • Improved tombstone/removal behavior for map entries, including correct reuse/revival semantics.
    • More robust LiveObjects operation handling: malformed/missing payloads are skipped instead of failing hard, avoiding disruption to other operations.
  • Documentation
    • Updated JSDoc for AnyPathObject.instance to reflect primitive support.

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

New LiveObjects runtime behavior and UTS coverage cover protocol variants, object APIs, CRDT state, synchronization, lifecycle flows, proxy faults, value types, tombstones, polling utilities, and adapted UTS deviations.

Changes

LiveObjects behavior and test coverage

Layer / File(s) Summary
Runtime behavior and object identity
src/plugins/liveobjects/*, liveobjects.d.ts
Updates malformed-operation handling, nonce generation, primitive Instance wrapping, parent-reference cleanup, and root-object preservation.
Protocol fixtures and test harness
test/uts/objects/helpers/*, test/uts/objects/integration/protocol_variants.ts, test/uts/helpers.ts
Adds protocol builders, deterministic object fixtures, mock synced-channel setup, update capture, protocol parameterization, and polling helpers.
Object pool and CRDT state coverage
test/uts/objects/unit/objects_pool.test.ts, test/uts/objects/unit/live_map.test.ts, test/uts/objects/unit/live_counter.test.ts, test/uts/objects/unit/parent_references.test.ts
Tests synchronization, buffering, deduplication, map and counter operations, tombstones, garbage collection, and parent-reference traversal.
Object and PathObject APIs
test/uts/objects/unit/instance.test.ts, test/uts/objects/unit/path_object*.test.ts, test/uts/objects/unit/live_object_subscribe.test.ts, test/uts/objects/unit/object_id.test.ts
Tests wrappers, path reads and mutations, identifiers, subscriptions, depth filtering, bubbling, replacement, and event dispatch.
Realtime lifecycle and integration flows
test/uts/objects/unit/realtime_object.test.ts, test/uts/objects/integration/*, test/uts/objects/integration/proxy/*
Covers attach and sync transitions, publish and ACK behavior, lifecycle propagation, tombstones, reconnects, REST-provisioned state, and proxy fault recovery.
Value types and API wire behavior
test/uts/objects/unit/value_types.test.ts, test/uts/objects/unit/live_map_api.test.ts, test/uts/objects/unit/live_counter_api.test.ts, test/uts/objects/unit/public_object_message.test.ts
Validates value-type creation, nested wire encoding, primitive and JSON mapping, bytes, map and counter APIs, and public object-message shaping.
Test synchronization and documentation
test/uts/realtime/unit/*, test/uts/realtime/integration/*, test/uts/rest/integration/*, test/uts/deviations.md, test/browser/modular.test.js, test/realtime/message.test.js, test/uts/rest/unit/fallback.test.ts
Replaces fixed waits with polling, handles presence re-entry, isolates browser channels, stabilizes filtered-message assertions, and records adapted UTS behavior.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • ably/ably-js#2256: Updates overlapping LiveObjects integration suites and protocol-variant helpers.
  • ably/ably-js#2257: Intersects with the shared LiveObjects test helper infrastructure.
  • ably/ably-js#2260: Covers primitive wrapping by PathObject.instance().

Poem

A rabbit tests maps by moonlight,
Counters hop through syncs just right.
Tombstones fade, protocols hum,
ACKs and paths say, “Here we come!”
The root stays safe beneath the sun. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 67.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding UTS tests for the LiveObjects path-based API.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch uts-liveobjects

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features May 13, 2026 12:48 Inactive
@paddybyers
paddybyers requested a review from ttypic May 13, 2026 13:48
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features May 14, 2026 07:18 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features May 29, 2026 12:10 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features June 6, 2026 11:16 Inactive
@ttypic
ttypic force-pushed the uts-liveobjects branch from 400c6a4 to dfcacca Compare June 30, 2026 17:31
@ttypic
ttypic changed the base branch from uts-integration-proxy to main June 30, 2026 17:32
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features July 2, 2026 10:29 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/bundle-report July 2, 2026 10:29 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/typedoc July 2, 2026 10:29 Inactive
@ttypic
ttypic force-pushed the uts-liveobjects branch from 6d756dd to 91ebdf1 Compare July 2, 2026 10:41
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features July 2, 2026 10:41 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/bundle-report July 2, 2026 10:42 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/typedoc July 2, 2026 10:42 Inactive
paddybyers and others added 4 commits July 2, 2026 11:57
Translate portable UTS test specs from specification/uts/objects/ into
working ably-js TypeScript tests covering PathObject, Instance, batch
operations, LiveCounter/LiveMap CRDT internals, ObjectsPool sync state
machine, RealtimeObject lifecycle, value types, and subscriptions.

19 test files: 14 unit (270 tests), 4 integration (15 tests),
1 proxy fault injection (5 tests). 1 test pending (LiveMap#clear()
not yet implemented).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove client-side port allocation (TOCTOU race) and let the proxy
auto-assign free ports via OS. Read the assigned port from the session
creation response. Update binary to v0.2.0 with new asset naming.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds parentReferences, PublicAPI::ObjectMessage, RTO24/25/26 tests;
updates objectMessage/subscription assertions; removes batch API tests.
308 passing, 4 pending deviations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The webpack build type-checks the whole tsconfig program (which
includes test/**/*), so type errors in the UTS LiveObjects tests
failed `npm run build` and therefore `npm ci`.

 - Add siteCode and objectsGCGracePeriod to the mock CONNECTED
   message's connectionDetails defaults, so tests can set these
   real protocol fields without widening a mismatched type.
 - Pass the LiveObjects plugin module namespace to `plugins`
   instead of the LiveObjects const export, matching the internal
   ModularPlugins type (typeof import('plugins/liveobjects')) and
   the existing JS tests. Runtime behaviour is unchanged.
@ttypic
ttypic force-pushed the uts-liveobjects branch from 91ebdf1 to 4d0fa70 Compare July 2, 2026 10:57
@ttypic
ttypic marked this pull request as ready for review July 2, 2026 10:57

@ttypic ttypic 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.

LGTM

sacOO7 added 2 commits July 6, 2026 22:49
…son+msgpack variants

- objects_faults: restructure the RTO20e proxy test to the corrected spec
  sequence (ably/specification#501) — force SYNCING via injected ATTACHED
  with HAS_OBJECTS, mutate while SYNCING, wait for the publish ACK in the
  proxy log, then inject channel ERROR and assert the pending operation
  fails with 92008 / statusCode 400 / cause 90000 (RTO20e1). Removes the
  90001 DEVIATION, which documented the spec error now fixed at source.
- objects_gc: replace the deviation comments with the real spec references —
  undefined reads are RTLM5d2h-compliant (spec says undefined/null), and the
  timer-based GC sweep is covered at the unit tier (RTO10/RTO10b1/RTLM19
  unit tests), so only observable tombstone semantics belong here.
- objects_sync: align the RTO4 subscribe-only test title with the corrected
  spec wording and drop its DEVIATION comment.
- Add describeWithProtocols helper and run objects_lifecycle, objects_sync
  and objects_gc once per protocol variant (json, msgpack) as their specs
  require, without any command-line or environment parameter.

All suites verified against the nonprod sandbox: objects_faults 5/5,
lifecycle/sync/gc 24/24 across both protocol variants.
[AIT-1130] fix(uts): align objects integration tests with corrected specs and run both protocol variants
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features July 8, 2026 12:55 Inactive
sacOO7 added 4 commits July 21, 2026 14:47
…aining nondeterminism

- add pollUntilSuccess to the integration sandbox helpers: any error from the
  polled read means "keep polling" (logged as it happens); on timeout the most
  recent error is thrown so failures stay diagnosable
- poll all eventually-consistent message-store reads (getMessage,
  getMessageVersions, annotations.get) through pollUntilSuccess in the REST and
  realtime mutable_messages tests, replacing the fixed 2s propagation sleep and
  fail-fast polls that raced store visibility
- use pollUntilSuccess for the objects_faults value polls, where value() raises
  by design while the channel is transiently detached mid-recovery; objects
  sync/lifecycle/gc value polls stay on plain pollUntil (an error there is a
  real bug) and drop redundant default interval/timeout options
- RTO10/RTO10b1 GC unit tests: backdate the tombstone serialTimestamp instead
  of stubbing Date.now; RTO10b1 now genuinely discriminates the server-provided
  5s grace period from the 24h default
- align the RSC15f cached-fallback tick with the spec (150ms) and document the
  sanctioned RTLM19 Date.now stub in live_map's deviation header
…helper

The helper's only call site was LiveMap.overrideWithObjectState, which is
invoked exclusively from the OBJECT_SYNC flow (RTO5c1a1, RTO5c1b1a/b).
Every such path runs _rebuildAllParentReferences (RTO5c10) before any
subscriber callbacks fire, unconditionally clearing and re-deriving all
parentReferences from the final post-sync pool state — so the helper's
intermediate updates were never observable. parentReferences has a single
reader (getFullPaths, used by _notifyPathSubscriptions), which during sync
only runs after the rebuild. In the tombstone branch the refs were already
removed by LiveMap.clearData (RTLO4e5) before the helper ran.

Also scope-tightens previousDataRef into the else branch of
overrideWithObjectState, its only consumer.

Supersedes #2234, which is applied here instead.
…s with stack

The truthiness check inherited from pollUntil is deliberate, matching the
spec's poll_until_success convention (a bare boolean condition polls until
true), so a falsy return means "keep polling" by design - now stated in the
doc comment along with what to do when the natural result could be falsy.
Retry warnings pass the error object to console.warn instead of interpolating
it, so stacks are preserved.
[AIT-1141] fix(liveobjects): spec-compliance fixes from the objects deviations audit (nonce length, inbound op handling, counter noop guards)
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features July 22, 2026 12:49 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/bundle-report July 22, 2026 12:49 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/typedoc July 22, 2026 12:49 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/uts/objects/unit/live_map.test.ts (1)

264-290: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep RTLM9b coverage on the entry-level comparison.

Because ObjectMessage.serial is empty, canApplyOperation rejects the message before RTLM9b runs. This assertion therefore covers the object-level RTLO4a3/RTLM15b rejection, not the “both entry serials empty” rule. Use a valid message serial with empty entry serials, or rename this test and add a separate RTLM9b case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/uts/objects/unit/live_map.test.ts` around lines 264 - 290, Update the
RTLM9b test to use a valid non-empty ObjectMessage.serial while keeping the map
entry’s timeserial empty, so applyOperation reaches and verifies the entry-level
empty-serial comparison. Preserve the rejection and unchanged-data assertions;
if object-level empty-serial behavior is still needed, cover it in a separately
named test.
🧹 Nitpick comments (4)
test/uts/realtime/integration/sandbox.ts (1)

224-251: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use one pollUntilSuccess implementation.

The same implementation remains duplicated in test/uts/realtime/integration/mutable_messages.test.ts Lines 231-250 and test/uts/objects/integration/proxy/objects_faults.test.ts Lines 231-250. Remove those local copies and import this shared helper so timeout and error-propagation behavior cannot drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/uts/realtime/integration/sandbox.ts` around lines 224 - 251, The shared
pollUntilSuccess helper in sandbox.ts should be the sole implementation. Remove
the duplicate local definitions from mutable_messages.test.ts and
objects_faults.test.ts, then import and use the shared pollUntilSuccess in both
tests while preserving their existing call sites and options.
src/plugins/liveobjects/livemap.ts (1)

707-716: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate of _logNoPayloadWarning in livecounter.ts — noted for the consolidation below.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/liveobjects/livemap.ts` around lines 707 - 716, Consolidate the
duplicate `_logNoPayloadWarning` implementation shared by `LiveMap` and
`LiveCounter`; remove the redundant `liveobjects/livemap.ts` version and reuse
the existing shared or canonical implementation while preserving the warning
message and discard behavior.
src/plugins/liveobjects/livecounter.ts (1)

265-301: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Correct noop semantics for missing create count; _logNoPayloadWarning duplicates the LiveMap version.

The _mergeInitialDataFromCreateOperation/_applyCounterInc noop handling matches the cited RTLC16/RTLC9 UTS expectations. Separately, _logNoPayloadWarning (Lines 292-301) is byte-for-byte the same helper added in livemap.ts aside from the class name in the log message — a good candidate to hoist onto the LiveObject base class. Flagging for the consolidation note below.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/liveobjects/livecounter.ts` around lines 265 - 301, Consolidate
the duplicate _logNoPayloadWarning helper by moving its shared warning behavior
from LiveCounter and LiveMap into the LiveObject base class. Update both
subclasses to use the inherited method, preserving the existing log action,
severity, message, and malformed-payload handling.
src/plugins/liveobjects/liveobject.ts (1)

246-262: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider centralizing the "well-formed but stale" skip-log in _canApplyOperation.

Both LiveCounter.applyOperation and LiveMap.applyOperation duplicate an if (opSerial && opSiteCode) { ...LOG_MICRO... } block right after this call, purely to avoid re-logging when this method already logged the malformed-serial warning. Consider having _canApplyOperation accept an action/description argument and emit both the malformed-serial and stale-serial logs itself, removing the need for subclasses to duplicate the guard.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/liveobjects/liveobject.ts` around lines 246 - 262, Extend
_canApplyOperation to accept the operation action or description and centralize
logging for both malformed and stale serials, including the existing LOG_MICRO
stale-operation message. Update LiveCounter.applyOperation and
LiveMap.applyOperation to pass the action context and remove their duplicated
opSerial/opSiteCode logging guards, while preserving the existing skip decisions
and log content.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/uts/deviations.md`:
- Around line 231-237: Update test/uts/deviations.md lines 231-237 to document
that increment(null) is runtime-reachable in JavaScript and follows the amount
?? 1 default, behaving like an omitted argument rather than being unreachable;
update test/uts/objects/unit/live_counter_api.test.ts lines 124-126 to add an
explicit increment(null) case asserting the counter increases by 1.

---

Outside diff comments:
In `@test/uts/objects/unit/live_map.test.ts`:
- Around line 264-290: Update the RTLM9b test to use a valid non-empty
ObjectMessage.serial while keeping the map entry’s timeserial empty, so
applyOperation reaches and verifies the entry-level empty-serial comparison.
Preserve the rejection and unchanged-data assertions; if object-level
empty-serial behavior is still needed, cover it in a separately named test.

---

Nitpick comments:
In `@src/plugins/liveobjects/livecounter.ts`:
- Around line 265-301: Consolidate the duplicate _logNoPayloadWarning helper by
moving its shared warning behavior from LiveCounter and LiveMap into the
LiveObject base class. Update both subclasses to use the inherited method,
preserving the existing log action, severity, message, and malformed-payload
handling.

In `@src/plugins/liveobjects/livemap.ts`:
- Around line 707-716: Consolidate the duplicate `_logNoPayloadWarning`
implementation shared by `LiveMap` and `LiveCounter`; remove the redundant
`liveobjects/livemap.ts` version and reuse the existing shared or canonical
implementation while preserving the warning message and discard behavior.

In `@src/plugins/liveobjects/liveobject.ts`:
- Around line 246-262: Extend _canApplyOperation to accept the operation action
or description and centralize logging for both malformed and stale serials,
including the existing LOG_MICRO stale-operation message. Update
LiveCounter.applyOperation and LiveMap.applyOperation to pass the action context
and remove their duplicated opSerial/opSiteCode logging guards, while preserving
the existing skip decisions and log content.

In `@test/uts/realtime/integration/sandbox.ts`:
- Around line 224-251: The shared pollUntilSuccess helper in sandbox.ts should
be the sole implementation. Remove the duplicate local definitions from
mutable_messages.test.ts and objects_faults.test.ts, then import and use the
shared pollUntilSuccess in both tests while preserving their existing call sites
and options.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: aa2386e6-4395-42a0-b78b-3a7add642e3b

📥 Commits

Reviewing files that changed from the base of the PR and between 4bd8c27 and c963991.

📒 Files selected for processing (33)
  • src/plugins/liveobjects/livecounter.ts
  • src/plugins/liveobjects/livecountervaluetype.ts
  • src/plugins/liveobjects/livemap.ts
  • src/plugins/liveobjects/livemapvaluetype.ts
  • src/plugins/liveobjects/liveobject.ts
  • src/plugins/liveobjects/objectid.ts
  • src/plugins/liveobjects/restobject.ts
  • test/browser/modular.test.js
  • test/realtime/message.test.js
  • test/uts/deviations.md
  • test/uts/helpers.ts
  • test/uts/objects/helpers/standard_test_pool.ts
  • test/uts/objects/integration/objects_gc.test.ts
  • test/uts/objects/integration/objects_lifecycle.test.ts
  • test/uts/objects/integration/objects_sync.test.ts
  • test/uts/objects/integration/proxy/objects_faults.test.ts
  • test/uts/objects/unit/instance.test.ts
  • test/uts/objects/unit/live_counter.test.ts
  • test/uts/objects/unit/live_counter_api.test.ts
  • test/uts/objects/unit/live_map.test.ts
  • test/uts/objects/unit/live_map_api.test.ts
  • test/uts/objects/unit/live_object_subscribe.test.ts
  • test/uts/objects/unit/objects_pool.test.ts
  • test/uts/objects/unit/path_object_subscribe.test.ts
  • test/uts/objects/unit/public_object_message.test.ts
  • test/uts/objects/unit/realtime_object.test.ts
  • test/uts/objects/unit/value_types.test.ts
  • test/uts/realtime/integration/mutable_messages.test.ts
  • test/uts/realtime/integration/presence/presence_lifecycle.test.ts
  • test/uts/realtime/integration/sandbox.ts
  • test/uts/rest/integration/mutable_messages.test.ts
  • test/uts/rest/integration/sandbox.ts
  • test/uts/rest/unit/fallback.test.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • test/uts/helpers.ts
  • test/uts/objects/integration/objects_sync.test.ts
  • test/uts/objects/integration/objects_lifecycle.test.ts
  • test/uts/objects/integration/objects_gc.test.ts
  • test/uts/objects/unit/instance.test.ts
  • test/uts/objects/integration/proxy/objects_faults.test.ts
  • test/uts/objects/unit/live_map_api.test.ts
  • test/uts/objects/unit/objects_pool.test.ts
  • test/uts/objects/helpers/standard_test_pool.ts
  • test/uts/objects/unit/live_object_subscribe.test.ts
  • test/uts/objects/unit/realtime_object.test.ts
  • test/uts/objects/unit/value_types.test.ts

Comment thread test/uts/deviations.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR brings the LiveObjects path-based API up to parity with the portable UTS specs by adding a large new UTS test suite and making a set of targeted LiveObjects implementation changes (primitive PathObject.instance() support, sync safety fixes, more tolerant operation handling, and nonce generation updates) to satisfy those specs.

Changes:

  • Added a comprehensive UTS Objects test suite (unit + integration + proxy fault injection) plus shared fixtures/helpers to standardize mock pools and protocol builders.
  • Updated LiveObjects core logic to match UTS expectations (primitive-wrapping instance(), root object retention during sync cleanup, parent-reference rebuild after sync, and skipping malformed operations instead of throwing).
  • Improved test harness reliability for eventual consistency and async ordering (new polling helpers; reduced fixed sleeps).

Reviewed changes

Copilot reviewed 48 out of 49 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/uts/rest/unit/fallback.test.ts Adjusts fake-timer advancement to align with fallback retry timeout behavior.
test/uts/rest/integration/sandbox.ts Re-exports pollUntilSuccess for REST integration tests.
test/uts/rest/integration/mutable_messages.test.ts Uses pollUntilSuccess to avoid eventual-consistency flakes in message store reads.
test/uts/realtime/unit/presence/realtime_presence_reentry.test.ts Replaces ad-hoc flush loops with pollUntil for deterministic waiting.
test/uts/realtime/unit/channels/channel_server_initiated_detach.test.ts Simplifies “wait for reattach” logic using pollUntil.
test/uts/realtime/unit/channels/channel_properties.test.ts Simplifies “wait for reattach” logic using pollUntil.
test/uts/realtime/unit/auth/connection_auth.test.ts Replaces ad-hoc polling loop with pollUntil.
test/uts/realtime/unit/auth/auth_callback_errors.test.ts Replaces ad-hoc polling loops with pollUntil.
test/uts/realtime/integration/sandbox.ts Adds pollUntilSuccess helper and exports it for reuse.
test/uts/realtime/integration/presence/presence_lifecycle.test.ts Makes presence counting robust by tracking unique clientIds across enter/present.
test/uts/realtime/integration/mutable_messages.test.ts Replaces fixed sleeps with polling for eventual consistency across updates/versions.
test/uts/realtime/integration/helpers/proxy.ts Updates proxy binary versioning and session creation logic; adds versioned asset naming/checksums.
test/uts/objects/unit/value_types.test.ts Adds UTS coverage for LiveCounter/LiveMap value types and their wire encoding.
test/uts/objects/unit/public_object_message.test.ts Adds UTS coverage for public ObjectMessage/ObjectOperation user-facing mapping.
test/uts/objects/unit/path_object.test.ts Adds UTS coverage for PathObject read APIs (pathing, resolution, compact/compactJson).
test/uts/objects/unit/path_object_subscribe.test.ts Adds UTS coverage for PathObject subscribe semantics (depth, bubbling, path-following, quiescence).
test/uts/objects/unit/path_object_mutations.test.ts Adds UTS coverage for PathObject write APIs and error behavior.
test/uts/objects/unit/parent_references.test.ts Adds UTS coverage for parent reference tracking and getFullPaths traversal.
test/uts/objects/unit/object_id.test.ts Adds UTS coverage for ObjectId determinism/format/base64url properties.
test/uts/objects/unit/live_object_subscribe.test.ts Adds UTS coverage for Instance-based subscription behavior, noop suppression, tombstones.
test/uts/objects/unit/live_map_api.test.ts Adds UTS coverage for LiveMap API behavior and wire message generation.
test/uts/objects/unit/live_counter_api.test.ts Adds UTS coverage for LiveCounter API behavior and wire message generation.
test/uts/objects/unit/instance.test.ts Adds UTS coverage for Instance wrapper behavior over live objects and primitives.
test/uts/objects/integration/proxy/objects_faults.test.ts Adds proxy fault-injection integration tests for LiveObjects sync/lifecycle resilience.
test/uts/objects/integration/protocol_variants.ts Adds a helper to run integration suites on json+msgpack variants.
test/uts/objects/integration/objects_sync.test.ts Adds end-to-end sync integration tests (attach→sync→synced, reattach resync).
test/uts/objects/integration/objects_lifecycle.test.ts Adds end-to-end lifecycle tests covering propagation across clients and REST provisioning.
test/uts/objects/integration/objects_gc.test.ts Adds integration tests for tombstone semantics and recreatability.
test/uts/objects/helpers/standard_test_pool.ts Introduces shared mock pool fixture + protocol/object message builders for Objects UTS.
test/uts/mock_websocket.ts Extends default CONNECTED payload with siteCode and objectsGCGracePeriod.
test/uts/helpers.ts Adds unit-tier pollUntil helper and exports it for use across UTS unit tests.
test/uts/deviations.md Documents adapted/omitted UTS cases where JavaScript semantics differ (and other deviations).
test/realtime/message.test.js Fixes a race by waiting for filtered-channel deliveries before asserting.
test/realtime/liveobjects.test.js Updates expectation to match new primitive-wrapping PathObject.instance() behavior.
test/browser/modular.test.js Makes encrypted history channel name unique per client-class variant to avoid cross-variant interference.
src/plugins/liveobjects/restobject.ts Switches RestObject ID nonce generation to ObjectId.generateNonce.
src/plugins/liveobjects/pathobject.ts Makes PathObject.instance() wrap primitives; tightens batch() to require LiveObject target.
src/plugins/liveobjects/objectspool.ts Prevents sync cleanup from removing the root object.
src/plugins/liveobjects/objectid.ts Adds async nonce generation helper (generateNonce) with required entropy.
src/plugins/liveobjects/liveobject.ts Makes malformed serial/siteCode operations non-fatal (log + skip) and updates merge return type.
src/plugins/liveobjects/livemapvaluetype.ts Uses ObjectId.generateNonce for map create-with-objectId operations.
src/plugins/liveobjects/livemap.ts Skips malformed/missing payload ops via warnings; avoids throwing on unsupported actions.
src/plugins/liveobjects/livecountervaluetype.ts Uses ObjectId.generateNonce for counter create-with-objectId operations.
src/plugins/liveobjects/livecounter.ts Skips malformed/missing payload ops via warnings; treats missing increment number as noop.
liveobjects.d.ts Updates PathObject.instance() documentation to reflect primitive-wrapping behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/uts/realtime/integration/helpers/proxy.ts
A faulty OBJECT_DELETE operation (or a tombstoned object state) targeting
the root object would tombstone it: data cleared, all subscriptions
deregistered, and - tombstone being a terminal state - no re-sync could
ever resurrect it. After the GC grace period the sweep would then evict
root from the ObjectsPool entirely, violating RTO3b; root cannot be
re-created as a zero-value object ('root' is not a parseable object id),
so every subsequent objects operation on the channel fails unrecoverably.

Per RTLO4e the realtime system only tombstones orphaned or uninitialized
objects - root is by definition neither - so such a message indicates a
fault and is now rejected client-side, consistent with the existing
warn-and-skip handling for other invalid inbound operations.

- LiveObject.tombstone() rejects the root object with a warning and a
  noop update (RTLO4e10); single choke point covering both the RTLO5
  operation path and the RTLC6f/RTLM6f sync paths
- ObjectsPool._onGCInterval() never evicts root (RTO10c1b1, mirroring
  the existing RTO5c2a guard in deleteExtraObjectIds); root's tombstoned
  map entries still get RTLM19 entry-level GC
- overrideWithObjectState() in LiveMap/LiveCounter returns the tombstone
  branch early since tombstone() can now return a noop update

Derived UTS tests: RTLO4e10 operation/sync path tests in live_map.test.ts,
channel-level RTO10c1b1 GC test in realtime_object.test.ts.

Spec twin: ably/specification#509
Raised in #2219 review discussion r3558197916
sacOO7 added 2 commits July 23, 2026 09:26
…ejection warning

A rejected root tombstone indicates a faulty inbound message, and the
site/serial is what identifies its origin; matches the adjacent RTLO4a3
warning style. Addresses review feedback on #2270.
[AIT-1204] fix(liveobjects): reject tombstoning of the root object (RTLO4e10, RTO10c1b1)
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features July 23, 2026 09:11 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/bundle-report July 23, 2026 09:11 Inactive
sacOO7 added a commit to ably/specification that referenced this pull request Jul 23, 2026
…or GC-evicted

RTO10c1b as written compelled a compliant SDK to violate RTO3b: an
OBJECT_DELETE (or a tombstoned ObjectState) targeting the root object
would tombstone it - clearing its data, deregistering all listeners,
and (since tombstone is a terminal state) making the channel's objects
permanently unrecoverable - after which the GC sweep would evict root
from the ObjectsPool entirely.

- RTLO4e10: LiveObject.tombstone must reject the root object with a
  warning and a noop LiveObjectUpdate. Placed in the shared tombstone
  method so it covers both the RTLO5 operation path and the
  RTLC6f/RTLM6f sync paths.
- RTO10c1b1: the GC sweep must never remove the root object from the
  ObjectsPool (mirrors RTO5c2a), as a safeguard for the RTO3b invariant.

UTS test specs:
- internal_live_map.md: new RTLO4e10 tests for the operation and sync
  paths; the three existing tombstone-mechanics tests (RTLO5, RTLM6f,
  RTLO4e9) are repointed from objectId "root" to a tombstoneable
  non-root map, reconciling the spec with the ids the ably-js derived
  tests already used.
- realtime_object.md: new channel-level RTO10c1b1 test verifying root
  survives a GC sweep after a rogue OBJECT_DELETE and stays functional.

Raised in ably/ably-js#2219 review discussion r3558197916.
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/typedoc July 23, 2026 09:12 Inactive
…on missing proxy port

Addresses the two open review threads on #2219:

- RTLC12e1 deviation note reworded: increment(null) is runtime-reachable
  in JS; what is unreachable is the 40003 failure path, because the
  public API defines a nullish amount as equivalent to an omitted
  argument (amount ?? 1). New table case pins that contract by asserting
  the increment-by-1 default, so a later signature or coalescing change
  surfaces as a conscious decision. Also fixes the note's reference to a
  nonexistent test file name.
- createProxySession now validates that the proxy control server
  returned a numeric port and throws with the raw response, instead of
  letting tests connect to localhost:undefined and fail later with a
  less diagnosable error.
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/features July 23, 2026 09:27 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/bundle-report July 23, 2026 09:27 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2219/typedoc July 23, 2026 09:28 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants