crdt library in ocaml implementing json-joy
at main 60 kB view raw
1{"id":"automerge-001","title":"Define compatibility scope document","description":"Create a compatibility matrix documenting:\n- All 7 CRDT node types (con, val, obj, vec, arr, str, bin)\n- All 18 patch opcodes\n- CBOR extended types (bytes, undefined, timestamp refs)\n- All codec formats (verbose, compact, binary)\n- ClockVector semantics\n- Session ID conventions (SYSTEM=0, SERVER=1, GLOBAL=2, LOCAL=3)\n\nAcceptance: Written markdown document in docs/compatibility.md","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:45:26.848615499+01:00","updated_at":"2025-12-26T13:55:25.964059551+01:00","closed_at":"2025-12-26T13:55:25.964059551+01:00","labels":["documentation","phase-0"],"dependencies":[{"issue_id":"automerge-001","depends_on_id":"automerge-P0","type":"parent-child","created_at":"2025-12-26T13:51:38.794977801+01:00","created_by":"gdiazlo","metadata":"{}"}]} 2{"id":"automerge-002","title":"Restructure project as 'crdt' library","description":"Rename library from 'automerge' to 'crdt', update dune-project and opam files for OCaml 5.4, set up module structure:\n- lib/crdt.ml (top-level)\n- lib/value/, lib/clock/, lib/patch/, lib/model/, lib/codec/, lib/rx/\n\nAdd dependencies: jsont, jsont.bytesrw\n\nAcceptance: `dune build` succeeds, library exposes Crdt module","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:45:35.486027767+01:00","updated_at":"2025-12-26T14:00:07.738373581+01:00","closed_at":"2025-12-26T14:00:07.738373581+01:00","labels":["phase-0","setup"],"dependencies":[{"issue_id":"automerge-002","depends_on_id":"automerge-001","type":"blocks","created_at":"2025-12-26T11:45:35.491924351+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-002","depends_on_id":"automerge-P0","type":"parent-child","created_at":"2025-12-26T13:51:34.921564823+01:00","created_by":"gdiazlo","metadata":"{}"}]} 3{"id":"automerge-003","title":"Set up CI and test infrastructure","description":"Configure GitHub Actions or similar CI:\n- OCaml 5.4 setup\n- dune build + test\n- Clone json-crdt-traces as test fixtures submodule/dep\n\nAcceptance: CI runs on push, test directory wired up","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-26T11:45:40.507005406+01:00","updated_at":"2025-12-26T11:45:40.507005406+01:00","labels":["ci","phase-0","testing"],"dependencies":[{"issue_id":"automerge-003","depends_on_id":"automerge-002","type":"blocks","created_at":"2025-12-26T11:45:40.513174812+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-003","depends_on_id":"automerge-P0","type":"parent-child","created_at":"2025-12-26T13:51:36.164623987+01:00","created_by":"gdiazlo","metadata":"{}"}]} 4{"id":"automerge-010","title":"Implement Value.t (JSON + CBOR extended types)","description":"Define internal value type supporting JSON + CBOR extensions:\n```ocaml\ntype t =\n | Null\n | Undefined (* CBOR extension *)\n | Bool of bool\n | Int of int\n | Float of float\n | String of string\n | Bytes of bytes (* CBOR extension *)\n | Array of t list\n | Object of (string * t) list\n | Timestamp_ref of Timestamp.t (* for con nodes referencing other nodes *)\n```\n\nImplement equality, comparison, pretty-printing.\n\nAcceptance: Value module with full type + basic operations","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:45:54.67172373+01:00","updated_at":"2025-12-26T14:03:13.20714798+01:00","closed_at":"2025-12-26T14:03:13.20714798+01:00","labels":["core","phase-1","value"],"dependencies":[{"issue_id":"automerge-010","depends_on_id":"automerge-P1","type":"parent-child","created_at":"2025-12-26T13:51:53.285652209+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-010","depends_on_id":"automerge-002","type":"blocks","created_at":"2025-12-26T13:53:31.701837991+01:00","created_by":"gdiazlo","metadata":"{}"}]} 5{"id":"automerge-011","title":"Implement JSON Pointer (RFC 6901)","description":"Implement JSON Pointer parsing, printing, and resolution:\n- Parse \"/foo/0/bar\" style paths\n- Escape handling (~0 for ~, ~1 for /)\n- Resolve pointer against Value.t\n- Build paths programmatically\n\nAcceptance: Pointer module, roundtrip parse/print tests","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:45:57.775816194+01:00","updated_at":"2025-12-26T14:07:33.432863487+01:00","closed_at":"2025-12-26T14:07:33.432863487+01:00","labels":["core","phase-1","pointer"],"dependencies":[{"issue_id":"automerge-011","depends_on_id":"automerge-010","type":"blocks","created_at":"2025-12-26T11:45:57.782308631+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-011","depends_on_id":"automerge-P1","type":"parent-child","created_at":"2025-12-26T13:51:49.374061216+01:00","created_by":"gdiazlo","metadata":"{}"}]} 6{"id":"automerge-012","title":"Implement jsont codec for Value.t","description":"Create Jsont.t codec for Value.t:\n- Handle JSON subset directly\n- Encode bytes as base64 or CBOR tag\n- Encode undefined as null (or custom encoding)\n- Encode timestamp refs appropriately\n\nAcceptance: Roundtrip encode/decode for all value variants","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:46:00.757330503+01:00","updated_at":"2025-12-26T14:12:10.469018679+01:00","closed_at":"2025-12-26T14:12:10.469018679+01:00","labels":["core","jsont","phase-1"],"dependencies":[{"issue_id":"automerge-012","depends_on_id":"automerge-010","type":"blocks","created_at":"2025-12-26T11:46:00.758611059+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-012","depends_on_id":"automerge-P1","type":"parent-child","created_at":"2025-12-26T13:51:50.331560371+01:00","created_by":"gdiazlo","metadata":"{}"}]} 7{"id":"automerge-020","title":"Implement Timestamp and Timespan types","description":"Implement logical timestamp types matching json-joy:\n```ocaml\ntype timestamp = { sid: int; time: int }\ntype timespan = { sid: int; time: int; span: int }\n```\n\nFunctions: compare, equal, contains, contains_id, tick, interval, print_ts\n\nAcceptance: Timestamp module with full API matching clock/types.ts","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:46:04.173967202+01:00","updated_at":"2025-12-26T14:12:52.627454164+01:00","closed_at":"2025-12-26T14:12:52.627454164+01:00","labels":["clock","core","phase-1"],"dependencies":[{"issue_id":"automerge-020","depends_on_id":"automerge-P1","type":"parent-child","created_at":"2025-12-26T13:51:56.643178664+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-020","depends_on_id":"automerge-002","type":"blocks","created_at":"2025-12-26T13:53:36.749228296+01:00","created_by":"gdiazlo","metadata":"{}"}]} 8{"id":"automerge-021","title":"Implement LogicalClock and ClockVector","description":"Implement clock types:\n- LogicalClock: single session clock with tick()\n- ClockVector: local clock + peers map, observe(), clone(), fork()\n- ServerClockVector: fixed session ID variant\n\nMatch semantics from json-joy clock/clock.ts exactly.\n\nAcceptance: Clock module, vector clock convergence tests","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:46:07.700083537+01:00","updated_at":"2025-12-26T14:13:18.09296712+01:00","closed_at":"2025-12-26T14:13:18.09296712+01:00","labels":["clock","core","phase-1"],"dependencies":[{"issue_id":"automerge-021","depends_on_id":"automerge-020","type":"blocks","created_at":"2025-12-26T11:46:07.706097752+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-021","depends_on_id":"automerge-P1","type":"parent-child","created_at":"2025-12-26T13:51:52.547235605+01:00","created_by":"gdiazlo","metadata":"{}"}]} 9{"id":"automerge-022","title":"Implement Session ID constants and validation","description":"Define session ID constants matching json-joy:\n- SYSTEM = 0 (reserved)\n- SERVER = 1 (server clock mode)\n- GLOBAL = 2 (schema/initial patches)\n- LOCAL = 3 (local-only data)\n- MAX = 9007199254740991 (53-bit limit)\n\nValidation functions for session ID ranges.\n\nAcceptance: Session module with constants and validators","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:46:10.853587622+01:00","updated_at":"2025-12-26T14:13:23.137020547+01:00","closed_at":"2025-12-26T14:13:23.137020547+01:00","labels":["clock","core","phase-1"],"dependencies":[{"issue_id":"automerge-022","depends_on_id":"automerge-020","type":"blocks","created_at":"2025-12-26T11:46:10.859673977+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-022","depends_on_id":"automerge-P1","type":"parent-child","created_at":"2025-12-26T13:51:53.52141741+01:00","created_by":"gdiazlo","metadata":"{}"}]} 10{"id":"automerge-030","title":"Implement all 18 patch operation types","description":"Define all patch operations matching json-joy operations.ts:\n\nCreation ops: new_con, new_val, new_obj, new_vec, new_str, new_bin, new_arr\nEdit ops: ins_val, ins_obj, ins_vec, ins_str, ins_bin, ins_arr, upd_arr\nOther: del, nop\n\nEach op has:\n- id: timestamp\n- span(): int (for compound ops)\n- name(): string\n\nAcceptance: Op module with all 18 types, pretty-printing","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:46:31.112040136+01:00","updated_at":"2025-12-26T14:57:19.474370047+01:00","closed_at":"2025-12-26T14:57:19.474370047+01:00","labels":["operations","patch","phase-2"],"dependencies":[{"issue_id":"automerge-030","depends_on_id":"automerge-020","type":"blocks","created_at":"2025-12-26T11:46:31.118482093+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-030","depends_on_id":"automerge-010","type":"blocks","created_at":"2025-12-26T11:46:31.119174986+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-030","depends_on_id":"automerge-P2","type":"parent-child","created_at":"2025-12-26T13:52:09.879351386+01:00","created_by":"gdiazlo","metadata":"{}"}]} 11{"id":"automerge-031","title":"Implement Patch container and Batch","description":"Implement Patch.t containing:\n- id: starting timestamp\n- ops: operation list\n- span(): total span\n- Iteration, rebase, transformation utilities\n\nAlso implement Batch for multiple patches.\n\nAcceptance: Patch module matching Patch.ts behavior","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:46:35.513606123+01:00","updated_at":"2025-12-26T15:04:58.03625984+01:00","closed_at":"2025-12-26T15:04:58.03625984+01:00","labels":["patch","phase-2"],"dependencies":[{"issue_id":"automerge-031","depends_on_id":"automerge-030","type":"blocks","created_at":"2025-12-26T11:46:35.514822868+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-031","depends_on_id":"automerge-P2","type":"parent-child","created_at":"2025-12-26T13:52:14.923587649+01:00","created_by":"gdiazlo","metadata":"{}"}]} 12{"id":"automerge-032","title":"Implement Patch_builder API","description":"Implement builder for constructing patches ergonomically:\n- new_con, new_str, etc. methods\n- Automatic ID assignment from clock\n- flush() to emit completed Patch\n\nMatch PatchBuilder.ts API.\n\nAcceptance: Builder module, example patch construction tests","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:46:40.536544174+01:00","updated_at":"2025-12-26T15:04:59.513747889+01:00","closed_at":"2025-12-26T15:04:59.513747889+01:00","labels":["builder","patch","phase-2"],"dependencies":[{"issue_id":"automerge-032","depends_on_id":"automerge-031","type":"blocks","created_at":"2025-12-26T11:46:40.54263163+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-032","depends_on_id":"automerge-021","type":"blocks","created_at":"2025-12-26T11:46:40.543265872+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-032","depends_on_id":"automerge-P2","type":"parent-child","created_at":"2025-12-26T13:52:19.96709866+01:00","created_by":"gdiazlo","metadata":"{}"}]} 13{"id":"automerge-033","title":"Implement verbose JSON codec for patches","description":"Implement human-readable JSON encoding for patches matching json-joy verbose format:\n- Each op as JSON object with type field\n- Timestamps as [sid, time] arrays\n- Full decode/encode roundtrip\n\nAcceptance: Verbose codec, matches patches.verbose.json from traces","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:46:42.224847636+01:00","updated_at":"2025-12-26T15:07:19.576373031+01:00","closed_at":"2025-12-26T15:07:19.576373031+01:00","labels":["codec","patch","phase-2"],"dependencies":[{"issue_id":"automerge-033","depends_on_id":"automerge-031","type":"blocks","created_at":"2025-12-26T11:46:42.230845631+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-033","depends_on_id":"automerge-012","type":"blocks","created_at":"2025-12-26T11:46:42.231459334+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-033","depends_on_id":"automerge-P2","type":"parent-child","created_at":"2025-12-26T13:52:25.004140186+01:00","created_by":"gdiazlo","metadata":"{}"}]} 14{"id":"automerge-034","title":"Implement compact JSON codec for patches","description":"Implement compact array-based JSON encoding:\n- Ops as arrays [opcode, ...]\n- Delta-encoded timestamps where possible\n- Smaller than verbose, still JSON\n\nAcceptance: Compact codec, matches patches.compact.json from traces","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:46:43.711008958+01:00","updated_at":"2025-12-26T16:16:54.975710531+01:00","closed_at":"2025-12-26T16:16:54.975710531+01:00","labels":["codec","patch","phase-2"],"dependencies":[{"issue_id":"automerge-034","depends_on_id":"automerge-033","type":"blocks","created_at":"2025-12-26T11:46:43.716604731+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-034","depends_on_id":"automerge-P2","type":"parent-child","created_at":"2025-12-26T13:52:30.049857021+01:00","created_by":"gdiazlo","metadata":"{}"}]} 15{"id":"automerge-035","title":"Implement binary codec for patches","description":"Implement CBOR/MessagePack-based binary encoding:\n- Opcode byte + varint encoded fields\n- Efficient for wire transfer\n- Match json-joy binary format exactly\n\nAcceptance: Binary codec, matches patches.bin from traces (byte-for-byte)","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:46:44.812938641+01:00","updated_at":"2025-12-26T16:48:43.308157255+01:00","closed_at":"2025-12-26T16:48:43.308157255+01:00","labels":["binary","codec","patch","phase-2"],"dependencies":[{"issue_id":"automerge-035","depends_on_id":"automerge-034","type":"blocks","created_at":"2025-12-26T11:46:44.819223527+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-035","depends_on_id":"automerge-P2","type":"parent-child","created_at":"2025-12-26T13:52:35.094416882+01:00","created_by":"gdiazlo","metadata":"{}"}]} 16{"id":"automerge-040","title":"Implement CRDT node type definitions","description":"Define node type interface and all 7 concrete types:\n- con: constant/immutable value\n- val: mutable reference to another node\n- obj: mutable string-keyed map\n- vec: mutable indexed tuple (0-255)\n- arr: mutable ordered list (RGA)\n- str: mutable text string (RGA)\n- bin: mutable binary data (RGA)\n\nEach node has: id, name(), view(), children()\n\nAcceptance: Node module with all type definitions","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:46:58.811796737+01:00","updated_at":"2025-12-26T15:12:36.070523402+01:00","closed_at":"2025-12-26T15:12:36.070523402+01:00","labels":["model","nodes","phase-3"],"dependencies":[{"issue_id":"automerge-040","depends_on_id":"automerge-020","type":"blocks","created_at":"2025-12-26T11:46:58.817889283+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-040","depends_on_id":"automerge-010","type":"blocks","created_at":"2025-12-26T11:46:58.818602755+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-040","depends_on_id":"automerge-P3","type":"parent-child","created_at":"2025-12-26T13:52:12.302450996+01:00","created_by":"gdiazlo","metadata":"{}"}]} 17{"id":"automerge-041","title":"Implement RGA (Replicated Growable Array) core","description":"Implement RGA data structure for str, bin, arr nodes:\n- Chunks with IDs and spans\n- Insert after reference ID\n- Delete by ID range\n- Deterministic ordering by timestamp comparison\n- Tombstone handling\n\nMatch json-joy RGA implementation for convergence.\n\nAcceptance: Rga module, concurrent edit convergence tests","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:02.005895033+01:00","updated_at":"2025-12-26T15:24:42.189226683+01:00","closed_at":"2025-12-26T15:24:42.189226683+01:00","labels":["model","phase-3","rga"],"dependencies":[{"issue_id":"automerge-041","depends_on_id":"automerge-040","type":"blocks","created_at":"2025-12-26T11:47:02.012018318+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-041","depends_on_id":"automerge-P3","type":"parent-child","created_at":"2025-12-26T13:52:17.348444487+01:00","created_by":"gdiazlo","metadata":"{}"}]} 18{"id":"automerge-042","title":"Implement con, val, obj, vec node types","description":"Full implementation of non-RGA nodes:\n- con: holds immutable Value.t or timestamp ref\n- val: LWW register pointing to another node\n- obj: map with LWW per key\n- vec: fixed-size tuple (max 256 slots)\n\nAcceptance: All 4 node types with view() and mutation ops","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:47:05.089895731+01:00","updated_at":"2025-12-26T15:25:57.304303269+01:00","closed_at":"2025-12-26T15:25:57.304303269+01:00","labels":["model","nodes","phase-3"],"dependencies":[{"issue_id":"automerge-042","depends_on_id":"automerge-040","type":"blocks","created_at":"2025-12-26T11:47:05.096045876+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-042","depends_on_id":"automerge-P3","type":"parent-child","created_at":"2025-12-26T13:52:22.393831497+01:00","created_by":"gdiazlo","metadata":"{}"}]} 19{"id":"automerge-043","title":"Implement str, bin, arr node types using RGA","description":"Full implementation of RGA-based nodes:\n- str: text string with character-level edits\n- bin: binary data with byte-level edits\n- arr: array with element-level edits + updates\n\nEach wraps Rga with type-specific view().\n\nAcceptance: All 3 RGA nodes, concurrent edit tests","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:47:07.9241064+01:00","updated_at":"2025-12-26T15:25:19.669552876+01:00","closed_at":"2025-12-26T15:25:19.669552876+01:00","labels":["model","nodes","phase-3","rga"],"dependencies":[{"issue_id":"automerge-043","depends_on_id":"automerge-041","type":"blocks","created_at":"2025-12-26T11:47:07.930346926+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-043","depends_on_id":"automerge-P3","type":"parent-child","created_at":"2025-12-26T13:52:27.438194425+01:00","created_by":"gdiazlo","metadata":"{}"}]} 20{"id":"automerge-044","title":"Implement Model container","description":"Implement Model.t document container:\n- clock: ClockVector\n- root: root node (val pointing to document)\n- index: map from timestamp to node\n- view(): materialize JSON view\n- fork(): create independent replica\n\nAcceptance: Model module, basic document creation/view","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:11.267243926+01:00","updated_at":"2025-12-26T15:28:46.660993947+01:00","closed_at":"2025-12-26T15:28:46.660993947+01:00","labels":["model","phase-3"],"dependencies":[{"issue_id":"automerge-044","depends_on_id":"automerge-042","type":"blocks","created_at":"2025-12-26T11:47:11.272834999+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-044","depends_on_id":"automerge-043","type":"blocks","created_at":"2025-12-26T11:47:11.273542902+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-044","depends_on_id":"automerge-021","type":"blocks","created_at":"2025-12-26T11:47:11.274091894+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-044","depends_on_id":"automerge-P3","type":"parent-child","created_at":"2025-12-26T13:52:32.485326356+01:00","created_by":"gdiazlo","metadata":"{}"}]} 21{"id":"automerge-045","title":"Implement patch application","description":"Implement Model.apply(patch) to apply patches:\n- Process each operation in order\n- Create nodes for new_* ops\n- Apply edits for ins_*/del/upd_* ops\n- Update clock via observe()\n- Deterministic merge semantics\n\nAcceptance: Apply patches from traces, correct final state","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:14.493281805+01:00","updated_at":"2025-12-26T15:43:38.371642388+01:00","closed_at":"2025-12-26T15:43:38.371642388+01:00","labels":["model","patch","phase-3"],"dependencies":[{"issue_id":"automerge-045","depends_on_id":"automerge-044","type":"blocks","created_at":"2025-12-26T11:47:14.49934772+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-045","depends_on_id":"automerge-031","type":"blocks","created_at":"2025-12-26T11:47:14.500077243+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-045","depends_on_id":"automerge-P3","type":"parent-child","created_at":"2025-12-26T13:52:37.530383611+01:00","created_by":"gdiazlo","metadata":"{}"}]} 22{"id":"automerge-046","title":"Implement Model_api high-level editing interface","description":"Implement user-friendly editing API:\n- Path-based access (api.obj(\"/foo/bar\"))\n- Transaction support\n- Auto-flush buffered operations\n- Event hooks (onChange, onPatch, etc.)\n\nMatch ModelApi.ts interface.\n\nAcceptance: Api module, ergonomic editing examples","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:17.49001233+01:00","updated_at":"2025-12-26T16:03:50.115595752+01:00","closed_at":"2025-12-26T16:03:50.115595752+01:00","labels":["api","model","phase-3"],"dependencies":[{"issue_id":"automerge-046","depends_on_id":"automerge-045","type":"blocks","created_at":"2025-12-26T11:47:17.496337546+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-046","depends_on_id":"automerge-032","type":"blocks","created_at":"2025-12-26T11:47:17.497024779+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-046","depends_on_id":"automerge-P3","type":"parent-child","created_at":"2025-12-26T13:52:42.577207135+01:00","created_by":"gdiazlo","metadata":"{}"}]} 23{"id":"automerge-050","title":"Implement sidecar document codec","description":"Implement sidecar encoding for document snapshots:\n- View encoded as plain JSON/CBOR\n- CRDT metadata in separate blob\n- Path-based node references\n\nGood for compatibility with non-CRDT systems.\n\nAcceptance: Sidecar codec, roundtrip tests","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:30.605318286+01:00","updated_at":"2025-12-26T22:10:02.227569165+01:00","closed_at":"2025-12-26T22:10:02.227569165+01:00","labels":["codec","phase-4","snapshot"],"dependencies":[{"issue_id":"automerge-050","depends_on_id":"automerge-044","type":"blocks","created_at":"2025-12-26T11:47:30.606875283+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-050","depends_on_id":"automerge-011","type":"blocks","created_at":"2025-12-26T11:47:30.607702686+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-050","depends_on_id":"automerge-P4","type":"parent-child","created_at":"2025-12-26T13:52:13.371558762+01:00","created_by":"gdiazlo","metadata":"{}"}]} 24{"id":"automerge-051","title":"Implement verbose structural document codec","description":"Implement verbose JSON structural encoding:\n- Hierarchical tree structure\n- Each node as JSON object with type, id, children\n- Human-readable for debugging\n\nAcceptance: Matches model.verbose.json from traces","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:32.942205277+01:00","updated_at":"2025-12-26T18:07:36.930486642+01:00","closed_at":"2025-12-26T18:07:36.930486642+01:00","labels":["codec","phase-4","snapshot"],"dependencies":[{"issue_id":"automerge-051","depends_on_id":"automerge-044","type":"blocks","created_at":"2025-12-26T11:47:32.948674214+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-051","depends_on_id":"automerge-012","type":"blocks","created_at":"2025-12-26T11:47:32.949556938+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-051","depends_on_id":"automerge-P4","type":"parent-child","created_at":"2025-12-26T13:52:18.414946482+01:00","created_by":"gdiazlo","metadata":"{}"}]} 25{"id":"automerge-052","title":"Implement compact structural document codec","description":"Implement compact JSON structural encoding:\n- Array-based representation\n- Smaller than verbose\n\nAcceptance: Matches model.compact.json from traces","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:34.230145185+01:00","updated_at":"2025-12-26T18:39:51.088684941+01:00","closed_at":"2025-12-26T18:39:51.088684941+01:00","labels":["codec","phase-4","snapshot"],"dependencies":[{"issue_id":"automerge-052","depends_on_id":"automerge-051","type":"blocks","created_at":"2025-12-26T11:47:34.236347491+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-052","depends_on_id":"automerge-P4","type":"parent-child","created_at":"2025-12-26T13:52:23.452799201+01:00","created_by":"gdiazlo","metadata":"{}"}]} 26{"id":"automerge-053","title":"Implement binary structural document codec","description":"Implement binary structural encoding:\n- CBOR-based wire format\n- Efficient for storage/transfer\n\nAcceptance: Matches model.bin from traces (byte-for-byte)","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:36.243234539+01:00","updated_at":"2025-12-26T19:08:51.026767464+01:00","closed_at":"2025-12-26T19:08:51.026767464+01:00","labels":["binary","codec","phase-4","snapshot"],"dependencies":[{"issue_id":"automerge-053","depends_on_id":"automerge-052","type":"blocks","created_at":"2025-12-26T11:47:36.244781466+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-053","depends_on_id":"automerge-P4","type":"parent-child","created_at":"2025-12-26T13:52:28.498378794+01:00","created_by":"gdiazlo","metadata":"{}"}]} 27{"id":"automerge-054","title":"Implement indexed document codec","description":"Implement indexed/flat map encoding:\n- Nodes as flat map keyed by timestamp\n- Good for incremental sync\n\nAcceptance: Indexed codec, roundtrip tests","status":"closed","priority":2,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:38.266349725+01:00","updated_at":"2025-12-26T22:18:03.555502439+01:00","closed_at":"2025-12-26T22:18:03.555502439+01:00","labels":["codec","phase-4","snapshot"],"dependencies":[{"issue_id":"automerge-054","depends_on_id":"automerge-051","type":"blocks","created_at":"2025-12-26T11:47:38.272208229+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-054","depends_on_id":"automerge-P4","type":"parent-child","created_at":"2025-12-26T13:52:33.542756005+01:00","created_by":"gdiazlo","metadata":"{}"}]} 28{"id":"automerge-060","title":"Define IO effect signatures","description":"Define OCaml 5.4 effect signatures for IO operations:\n```ocaml\ntype _ Effect.t +=\n | Read_bytes : int -\u003e bytes Effect.t\n | Write_bytes : bytes -\u003e unit Effect.t\n | Yield : unit Effect.t\n```\n\nThis allows codec implementations to be IO-library agnostic.\n\nAcceptance: Io_intf module with effect definitions","status":"closed","priority":2,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:51.297003032+01:00","updated_at":"2025-12-26T20:52:57.819458688+01:00","closed_at":"2025-12-26T20:52:57.819458688+01:00","labels":["effects","io","phase-5"],"dependencies":[{"issue_id":"automerge-060","depends_on_id":"automerge-P5","type":"parent-child","created_at":"2025-12-26T13:52:20.00268744+01:00","created_by":"gdiazlo","metadata":"{}"}]} 29{"id":"automerge-061","title":"Implement Eio effect handler","description":"Implement effect handler for Eio:\n- Map Read_bytes/Write_bytes to Eio.Flow operations\n- Proper fiber integration\n\nAcceptance: Io_eio module, works with Eio scheduler","status":"closed","priority":2,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:53.58006397+01:00","updated_at":"2025-12-26T23:04:06.881031909+01:00","closed_at":"2025-12-26T23:04:06.881031909+01:00","labels":["effects","eio","io","phase-5"],"dependencies":[{"issue_id":"automerge-061","depends_on_id":"automerge-060","type":"blocks","created_at":"2025-12-26T11:47:53.586155425+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-061","depends_on_id":"automerge-P5","type":"parent-child","created_at":"2025-12-26T13:52:25.039942597+01:00","created_by":"gdiazlo","metadata":"{}"}]} 30{"id":"automerge-062","title":"Implement Lwt effect handler","description":"Implement effect handler for Lwt:\n- Bridge effects to Lwt promises\n- Use Lwt_eio or direct integration\n\nAcceptance: Io_lwt module, works with Lwt scheduler","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-26T11:47:55.570931472+01:00","updated_at":"2025-12-26T11:47:55.570931472+01:00","labels":["effects","io","lwt","phase-5"],"dependencies":[{"issue_id":"automerge-062","depends_on_id":"automerge-060","type":"blocks","created_at":"2025-12-26T11:47:55.576720766+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-062","depends_on_id":"automerge-P5","type":"parent-child","created_at":"2025-12-26T13:52:30.078688282+01:00","created_by":"gdiazlo","metadata":"{}"}]} 31{"id":"automerge-063","title":"Implement direct/blocking effect handler","description":"Implement simple blocking effect handler:\n- Direct Unix read/write\n- For CLI tools and simple scripts\n\nAcceptance: Io_unix module, basic blocking IO","status":"closed","priority":2,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:47:57.720040452+01:00","updated_at":"2025-12-26T22:13:14.217567021+01:00","closed_at":"2025-12-26T22:13:14.217567021+01:00","labels":["effects","io","phase-5"],"dependencies":[{"issue_id":"automerge-063","depends_on_id":"automerge-060","type":"blocks","created_at":"2025-12-26T11:47:57.725896017+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-063","depends_on_id":"automerge-P5","type":"parent-child","created_at":"2025-12-26T13:52:35.117438889+01:00","created_by":"gdiazlo","metadata":"{}"}]} 32{"id":"automerge-070","title":"Implement JSON-Rx message types","description":"Define JSON Reactive RPC message types:\n- request: {id, method, data}\n- response: {id, data} or {id, error}\n- notification: {method, data}\n- subscribe: {id, channel}\n- unsubscribe: {id}\n- data: {id, data} (subscription data)\n- complete: {id}\n- error: {id, error}\n\nAcceptance: Rx_message module with all types","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:48:12.176526547+01:00","updated_at":"2025-12-26T20:30:06.699943128+01:00","closed_at":"2025-12-26T20:30:06.699943128+01:00","labels":["json-rx","phase-6","rpc"],"dependencies":[{"issue_id":"automerge-070","depends_on_id":"automerge-010","type":"blocks","created_at":"2025-12-26T11:48:12.181829019+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-070","depends_on_id":"automerge-P6","type":"parent-child","created_at":"2025-12-26T13:52:15.793020025+01:00","created_by":"gdiazlo","metadata":"{}"}]} 33{"id":"automerge-071","title":"Implement JSON-Rx message codecs","description":"Implement encode/decode for JSON-Rx messages:\n- JSON codec (verbose)\n- Binary codec (CBOR-based)\n- Framing for streams (length-prefixed)\n\nAcceptance: Rx_codec module, roundtrip tests","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:48:14.580803869+01:00","updated_at":"2025-12-26T20:48:14.709462476+01:00","closed_at":"2025-12-26T20:48:14.709462476+01:00","labels":["codec","json-rx","phase-6","rpc"],"dependencies":[{"issue_id":"automerge-071","depends_on_id":"automerge-070","type":"blocks","created_at":"2025-12-26T11:48:14.586685554+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-071","depends_on_id":"automerge-012","type":"blocks","created_at":"2025-12-26T11:48:14.587458337+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-071","depends_on_id":"automerge-P6","type":"parent-child","created_at":"2025-12-26T13:52:20.835488113+01:00","created_by":"gdiazlo","metadata":"{}"}]} 34{"id":"automerge-072","title":"Implement JSON-Rx server router/dispatcher","description":"Implement server-side RPC infrastructure:\n- Method registration\n- Request routing\n- Subscription management\n- Response/error handling\n- Uses effects for transport abstraction\n\nAcceptance: Rx_server module, echo server example","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:48:17.122433073+01:00","updated_at":"2025-12-26T20:56:11.786870583+01:00","closed_at":"2025-12-26T20:56:11.786870583+01:00","labels":["json-rx","phase-6","rpc","server"],"dependencies":[{"issue_id":"automerge-072","depends_on_id":"automerge-071","type":"blocks","created_at":"2025-12-26T11:48:17.128444968+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-072","depends_on_id":"automerge-060","type":"blocks","created_at":"2025-12-26T11:48:17.129165031+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-072","depends_on_id":"automerge-P6","type":"parent-child","created_at":"2025-12-26T13:52:25.880762844+01:00","created_by":"gdiazlo","metadata":"{}"}]} 35{"id":"automerge-073","title":"Implement JSON-Rx client","description":"Implement client-side RPC infrastructure:\n- Request/response correlation\n- Subscription callbacks\n- Automatic reconnection (optional)\n- Uses effects for transport abstraction\n\nAcceptance: Rx_client module, connects to Rx_server","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:48:19.170175203+01:00","updated_at":"2025-12-26T21:00:14.887998998+01:00","closed_at":"2025-12-26T21:00:14.887998998+01:00","labels":["client","json-rx","phase-6","rpc"],"dependencies":[{"issue_id":"automerge-073","depends_on_id":"automerge-071","type":"blocks","created_at":"2025-12-26T11:48:19.176314638+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-073","depends_on_id":"automerge-060","type":"blocks","created_at":"2025-12-26T11:48:19.176997021+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-073","depends_on_id":"automerge-P6","type":"parent-child","created_at":"2025-12-26T13:52:30.927145741+01:00","created_by":"gdiazlo","metadata":"{}"}]} 36{"id":"automerge-074","title":"Implement CRDT sync protocol over JSON-Rx","description":"Implement document sync using JSON-Rx:\n- Subscribe to document changes\n- Send/receive patches\n- Initial sync (snapshot + patches)\n- Conflict-free merge\n\nAcceptance: Sync module, two-replica sync demo","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:48:21.692664467+01:00","updated_at":"2025-12-26T21:47:53.905160333+01:00","closed_at":"2025-12-26T21:47:53.905160333+01:00","labels":["json-rx","phase-6","rpc","sync"],"dependencies":[{"issue_id":"automerge-074","depends_on_id":"automerge-072","type":"blocks","created_at":"2025-12-26T11:48:21.699973097+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-074","depends_on_id":"automerge-073","type":"blocks","created_at":"2025-12-26T11:48:21.700903581+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-074","depends_on_id":"automerge-045","type":"blocks","created_at":"2025-12-26T11:48:21.701505524+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-074","depends_on_id":"automerge-P6","type":"parent-child","created_at":"2025-12-26T13:52:35.972660107+01:00","created_by":"gdiazlo","metadata":"{}"}]} 37{"id":"automerge-080","title":"Implement counter extension (cnt)","description":"Implement PN-counter CRDT extension:\n- Built on vec node\n- Increment/decrement operations\n- Convergent counter value\n\nAcceptance: Counter module, concurrent increment test","status":"closed","priority":2,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:48:34.45173157+01:00","updated_at":"2025-12-26T22:30:37.530007794+01:00","closed_at":"2025-12-26T22:30:37.530007794+01:00","labels":["counter","extensions","phase-7"],"dependencies":[{"issue_id":"automerge-080","depends_on_id":"automerge-046","type":"blocks","created_at":"2025-12-26T11:48:34.457733185+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-080","depends_on_id":"automerge-P7","type":"parent-child","created_at":"2025-12-26T13:52:16.507061338+01:00","created_by":"gdiazlo","metadata":"{}"}]} 38{"id":"automerge-081","title":"Implement multi-value register extension (mval)","description":"Implement multi-value register:\n- All concurrent writes visible\n- Built on arr node\n- Explicit conflict resolution\n\nAcceptance: Mval module, concurrent write visibility test","status":"closed","priority":2,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:48:36.587554226+01:00","updated_at":"2025-12-26T23:04:06.035660088+01:00","closed_at":"2025-12-26T23:04:06.035660088+01:00","labels":["extensions","mval","phase-7"],"dependencies":[{"issue_id":"automerge-081","depends_on_id":"automerge-046","type":"blocks","created_at":"2025-12-26T11:48:36.59347269+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-081","depends_on_id":"automerge-P7","type":"parent-child","created_at":"2025-12-26T13:52:21.551122043+01:00","created_by":"gdiazlo","metadata":"{}"}]} 39{"id":"automerge-082","title":"Implement peritext rich text extension","description":"Implement peritext for rich text editing:\n- Text stored in str node\n- Annotations (bold, italic, etc.) as markers\n- Range-based formatting\n- Quill Delta compatible view\n\nAcceptance: Peritext module, basic formatting test","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-26T11:48:39.372259662+01:00","updated_at":"2025-12-26T11:48:39.372259662+01:00","labels":["extensions","peritext","phase-7","rich-text"],"dependencies":[{"issue_id":"automerge-082","depends_on_id":"automerge-043","type":"blocks","created_at":"2025-12-26T11:48:39.378516298+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-082","depends_on_id":"automerge-046","type":"blocks","created_at":"2025-12-26T11:48:39.3792458+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-082","depends_on_id":"automerge-P7","type":"parent-child","created_at":"2025-12-26T13:52:26.596108133+01:00","created_by":"gdiazlo","metadata":"{}"}]} 40{"id":"automerge-090","title":"Integrate json-crdt-traces as test fixtures","description":"Set up json-crdt-traces repository as test fixture source:\n- Git submodule or download script\n- Loader for trace files (patches.*, model.*, view.*)\n- Support for text, json, rich-text, fuzzer traces\n\nReference: https://github.com/streamich/json-crdt-traces\n\nAcceptance: Traces available in test/fixtures/","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:48:53.152941737+01:00","updated_at":"2025-12-26T17:00:31.273083747+01:00","closed_at":"2025-12-26T17:00:31.273083747+01:00","labels":["fixtures","phase-8","testing"],"dependencies":[{"issue_id":"automerge-090","depends_on_id":"automerge-003","type":"blocks","created_at":"2025-12-26T11:48:53.159115673+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-090","depends_on_id":"automerge-P8","type":"parent-child","created_at":"2025-12-26T13:52:17.477203588+01:00","created_by":"gdiazlo","metadata":"{}"}]} 41{"id":"automerge-091","title":"Implement patch codec conformance tests","description":"Test patch codecs against json-crdt-traces:\n- Load patches.verbose.json, patches.compact.json, patches.bin\n- Decode each format\n- Re-encode and compare (roundtrip)\n- Binary format byte-for-byte match\n\nAcceptance: All trace patch files decode/encode correctly","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-26T11:48:56.245202063+01:00","updated_at":"2025-12-26T17:00:33.339965822+01:00","closed_at":"2025-12-26T17:00:33.339965822+01:00","labels":["conformance","patch","phase-8","testing"],"dependencies":[{"issue_id":"automerge-091","depends_on_id":"automerge-090","type":"blocks","created_at":"2025-12-26T11:48:56.246588479+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-091","depends_on_id":"automerge-035","type":"blocks","created_at":"2025-12-26T11:48:56.247630493+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-091","depends_on_id":"automerge-P8","type":"parent-child","created_at":"2025-12-26T13:52:22.51572169+01:00","created_by":"gdiazlo","metadata":"{}"}]} 42{"id":"automerge-092","title":"Implement model codec conformance tests","description":"Test document codecs against json-crdt-traces:\n- Load model.verbose.json, model.compact.json, model.bin\n- Decode each format\n- Verify view matches view.json\n- Re-encode and compare\n\nAcceptance: All trace model files decode/encode correctly","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:48:58.347041938+01:00","updated_at":"2025-12-26T19:18:49.05459426+01:00","closed_at":"2025-12-26T19:18:49.05459426+01:00","labels":["conformance","model","phase-8","testing"],"dependencies":[{"issue_id":"automerge-092","depends_on_id":"automerge-090","type":"blocks","created_at":"2025-12-26T11:48:58.353314374+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-092","depends_on_id":"automerge-053","type":"blocks","created_at":"2025-12-26T11:48:58.354103597+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-092","depends_on_id":"automerge-P8","type":"parent-child","created_at":"2025-12-26T13:52:27.556789084+01:00","created_by":"gdiazlo","metadata":"{}"}]} 43{"id":"automerge-093","title":"Implement patch application conformance tests","description":"Test patch application produces correct results:\n- Start with empty model\n- Apply all patches from trace\n- Compare final view to view.json\n- Test all trace categories (text, json, rich-text)\n\nAcceptance: All traces produce expected final views","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:49:00.930625477+01:00","updated_at":"2025-12-26T17:20:51.962470449+01:00","closed_at":"2025-12-26T17:20:51.962470449+01:00","labels":["conformance","phase-8","testing"],"dependencies":[{"issue_id":"automerge-093","depends_on_id":"automerge-091","type":"blocks","created_at":"2025-12-26T11:49:00.932421995+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-093","depends_on_id":"automerge-045","type":"blocks","created_at":"2025-12-26T11:49:00.933266938+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-093","depends_on_id":"automerge-P8","type":"parent-child","created_at":"2025-12-26T13:52:32.596364033+01:00","created_by":"gdiazlo","metadata":"{}"}]} 44{"id":"automerge-094","title":"Implement replica convergence tests","description":"Test that replicas converge regardless of apply order:\n- Create multiple replicas\n- Apply patches in different orders\n- Verify all replicas have identical final state\n- Test concurrent edits on different replicas\n\nAcceptance: Convergence tests pass for all node types","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:49:03.348649768+01:00","updated_at":"2025-12-26T19:23:25.34783506+01:00","closed_at":"2025-12-26T19:23:25.34783506+01:00","labels":["convergence","phase-8","testing"],"dependencies":[{"issue_id":"automerge-094","depends_on_id":"automerge-093","type":"blocks","created_at":"2025-12-26T11:49:03.354851804+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-094","depends_on_id":"automerge-P8","type":"parent-child","created_at":"2025-12-26T13:52:37.635375692+01:00","created_by":"gdiazlo","metadata":"{}"}]} 45{"id":"automerge-095","title":"Implement fuzzer for CRDT operations","description":"Port json-joy fuzzer to OCaml:\n- Random operation generation\n- Multiple concurrent sessions\n- Verify convergence after random operations\n- Verify codec roundtrips\n\nReference: json-joy __tests__/fuzzer/\n\nAcceptance: Fuzzer runs without failures, generates traces","status":"closed","priority":1,"issue_type":"task","assignee":"claude","created_at":"2025-12-26T11:49:06.406644582+01:00","updated_at":"2025-12-26T20:26:58.684450402+01:00","closed_at":"2025-12-26T20:26:58.684450402+01:00","labels":["fuzzer","phase-8","testing"],"dependencies":[{"issue_id":"automerge-095","depends_on_id":"automerge-094","type":"blocks","created_at":"2025-12-26T11:49:06.412500806+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-095","depends_on_id":"automerge-P8","type":"parent-child","created_at":"2025-12-26T13:52:42.676637453+01:00","created_by":"gdiazlo","metadata":"{}"}]} 46{"id":"automerge-096","title":"Implement cross-language interop tests","description":"Test OCaml ↔ TypeScript interoperability:\n- Generate patches in OCaml, apply in TS json-joy\n- Generate patches in TS, apply in OCaml\n- Verify identical results\n- Test via wire format (binary codec)\n\nAcceptance: Bidirectional interop demonstrated","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-26T11:49:09.143041317+01:00","updated_at":"2025-12-26T11:49:09.143041317+01:00","labels":["interop","phase-8","testing"],"dependencies":[{"issue_id":"automerge-096","depends_on_id":"automerge-095","type":"blocks","created_at":"2025-12-26T11:49:09.144123382+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"automerge-096","depends_on_id":"automerge-P8","type":"parent-child","created_at":"2025-12-26T13:52:47.716028717+01:00","created_by":"gdiazlo","metadata":"{}"}]} 47{"id":"automerge-EPIC","title":"CRDT Library - Full json-joy compatible implementation","description":"Implement a full OCaml 5.4 CRDT library compatible with the json-joy specification. This includes:\n- JSON CRDT document model (7 node types: con, val, obj, vec, arr, str, bin)\n- JSON CRDT Patch (18 operations)\n- Full ClockVector support\n- CBOR extended value types (bytes, undefined)\n- All codecs (verbose, compact, binary) for patches and snapshots\n- JSON Reactive RPC (JSON-Rx) for OCaml-to-OCaml communication\n- Effects-based IO abstraction (IO-library agnostic)\n- Conformance tests using json-crdt-traces fixtures\n\nReference: https://github.com/streamich/json-joy\nTraces: https://github.com/streamich/json-crdt-traces","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-26T11:44:33.758836708+01:00","updated_at":"2025-12-26T11:44:33.758836708+01:00","labels":["crdt","epic","json-joy"]} 48{"id":"automerge-P0","title":"Phase 0: Project setup and compatibility scope definition","description":"Foundation work: define compatibility scope, restructure project for OCaml 5.4, set up CI/test harness.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-26T11:44:49.42930602+01:00","updated_at":"2025-12-26T11:44:49.42930602+01:00","labels":["epic","phase-0","setup"],"dependencies":[{"issue_id":"automerge-P0","depends_on_id":"automerge-EPIC","type":"parent-child","created_at":"2025-12-26T13:49:47.42174698+01:00","created_by":"gdiazlo","metadata":"{}"}]} 49{"id":"automerge-P1","title":"Phase 1: Core data types (IO-agnostic, pure OCaml)","description":"Implement fundamental data types: Value (JSON+CBOR), Timestamps, Clocks, JSON Pointer.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-26T11:44:50.942489501+01:00","updated_at":"2025-12-26T11:44:50.942489501+01:00","labels":["core","epic","phase-1"],"dependencies":[{"issue_id":"automerge-P1","depends_on_id":"automerge-P0","type":"parent-child","created_at":"2025-12-26T13:50:03.993146558+01:00","created_by":"gdiazlo","metadata":"{}"}]} 50{"id":"automerge-P2","title":"Phase 2: JSON CRDT Patch specification","description":"Implement all 18 patch operations, Patch container, Builder API, and all codecs (verbose, compact, binary).","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-26T11:44:52.964382798+01:00","updated_at":"2025-12-26T11:44:52.964382798+01:00","labels":["epic","patch","phase-2"],"dependencies":[{"issue_id":"automerge-P2","depends_on_id":"automerge-P1","type":"parent-child","created_at":"2025-12-26T13:50:05.126781633+01:00","created_by":"gdiazlo","metadata":"{}"}]} 51{"id":"automerge-P3","title":"Phase 3: JSON CRDT Document Model","description":"Implement all 7 node types, RGA core, Model container, patch application, and high-level API.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-26T11:44:55.376803488+01:00","updated_at":"2025-12-26T11:44:55.376803488+01:00","labels":["epic","model","phase-3"],"dependencies":[{"issue_id":"automerge-P3","depends_on_id":"automerge-P2","type":"parent-child","created_at":"2025-12-26T13:50:05.974244247+01:00","created_by":"gdiazlo","metadata":"{}"}]} 52{"id":"automerge-P4","title":"Phase 4: Document codecs (snapshot serialization)","description":"Implement sidecar, structural (verbose/compact/binary), and indexed codecs for document snapshots.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-26T11:45:00.078660998+01:00","updated_at":"2025-12-26T11:45:00.078660998+01:00","labels":["codec","epic","phase-4"],"dependencies":[{"issue_id":"automerge-P4","depends_on_id":"automerge-P3","type":"parent-child","created_at":"2025-12-26T13:50:06.414616604+01:00","created_by":"gdiazlo","metadata":"{}"}]} 53{"id":"automerge-P5","title":"Phase 5: Effects-based IO abstraction","description":"Define effect signatures for IO operations, implement handlers for Eio, Lwt, and direct (blocking).","status":"open","priority":2,"issue_type":"epic","created_at":"2025-12-26T11:45:02.615064764+01:00","updated_at":"2025-12-26T11:45:02.615064764+01:00","labels":["effects","epic","io","phase-5"],"dependencies":[{"issue_id":"automerge-P5","depends_on_id":"automerge-P4","type":"parent-child","created_at":"2025-12-26T13:50:06.747479551+01:00","created_by":"gdiazlo","metadata":"{}"}]} 54{"id":"automerge-P6","title":"Phase 6: JSON Reactive RPC (JSON-Rx)","description":"Implement JSON-Rx message types, codecs, server-side router, and client-side subscription manager for OCaml-to-OCaml RPC.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-26T11:45:03.380938458+01:00","updated_at":"2025-12-26T11:45:03.380938458+01:00","labels":["epic","json-rx","phase-6","rpc"],"dependencies":[{"issue_id":"automerge-P6","depends_on_id":"automerge-P5","type":"parent-child","created_at":"2025-12-26T13:50:07.304302196+01:00","created_by":"gdiazlo","metadata":"{}"}]} 55{"id":"automerge-P7","title":"Phase 7: Extensions (counter, mval, peritext)","description":"Implement higher-order CRDT extensions: counter (cnt), multi-value register (mval), and peritext (rich text).","status":"open","priority":2,"issue_type":"epic","created_at":"2025-12-26T11:45:03.832469826+01:00","updated_at":"2025-12-26T11:45:03.832469826+01:00","labels":["epic","extensions","phase-7"],"dependencies":[{"issue_id":"automerge-P7","depends_on_id":"automerge-P6","type":"parent-child","created_at":"2025-12-26T13:51:14.944575011+01:00","created_by":"gdiazlo","metadata":"{}"}]} 56{"id":"automerge-P8","title":"Phase 8: Conformance testing","description":"Implement full conformance test suite using json-crdt-traces fixtures plus fuzzing/property tests.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-26T11:45:05.443231113+01:00","updated_at":"2025-12-26T11:45:05.443231113+01:00","labels":["conformance","epic","phase-8","testing"],"dependencies":[{"issue_id":"automerge-P8","depends_on_id":"automerge-P7","type":"parent-child","created_at":"2025-12-26T13:51:16.084904641+01:00","created_by":"gdiazlo","metadata":"{}"}]} 57{"id":"crdt-4pq","title":"Fix RGA concurrent insert ordering for json-joy compatibility","description":"The RGA algorithm's tie-breaking for concurrent inserts doesn't match json-joy's implementation. When two replicas insert at the same position concurrently, the resulting order differs.\n\nEvidence from conformance tests:\n- Expected: \"An epic synopsis\" \n- Got: \"A synepic nopsis\" (the \"n\" from \"An\" appears in wrong position)\n\nNeed to analyze json-joy's RGA implementation and match its ordering rules:\n- Understand how json-joy determines concurrent inserts\n- Match tie-breaking logic for timestamp comparison\n- May need to track causal dependencies to determine concurrency","status":"closed","priority":1,"issue_type":"bug","assignee":"claude","created_at":"2025-12-26T17:19:31.628018647+01:00","updated_at":"2025-12-26T17:45:10.110299973+01:00","closed_at":"2025-12-26T17:45:10.110299973+01:00","labels":["conformance","crdt","json-joy","rga"]} 58{"id":"crdt-4ra","title":"Reduce binary codec output size (currently 4x larger than json-joy)","description":"Binary output is 4.9KB vs json-joy's ~1.2KB for 1K chars.\nInvestigate:\n1. Timestamp encoding efficiency (delta encoding?)\n2. RGA chunk representation\n3. Node type encoding overhead\n4. Compare byte-by-byte with json-joy format","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-27T00:34:56.319523298+01:00","updated_at":"2025-12-27T09:29:04.871828606+01:00","closed_at":"2025-12-27T09:29:04.871828606+01:00","labels":["binary-codec","optimization","performance","size"],"dependencies":[{"issue_id":"crdt-4ra","depends_on_id":"crdt-icx","type":"blocks","created_at":"2025-12-27T00:34:56.320955254+01:00","created_by":"gdiazlo","metadata":"{}"}]} 59{"id":"crdt-68q","title":"Fix compact codec failing tests (friendsforever_flat)","status":"closed","priority":0,"issue_type":"bug","created_at":"2026-01-02T12:15:25.878861438+01:00","updated_at":"2026-01-02T18:42:18.462948762+01:00","closed_at":"2026-01-02T18:42:18.462948762+01:00"} 60{"id":"crdt-6rt","title":"Fix remaining test failures after simdjsont migration","status":"closed","priority":0,"issue_type":"bug","assignee":"gdiazlo","created_at":"2026-01-02T11:36:44.354508505+01:00","updated_at":"2026-01-02T18:42:13.420876009+01:00","closed_at":"2026-01-02T18:42:13.420876009+01:00"} 61{"id":"crdt-7f0","title":"Optimize RGA sequential insert (O(n²) -\u003e O(n log n))","description":"Sequential insert of 10K chars takes 284ms - this is O(n²) behavior.\nOptions:\n1. Use tree-based structure (AVL, finger tree) instead of list\n2. Add index for fast position lookup\n3. Consider json-joy's B+tree approach\n\nTarget: \u003c 50ms for 10K sequential inserts","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-27T00:35:00.551809524+01:00","updated_at":"2025-12-27T00:46:27.873263358+01:00","closed_at":"2025-12-27T00:46:27.873263358+01:00","labels":["optimization","performance","rga"],"dependencies":[{"issue_id":"crdt-7f0","depends_on_id":"crdt-icx","type":"blocks","created_at":"2025-12-27T00:35:00.557418209+01:00","created_by":"gdiazlo","metadata":"{}"}]} 62{"id":"crdt-9h3","title":"Optimize binary encoding performance (currently 3x slower than json-joy)","description":"Binary encoding is ~21K ops/sec vs json-joy's ~108K ops/sec.\nInvestigate:\n1. Buffer allocation strategy\n2. Varint encoding efficiency\n3. CBOR encoding overhead\n4. Consider pre-allocating buffers based on model size","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-27T00:34:52.454913078+01:00","updated_at":"2025-12-27T00:41:24.590935842+01:00","closed_at":"2025-12-27T00:41:24.590935842+01:00","labels":["binary-codec","optimization","performance"],"dependencies":[{"issue_id":"crdt-9h3","depends_on_id":"crdt-icx","type":"blocks","created_at":"2025-12-27T00:34:52.456412445+01:00","created_by":"gdiazlo","metadata":"{}"}]} 63{"id":"crdt-9ry","title":"Run final benchmarks and compare with json-joy","description":"After all optimizations:\n1. Run full benchmark suite\n2. Verify all tests pass\n3. Document comparison with json-joy\n4. Target: exceed json-joy performance across all metrics","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-27T00:35:14.61471182+01:00","updated_at":"2025-12-27T00:46:58.828283923+01:00","closed_at":"2025-12-27T00:46:58.828283923+01:00","labels":["benchmarks","documentation"],"dependencies":[{"issue_id":"crdt-9ry","depends_on_id":"crdt-apw","type":"blocks","created_at":"2025-12-27T00:35:14.620794117+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"crdt-9ry","depends_on_id":"crdt-9h3","type":"blocks","created_at":"2025-12-27T00:35:14.621445689+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"crdt-9ry","depends_on_id":"crdt-4ra","type":"blocks","created_at":"2025-12-27T00:35:14.621869631+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"crdt-9ry","depends_on_id":"crdt-7f0","type":"blocks","created_at":"2025-12-27T00:35:14.622264163+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"crdt-9ry","depends_on_id":"crdt-z3n","type":"blocks","created_at":"2025-12-27T00:35:14.622793455+01:00","created_by":"gdiazlo","metadata":"{}"}]} 64{"id":"crdt-apw","title":"Investigate binary decode performance (35M ops/sec seems wrong)","description":"Binary decode shows 35M ops/sec which is suspiciously fast. Need to verify:\n1. The decode is actually doing work (not returning cached/memoized result)\n2. The decoded model is correct and usable\n3. Add validation that decoded model matches original","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-27T00:34:47.948086278+01:00","updated_at":"2025-12-27T00:38:53.472587773+01:00","closed_at":"2025-12-27T00:38:53.472587773+01:00","labels":["binary-codec","investigation","performance"],"dependencies":[{"issue_id":"crdt-apw","depends_on_id":"crdt-icx","type":"blocks","created_at":"2025-12-27T00:34:47.954081564+01:00","created_by":"gdiazlo","metadata":"{}"}]} 65{"id":"crdt-bwe","title":"Fix A decode_timestamp","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-02T12:06:12.866717163+01:00","updated_at":"2026-01-02T18:42:23.50415162+01:00","closed_at":"2026-01-02T18:42:23.50415162+01:00"} 66{"id":"crdt-icx","title":"Investigate and optimize benchmark performance issues","description":"Investigation and optimization of CRDT library performance based on benchmark comparison with json-joy.\n\nKey findings from initial benchmarks:\n1. Binary decode shows suspiciously fast results (35M ops/sec) - needs verification\n2. Binary encoding is 3x slower than json-joy\n3. Binary codec produces 4x larger output than json-joy\n4. RGA sequential insert is O(n²) - 284ms for 10K chars\n\nTarget: Match or exceed json-joy performance given our more capable CPU.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-27T00:34:36.713327259+01:00","updated_at":"2025-12-27T00:47:00.530534521+01:00","closed_at":"2025-12-27T00:47:00.530534521+01:00","labels":["benchmarks","optimization","performance"]} 67{"id":"crdt-z3n","title":"Add benchmark validation to ensure correctness","description":"Add validation steps to benchmarks:\n1. Verify encode/decode round-trip produces identical model\n2. Verify model view matches expected content\n3. Add checksums/hashes to detect corruption","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-27T00:35:03.801590973+01:00","updated_at":"2025-12-27T00:38:54.776020436+01:00","closed_at":"2025-12-27T00:38:54.776020436+01:00","labels":["benchmarks","testing"],"dependencies":[{"issue_id":"crdt-z3n","depends_on_id":"crdt-icx","type":"blocks","created_at":"2025-12-27T00:35:03.802861658+01:00","created_by":"gdiazlo","metadata":"{}"}]}