diff --git a/lib/data/note_bulk.dart b/lib/data/note_bulk.dart index ce0b387..f317997 100644 --- a/lib/data/note_bulk.dart +++ b/lib/data/note_bulk.dart @@ -31,6 +31,10 @@ Log planBulkUpdate( final note = noteFromRecord(current); final next = note.copyWith(priority: priority, status: status); if (next.priority == note.priority && next.status == note.status) continue; + // Generated against generated, never against the stored text: a peer's + // `...00Z` (or a web build's millisecond date) would otherwise read as + // a change and get a fresh clock, erasing the `created_at` node signal. + final before = noteFields(note, hlc); plan[id] = Record( id: id, fields: { @@ -38,7 +42,7 @@ Log planBulkUpdate( next.copyWith(updatedAt: now), hlc, ).entries) - if (current.fields[key]?.$1 != value.$1) key: value, + if (before[key]?.$1 != value.$1) key: value, }, ); } diff --git a/pubspec.yaml b/pubspec.yaml index 2f5554e..be36ec2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.68+1 +version: 1.0.69+1 environment: sdk: ^3.12.2 diff --git a/test/note_repository_bulk_test.dart b/test/note_repository_bulk_test.dart index 54a5f1f..6a38738 100644 --- a/test/note_repository_bulk_test.dart +++ b/test/note_repository_bulk_test.dart @@ -75,6 +75,33 @@ void main() { expect((await repo.listNotes()).single.status, Status.done); }); + test( + 'a stored value Dart would format differently keeps its clock', + () async { + final (repo, _) = await _open(); + final peer = Hlc(wallTimeMs: 1000, counter: 0, nodeId: 'mcp'); + // A peer's (or a web build's) timestamp text, and no priority field. + await repo.importLog({ + 'a': Record( + id: 'a', + fields: { + 'text': ('A', peer), + 'status': (0, peer), + 'created_at': ('2026-01-01T00:00:00Z', peer), + 'updated_at': ('2026-01-01T00:00:00Z', peer), + }, + ), + }); + + await repo.bulkUpdate({'a'}, status: Status.done); + + final fields = repo.exportLog()['a']!.fields; + expect(fields['created_at'], ('2026-01-01T00:00:00Z', peer)); + expect(fields.containsKey('priority'), isFalse); + expect(fields['status']!.$2.nodeId, 'dev'); + }, + ); + test('no write when nothing changes or ids are unknown/deleted', () async { final (repo, p) = await _open(); await repo.upsert(noteFixture('a', 'A'));