Skip to content

[PUB-1837] Use server-provided timestamp to sweep old tombstones#2054

Merged
VeskeR merged 1 commit intomainfrom
PUB-1837/server-provided-tombstone-timestamp
Jul 22, 2025
Merged

[PUB-1837] Use server-provided timestamp to sweep old tombstones#2054
VeskeR merged 1 commit intomainfrom
PUB-1837/server-provided-tombstone-timestamp

Conversation

@VeskeR
Copy link
Contributor

@VeskeR VeskeR commented Jul 3, 2025

Use serialTimestamp field from ObjectMessage to know when a tombstone was created for an object or a map entry.

Resolves PUB-1837

Summary by CodeRabbit

  • New Features

    • Added support for tracking and exposing tombstone timestamps when objects or map entries are deleted, using server-provided timestamps when available.
  • Bug Fixes

    • Improved error handling for missing object state in messages.
  • Tests

    • Introduced new test cases to verify correct assignment of tombstone timestamps during object and map entry deletions.
  • Chores

    • Updated method signatures and internal structures to consistently use object messages and propagate tombstone timestamps.

@VeskeR VeskeR requested a review from mschristensen July 3, 2025 05:05
@coderabbitai
Copy link

coderabbitai bot commented Jul 3, 2025

Warning

Rate limit exceeded

@VeskeR has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 13 minutes and 33 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 8313fbe and 7c7033b.

📒 Files selected for processing (9)
  • src/plugins/objects/livecounter.ts (4 hunks)
  • src/plugins/objects/livemap.ts (9 hunks)
  • src/plugins/objects/liveobject.ts (5 hunks)
  • src/plugins/objects/objectmessage.ts (4 hunks)
  • src/plugins/objects/objects.ts (2 hunks)
  • src/plugins/objects/syncobjectsdatapool.ts (3 hunks)
  • test/common/modules/objects_helper.js (2 hunks)
  • test/common/modules/private_api_recorder.js (1 hunks)
  • test/realtime/objects.test.js (6 hunks)

Walkthrough

The changes update the handling of tombstoned objects and map entries to consistently use a server-provided numeric timestamp (serialTimestamp) when available. Method signatures and internal logic are modified to propagate and utilize this timestamp throughout object and map operations, sync flows, and tests, replacing previous reliance on local clock time.

Changes

Files/Paths Change Summary
src/plugins/objects/livecounter.ts, src/plugins/objects/livemap.ts, src/plugins/objects/liveobject.ts Updated method signatures to accept ObjectMessage instead of ObjectState; now use serialTimestamp for tombstone times; improved error handling for missing object state.
src/plugins/objects/objectmessage.ts Added optional serialTimestamp property to ObjectMessage, WireObjectMessage, and ObjectsMapEntry; updated copyMsg to handle new property.
src/plugins/objects/objects.ts, src/plugins/objects/syncobjectsdatapool.ts Refactored to propagate and use objectMessage (with serialTimestamp) instead of objectState in sync and data pool logic.
test/common/modules/objects_helper.js, test/common/modules/private_api_recorder.js Updated helper methods and private API identifiers to handle/test serialTimestamp in object messages.
test/realtime/objects.test.js Added/updated tests to verify correct assignment of tombstone timestamps from serialTimestamp or local clock.

Sequence Diagram(s)

sequenceDiagram
    participant Server
    participant Client
    participant LiveObject/LiveMap

    Server->>Client: Send ObjectMessage (with serialTimestamp)
    Client->>LiveObject/LiveMap: Apply operation (pass ObjectMessage)
    LiveObject/LiveMap->>LiveObject/LiveMap: Tombstone object/entry (use serialTimestamp if present)
    LiveObject/LiveMap->>Client: Expose tombstonedAt property (from serialTimestamp or local clock)
Loading

Estimated code review effort

3 (~45 minutes)

Possibly related PRs

Suggested reviewers

  • mschristensen
  • sacOO7

Poem

The tombstones now keep perfect time,
With server clocks, their moments chime.
No more guesswork, no more fuss—
Each object’s fate is clear to us!
A hop, a skip, a timestamp true,
This bunny’s code review is through.
🐇⏰

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch PUB-1837/server-provided-tombstone-timestamp

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot temporarily deployed to staging/pull/2054/features July 3, 2025 05:06 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2054/bundle-report July 3, 2025 05:06 Inactive
@VeskeR VeskeR changed the title Use server-provided timestamp to sweep old tombstones [PUB-1837] Use server-provided timestamp to sweep old tombstones Jul 3, 2025
@github-actions github-actions bot temporarily deployed to staging/pull/2054/typedoc July 3, 2025 05:06 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/plugins/objects/livemap.ts (1)

