Skip to content

Commit de3574f

Browse files
lawrence-forooghianclaude
authored andcommitted
Rework RTLO4f around an explicit graph-theoretic definition
Replace the seven-clause MUST-style spec with four: define a directed graph G over parentReferences, return the *key-paths* corresponding to G's simple paths from root to this LiveObject. The new term *key-path* (matching PathObject's "path" concept) is used here to distinguish from the graph-theoretical "simple path". Edge cases (root, orphan, multi-key, multi-ancestor, cycles) fall out of the definition. There's a tension here: the most universal contract would just say "returns the key-paths from root to this LiveObject" and leave the mechanism to SDK implementers. But any SDK implementing `getFullPaths` will probably want a `parentReferences`-equivalent data structure, and keeping that structure consistent across the many places where `LiveMap.data` is mutated (`MAP_SET`, `MAP_REMOVE`, `MAP_CLEAR`, tombstone, sync rebuild) is the part SDKs are likely to get wrong. The prescriptive `parentReferences`-based formulation pays for itself by making those bookkeeping responsibilities explicit at each mutation site. If we hadn't already specified `parentReferences` and its maintenance, we might not have bothered — but we have, so let's use it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f399e44 commit de3574f

1 file changed

Lines changed: 5 additions & 8 deletions

File tree

specifications/objects-features.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -388,14 +388,11 @@ Objects feature enables clients to store shared data as "objects" on a channel.
388388
- `(RTLO4e6)` Set `LiveObjectUpdate.tombstone` to `true` on the object computed in [RTLO4e5](#RTLO4e5)
389389
- `(RTLO4e7)` Set `LiveObjectUpdate.objectMessage` on the object computed in [RTLO4e5](#RTLO4e5) to the `ObjectMessage` argument
390390
- `(RTLO4e8)` Return the `LiveObjectUpdate` object computed in [RTLO4e5](#RTLO4e5)
391-
- `(RTLO4f)` internal `getFullPaths` function - returns the list of distinct paths from the root `LiveMap` (objectId `root`) to this `LiveObject`, computed by traversing `parentReferences` upward. Each returned path is an ordered sequence of keys from `root` to this `LiveObject`.
392-
- `(RTLO4f1)` `getFullPaths` MUST be implemented as an enumeration of all *simple paths* from this `LiveObject` to the root `LiveMap` over the inverse of the `parentReferences` graph (i.e. walking child → parent). A *simple path* is a path along which no `LiveObject` appears more than once. This is the standard graph problem, typically solved by a depth-first traversal with path-local backtracking equivalent to NetworkX's `all_simple_paths`. Implementation should choose iterative DFS with explicit stack (easier to read and debugging).
393-
- `(RTLO4f2)` If this `LiveObject` is the root `LiveMap` (objectId `root`), the returned list MUST contain exactly one path, and that path MUST be empty (zero key segments). This makes the root reachable from itself via the empty key sequence
394-
- `(RTLO4f3)` If this `LiveObject` is not the root `LiveMap` and has no entries in its `parentReferences` at the time of the call (e.g. orphaned, or not yet reachable from root), the returned list MUST be empty
395-
- `(RTLO4f4)` While traversing paths, suppress cyclic paths whenever a sibling branch had already revisited the same node. Reference behaviour on cyclic graphs is given by NetworkX's `all_simple_paths`, which implementations MAY consult for worked examples
396-
- `(RTLO4f5)` When a single parent `LiveMap` references this `LiveObject` at multiple keys, the returned list MUST contain one distinct path per such key, each ending at the corresponding key
397-
- `(RTLO4f6)` When this `LiveObject` is reachable via multiple distinct ancestor paths (either because it has multiple parents in `parentReferences`, or because any ancestor on the way to root itself has multiple paths to root), the returned list MUST contain one path per distinct ancestor path
398-
- `(RTLO4f7)` The order of paths in the returned list is not mandatory. Implementations MAY return paths in any order; callers requiring a stable order MUST sort the result themselves
391+
- `(RTLO4f)` internal `getFullPaths` function - returns the list of all key-paths from the root `LiveMap` (objectId `root`) to this `LiveObject`. A *key-path* is a list of zero or more keys (the same concept as "path" elsewhere in this spec, e.g. on `PathObject`); we use the term key-path in this clause specifically to distinguish it from the graph-theoretical "simple path" used in [RTLO4f2](#RTLO4f2)
392+
- `(RTLO4f1)` Which key-paths are returned is determined via a directed graph G defined as follows. The nodes of G are the `LiveObject`s in the `ObjectsPool`. For each `(parent, key)` pair recorded in `child`'s `parentReferences` ([RTLO3f](#RTLO3f)), G has a directed edge from `parent` to `child` labelled `key`
393+
- `(RTLO4f2)` A *simple path* in G is a sequence of edges visiting each node at most once. Each such path in G from `root` to this `LiveObject` contributes one key-path to the returned list: the list of its edge labels. The empty simple path (which exists only when this `LiveObject` is itself `root`) contributes the empty key-path `[]`
394+
- `(RTLO4f3)` Each such key-path appears in the returned list exactly once. The order is unspecified
395+
- `(RTLO4f4)` (non-normative) A typical approach is iterative DFS with an explicit stack: walk upward from this `LiveObject` toward `root` via `parentReferences`, collecting keys along the way and skipping branches that would revisit a node
399396
- `(RTLO5)` An `OBJECT_DELETE` operation can be applied to a `LiveObject` in the following way:
400397
- `(RTLO5a)` Expects the following arguments:
401398
- `(RTLO5a1)` `ObjectMessage`

0 commit comments

Comments
 (0)