692-692: Nice improvement to error message formatting.

Adding quotes around the key value improves error message clarity, especially for keys containing spaces or special characters.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fc70477 and 7356070.

📒 Files selected for processing (9)
  • src/plugins/objects/livecounter.ts (4 hunks)
  • src/plugins/objects/livemap.ts (9 hunks)
  • src/plugins/objects/liveobject.ts (5 hunks)
  • src/plugins/objects/objectmessage.ts (4 hunks)
  • src/plugins/objects/objects.ts (2 hunks)
  • src/plugins/objects/syncobjectsdatapool.ts (3 hunks)
  • test/common/modules/objects_helper.js (2 hunks)
  • test/common/modules/private_api_recorder.js (1 hunks)
  • test/realtime/objects.test.js (6 hunks)
🧰 Additional context used
🧠 Learnings (9)
test/common/modules/private_api_recorder.js (2)
Learnt from: VeskeR
PR: ably/ably-js#1897
File: test/realtime/live_objects.test.js:125-127
Timestamp: 2024-10-22T16:20:01.724Z
Learning: In the file `test/realtime/live_objects.test.js`, the field name `regionalTimeserial` is correct and should not be changed to `timeserial`.
Learnt from: VeskeR
PR: ably/ably-js#1917
File: src/plugins/liveobjects/liveobject.ts:2-2
Timestamp: 2024-11-08T05:28:30.955Z
Learning: In `src/plugins/liveobjects/liveobject.ts`, `EventEmitter` is accessed via the client object, so importing it with the `type` modifier is acceptable.
src/plugins/objects/objects.ts (4)
Learnt from: VeskeR
PR: ably/ably-js#1924
File: src/plugins/liveobjects/statemessage.ts:220-224
Timestamp: 2024-11-22T17:15:25.075Z
Learning: In `src/plugins/liveobjects/statemessage.ts`, using `JSON.parse(JSON.stringify(...))` for deep copying is acceptable when buffer values are preserved in subsequent code.
Learnt from: VeskeR
PR: ably/ably-js#1917
File: src/plugins/liveobjects/liveobject.ts:2-2
Timestamp: 2024-11-08T05:28:30.955Z
Learning: In `src/plugins/liveobjects/liveobject.ts`, `EventEmitter` is accessed via the client object, so importing it with the `type` modifier is acceptable.
Learnt from: VeskeR
PR: ably/ably-js#1909
File: test/common/modules/live_objects_helper.js:209-209
Timestamp: 2024-10-25T08:54:46.022Z
Learning: In test code files such as `test/common/modules/live_objects_helper.js`, concerns about assignments within expressions are not applicable.
Learnt from: VeskeR
PR: ably/ably-js#1897
File: test/realtime/live_objects.test.js:125-127
Timestamp: 2024-10-22T16:20:01.724Z
Learning: In the file `test/realtime/live_objects.test.js`, the field name `regionalTimeserial` is correct and should not be changed to `timeserial`.
src/plugins/objects/objectmessage.ts (2)
Learnt from: VeskeR
PR: ably/ably-js#1924
File: src/plugins/liveobjects/statemessage.ts:220-224
Timestamp: 2024-11-22T17:15:25.075Z
Learning: In `src/plugins/liveobjects/statemessage.ts`, using `JSON.parse(JSON.stringify(...))` for deep copying is acceptable when buffer values are preserved in subsequent code.
Learnt from: VeskeR
PR: ably/ably-js#1897
File: test/realtime/live_objects.test.js:125-127
Timestamp: 2024-10-22T16:20:01.724Z
Learning: In the file `test/realtime/live_objects.test.js`, the field name `regionalTimeserial` is correct and should not be changed to `timeserial`.
test/common/modules/objects_helper.js (3)
Learnt from: VeskeR
PR: ably/ably-js#1924
File: src/plugins/liveobjects/statemessage.ts:220-224
Timestamp: 2024-11-22T17:15:25.075Z
Learning: In `src/plugins/liveobjects/statemessage.ts`, using `JSON.parse(JSON.stringify(...))` for deep copying is acceptable when buffer values are preserved in subsequent code.
Learnt from: VeskeR
PR: ably/ably-js#1897
File: test/realtime/live_objects.test.js:125-127
Timestamp: 2024-10-22T16:20:01.724Z
Learning: In the file `test/realtime/live_objects.test.js`, the field name `regionalTimeserial` is correct and should not be changed to `timeserial`.
Learnt from: VeskeR
PR: ably/ably-js#1909
File: test/common/modules/live_objects_helper.js:209-209
Timestamp: 2024-10-25T08:54:46.022Z
Learning: In test code files such as `test/common/modules/live_objects_helper.js`, concerns about assignments within expressions are not applicable.
src/plugins/objects/syncobjectsdatapool.ts (6)
Learnt from: VeskeR
PR: ably/ably-js#1924
File: src/plugins/liveobjects/statemessage.ts:220-224
Timestamp: 2024-11-22T17:15:25.075Z
Learning: In `src/plugins/liveobjects/statemessage.ts`, using `JSON.parse(JSON.stringify(...))` for deep copying is acceptable when buffer values are preserved in subsequent code.
Learnt from: VeskeR
PR: ably/ably-js#1917
File: src/plugins/liveobjects/liveobject.ts:2-2
Timestamp: 2024-11-08T05:28:30.955Z
Learning: In `src/plugins/liveobjects/liveobject.ts`, `EventEmitter` is accessed via the client object, so importing it with the `type` modifier is acceptable.
Learnt from: VeskeR
PR: ably/ably-js#1880
File: liveobjects.d.ts:26-26
Timestamp: 2024-10-08T15:37:26.765Z
Learning: For plugins like `LiveObjects`, the `any` type is intentionally used to maintain flexibility.
Learnt from: VeskeR
PR: ably/ably-js#2052
File: ably.d.ts:2608-2621
Timestamp: 2025-06-27T08:37:06.539Z
Learning: In ably.d.ts, null values are not supported in LiveMap objects. The PrimitiveObjectValue type correctly excludes null even though JsonScalar includes it, as this reflects the intentional design limitation of the LiveMap implementation.
Learnt from: VeskeR
PR: ably/ably-js#1909
File: test/common/modules/live_objects_helper.js:209-209
Timestamp: 2024-10-25T08:54:46.022Z
Learning: In test code files such as `test/common/modules/live_objects_helper.js`, concerns about assignments within expressions are not applicable.
Learnt from: VeskeR
PR: ably/ably-js#1897
File: src/plugins/liveobjects/livecounter.ts:93-93
Timestamp: 2024-10-22T13:26:59.680Z
Learning: In the `LiveCounter` class's `_applyCounterCreate` method, it's intentional to increment the counter's value using `+=` instead of initializing it with `=` because the counter may have a pre-existing non-zero value.
test/realtime/objects.test.js (3)

undefined

<retrieved_learning>
Learnt from: VeskeR
PR: #1897
File: test/realtime/live_objects.test.js:125-127
Timestamp: 2024-10-22T16:20:01.724Z
Learning: In the file test/realtime/live_objects.test.js, the field name regionalTimeserial is correct and should not be changed to timeserial.
</retrieved_learning>

<retrieved_learning>
Learnt from: VeskeR
PR: #1909
File: test/common/modules/live_objects_helper.js:209-209
Timestamp: 2024-10-25T08:54:46.022Z
Learning: In test code files such as test/common/modules/live_objects_helper.js, concerns about assignments within expressions are not applicable.
</retrieved_learning>

<retrieved_learning>
Learnt from: VeskeR
PR: #1926
File: test/realtime/live_objects.test.js:2078-2117
Timestamp: 2024-11-28T02:13:58.582Z
Learning: In this project, Mocha tests have an inherent default timeout of 60 seconds, so adding explicit timeouts in the test code is unnecessary.
</retrieved_learning>

src/plugins/objects/liveobject.ts (5)
Learnt from: VeskeR
PR: ably/ably-js#1924
File: src/plugins/liveobjects/statemessage.ts:220-224
Timestamp: 2024-11-22T17:15:25.075Z
Learning: In `src/plugins/liveobjects/statemessage.ts`, using `JSON.parse(JSON.stringify(...))` for deep copying is acceptable when buffer values are preserved in subsequent code.
Learnt from: VeskeR
PR: ably/ably-js#1917
File: src/plugins/liveobjects/liveobject.ts:2-2
Timestamp: 2024-11-08T05:28:30.955Z
Learning: In `src/plugins/liveobjects/liveobject.ts`, `EventEmitter` is accessed via the client object, so importing it with the `type` modifier is acceptable.
Learnt from: VeskeR
PR: ably/ably-js#1897
File: test/realtime/live_objects.test.js:125-127
Timestamp: 2024-10-22T16:20:01.724Z
Learning: In the file `test/realtime/live_objects.test.js`, the field name `regionalTimeserial` is correct and should not be changed to `timeserial`.
Learnt from: VeskeR
PR: ably/ably-js#2052
File: ably.d.ts:2608-2621
Timestamp: 2025-06-27T08:37:06.539Z
Learning: In ably.d.ts, null values are not supported in LiveMap objects. The PrimitiveObjectValue type correctly excludes null even though JsonScalar includes it, as this reflects the intentional design limitation of the LiveMap implementation.
Learnt from: VeskeR
PR: ably/ably-js#1909
File: test/common/modules/live_objects_helper.js:209-209
Timestamp: 2024-10-25T08:54:46.022Z
Learning: In test code files such as `test/common/modules/live_objects_helper.js`, concerns about assignments within expressions are not applicable.
src/plugins/objects/livecounter.ts (3)
Learnt from: VeskeR
PR: ably/ably-js#1924
File: src/plugins/liveobjects/statemessage.ts:220-224
Timestamp: 2024-11-22T17:15:25.075Z
Learning: In `src/plugins/liveobjects/statemessage.ts`, using `JSON.parse(JSON.stringify(...))` for deep copying is acceptable when buffer values are preserved in subsequent code.
Learnt from: VeskeR
PR: ably/ably-js#1917
File: src/plugins/liveobjects/liveobject.ts:2-2
Timestamp: 2024-11-08T05:28:30.955Z
Learning: In `src/plugins/liveobjects/liveobject.ts`, `EventEmitter` is accessed via the client object, so importing it with the `type` modifier is acceptable.
Learnt from: VeskeR
PR: ably/ably-js#1897
File: src/plugins/liveobjects/livecounter.ts:93-93
Timestamp: 2024-10-22T13:26:59.680Z
Learning: In the `LiveCounter` class's `_applyCounterCreate` method, it's intentional to increment the counter's value using `+=` instead of initializing it with `=` because the counter may have a pre-existing non-zero value.
src/plugins/objects/livemap.ts (4)
Learnt from: VeskeR
PR: ably/ably-js#1924
File: src/plugins/liveobjects/statemessage.ts:220-224
Timestamp: 2024-11-22T17:15:25.075Z
Learning: In `src/plugins/liveobjects/statemessage.ts`, using `JSON.parse(JSON.stringify(...))` for deep copying is acceptable when buffer values are preserved in subsequent code.
Learnt from: VeskeR
PR: ably/ably-js#1917
File: src/plugins/liveobjects/liveobject.ts:2-2
Timestamp: 2024-11-08T05:28:30.955Z
Learning: In `src/plugins/liveobjects/liveobject.ts`, `EventEmitter` is accessed via the client object, so importing it with the `type` modifier is acceptable.
Learnt from: VeskeR
PR: ably/ably-js#2052
File: ably.d.ts:2608-2621
Timestamp: 2025-06-27T08:37:06.539Z
Learning: In ably.d.ts, null values are not supported in LiveMap objects. The PrimitiveObjectValue type correctly excludes null even though JsonScalar includes it, as this reflects the intentional design limitation of the LiveMap implementation.
Learnt from: VeskeR
PR: ably/ably-js#1897
File: test/realtime/live_objects.test.js:125-127
Timestamp: 2024-10-22T16:20:01.724Z
Learning: In the file `test/realtime/live_objects.test.js`, the field name `regionalTimeserial` is correct and should not be changed to `timeserial`.
🧬 Code Graph Analysis (2)
src/plugins/objects/objects.ts (2)
src/plugins/objects/livecounter.ts (1)
  • LiveCounter (22-355)
src/plugins/objects/livemap.ts (1)
  • LiveMap (48-909)
src/plugins/objects/liveobject.ts (1)
src/plugins/objects/objectmessage.ts (1)
  • ObjectMessage (356-437)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: test-node (20.x)
  • GitHub Check: test-node (16.x)
  • GitHub Check: test-browser (chromium)
  • GitHub Check: test-node (18.x)
  • GitHub Check: test-browser (firefox)
  • GitHub Check: test-browser (webkit)
  • GitHub Check: test-npm-package
🔇 Additional comments (24)
src/plugins/objects/objectmessage.ts (4)

93-94: LGTM: Consistent addition of serialTimestamp property

The serialTimestamp property is correctly added to the ObjectsMapEntry interface with proper typing and documentation. The comment appropriately indicates it's only present when tombstone is true.


337-337: LGTM: Proper property copying in copyMsg function

The serialTimestamp property is correctly copied in the copyMsg function, maintaining consistency with other properties being copied.


376-377: LGTM: Consistent addition to ObjectMessage class

The serialTimestamp property is properly added to the ObjectMessage class with appropriate typing and documentation indicating its derivation from the serial field.


464-465: LGTM: Consistent addition to WireObjectMessage class

The serialTimestamp property is properly added to the WireObjectMessage class, maintaining consistency with the ObjectMessage class.

test/common/modules/private_api_recorder.js (1)

19-19: LGTM: Proper addition of new private API identifier

The new 'call.LiveObject.tombstonedAt' identifier is correctly added to support testing of the new tombstone timestamp functionality. It follows the established naming pattern for private API identifiers.

src/plugins/objects/objects.ts (3)

403-403: LGTM: Consistent refactor to use ObjectMessage

The change from entry.objectState to entry.objectMessage is correct and aligns with the broader refactor to use ObjectMessage instead of ObjectState. The overrideWithObjectState method signature in the relevant code snippets confirms it now accepts ObjectMessage.


416-416: LGTM: Consistent refactor for LiveCounter creation

The change to use entry.objectMessage is correct and consistent with the LiveCounter.fromObjectState method signature shown in the relevant code snippets, which now accepts ObjectMessage.


420-420: LGTM: Consistent refactor for LiveMap creation

The change to use entry.objectMessage is correct and consistent with the LiveMap.fromObjectState method signature shown in the relevant code snippets, which now accepts ObjectMessage.

test/realtime/objects.test.js (7)

780-780: LGTM: Improved test descriptions for clarity.

The terminology has been updated from "object state 'tombstone' property" to the clearer "tombstone=true" for an object, which better reflects the actual implementation and is more consistent with the codebase terminology.

Also applies to: 834-834, 887-887


940-980: Well-implemented test for serialTimestamp handling in OBJECT_SYNC.

This test thoroughly validates that tombstoned objects created during OBJECT_SYNC sequences properly use the serialTimestamp when provided. The test correctly:

  • Sets up a tombstoned counter with a specific serialTimestamp
  • Accesses private API to verify the object is in the pool
  • Validates the tombstonedAt property matches the provided timestamp

The use of helper.recordPrivateApi() properly documents the private API access.


982-1022: Good fallback test for missing serialTimestamp.

This test appropriately validates the fallback behavior when serialTimestamp is not provided. The timing check using Math.abs(tombstonedAt - Date.now()) < 1000 is reasonable for test stability while still ensuring the local clock is used.


1024-1100: Comprehensive map entry tombstone timestamp tests.

These two test cases properly cover both the main path (with serialTimestamp) and fallback path (without serialTimestamp) for map entry tombstoning during OBJECT_SYNC. The tests correctly access the internal map data structure to verify tombstone state.


1625-1673: Well-structured MAP_REMOVE tombstone timestamp tests.

These tests provide excellent coverage for the MAP_REMOVE operation's tombstone timestamp handling. The pattern of testing both serialTimestamp provided and fallback scenarios is consistent with other similar tests in the suite.


2129-2201: Thorough OBJECT_DELETE tombstone timestamp validation.

The OBJECT_DELETE tests follow the established pattern and properly validate:

  • Object creation and verification before deletion
  • Tombstone state verification after deletion
  • Timestamp handling for both serialTimestamp provided and fallback cases

The tests appropriately use private API access to verify internal object pool state.


1018-1020: Verify timing tolerance is appropriate for test stability.

The 1000ms tolerance for local clock timestamp validation (Math.abs(tombstonedAt - Date.now()) < 1000) appears across multiple tests. While this should be sufficient for normal test execution, consider if this tolerance is appropriate for slower CI environments.

The current tolerance seems reasonable, but monitor for potential flaky test failures if this proves insufficient in practice.

Also applies to: 1096-1098, 1669-1671, 2196-2198

test/common/modules/objects_helper.js (2)

243-249: LGTM! Proper propagation of serialTimestamp.

The method correctly propagates the serialTimestamp field to each object message, maintaining consistency with the existing pattern for serial and siteCode fields.


260-265: LGTM! Consistent handling of serialTimestamp in state messages.

The implementation correctly sets the serialTimestamp on each object message in the state array, which aligns with the PR's objective of propagating server-provided timestamps.

src/plugins/objects/syncobjectsdatapool.ts (1)

3-97: Clean refactor to use ObjectMessage throughout.

The changes correctly update the SyncObjectsDataPool to work with ObjectMessage instead of ObjectState, maintaining the same validation logic while enabling access to additional message fields like serialTimestamp. The error handling and logging remain intact.

src/plugins/objects/livecounter.ts (2)

236-241: Excellent null safety implementation.

The method properly validates the object state existence with a clear error message before proceeding. The tombstone call correctly passes the full objectMessage to enable access to serialTimestamp.

Also applies to: 281-281


39-41: Safe to keep non-null assertion in fromObjectState

The overrideWithObjectState call immediately checks for objectMessage.object == null and throws a clear ErrorInfo if missing, and fromObjectState is only ever invoked for initial state (COUNTER_CREATE) messages where object is guaranteed to exist. No additional null check is needed.

src/plugins/objects/liveobject.ts (1)

154-166: Well-implemented timestamp handling with proper fallback.

The tombstone method correctly prioritizes the server-provided serialTimestamp and falls back to local clock time with appropriate logging. This aligns perfectly with the PR's objective of using server timestamps for tombstone timing.

src/plugins/objects/livemap.ts (3)

736-765: Consistent timestamp handling for map entry removal.

The implementation correctly handles the opTimestamp parameter with proper fallback to local clock and logging. The pattern is consistent with the tombstone handling in LiveObject.


837-850: Proper timestamp initialization for tombstoned map entries.

The implementation correctly sets tombstonedAt from serialTimestamp when creating map data from entries, with consistent fallback and logging behavior.


73-75: Verify non-null assertions in LiveMap.fromObjectState

The objectMessage.object!.map! and objectMessage.object!.objectId assertions in src/plugins/objects/livemap.ts (lines 73–75) mirror those in LiveCounter.fromObjectState, but could throw if object or map is ever undefined. Please ensure that:

  • objectMessage.object and its map field are guaranteed to be populated before calling fromObjectState.
  • You document this invariant in the code or add an explicit runtime check with a clear error if the assertion fails.

Copy link
Contributor

@mschristensen mschristensen left a comment

Choose a reason for hiding this comment

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

Nice, minor suggestion but approving ahead of that :)

@VeskeR VeskeR force-pushed the PUB-1702/objects-server-gc branch from 49ae8c8 to 79c3f75 Compare July 22, 2025 08:11
@VeskeR VeskeR force-pushed the PUB-1837/server-provided-tombstone-timestamp branch from 7356070 to b0ed710 Compare July 22, 2025 08:24
@github-actions github-actions bot temporarily deployed to staging/pull/2054/bundle-report July 22, 2025 08:24 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2054/features July 22, 2025 08:24 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2054/typedoc July 22, 2025 08:24 Inactive
@VeskeR VeskeR force-pushed the PUB-1837/server-provided-tombstone-timestamp branch from b0ed710 to 8313fbe Compare July 22, 2025 08:36
@VeskeR VeskeR changed the base branch from PUB-1702/objects-server-gc to main July 22, 2025 08:37
@github-actions github-actions bot temporarily deployed to staging/pull/2054/bundle-report July 22, 2025 08:37 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2054/features July 22, 2025 08:37 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2054/typedoc July 22, 2025 08:37 Inactive
Use `serialTimestamp` field from ObjectMessage to know when a tombstone
was created for an object or a map entry.

Resolves PUB-1837
@VeskeR VeskeR force-pushed the PUB-1837/server-provided-tombstone-timestamp branch from 8313fbe to 7c7033b Compare July 22, 2025 08:45
@VeskeR VeskeR merged commit 38e5804 into main Jul 22, 2025
12 of 14 checks passed
@VeskeR VeskeR deleted the PUB-1837/server-provided-tombstone-timestamp branch July 22, 2025 09:05
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.

2 participants