feat: add the sync skeleton, Str.ascii and Str.squish, and AppLifecycle.states - #204
Conversation
…le.states Add SyncFeed, SyncLedger, SyncBookmarks, SyncPushRow, SyncReport and CreateSyncCursorsTable: a client-side push-then-pull sync skeleton over a documented wire protocol, with ledger writes issued in a SAVEPOINT so they nest under a caller's own transaction. Add Str.ascii (Latin-only diacritic fold, case preserved) and Str.squish (Laravel semantics), and route the User-Agent app-name folding through Str.ascii instead of its own logic. Add AppLifecycle.states(), a lazy lifecycle stream. Update exports, doc/digging-deeper/sync.md, the helpers doc, the README row, CHANGELOG under Unreleased, the magic-framework skill references (including the starter guest claim marked unreleased) and the SKILL.md stamp.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
Note Kodizm (AI-generated). May contain mistakes; verify before acting. Mostly sound, but one push-mark edge case can leave local rows unsent forever. Worth fixing before consumers build on this skeleton. Major
Possible fixes: only advance to a mark strictly below the next unsent row's mark, or document Minor
Other notes
TestsThere are new tests for CI
|
After a successful push batch, SyncFeed.run advanced the mark to slice.last.mark unconditionally. Marks are a local clock, not a row id, so a bulk write can stamp many rows with the same mark; when that run straddles a batch boundary, advancing to it makes the next run's sinceMillis filter (a strict >) skip the still-unsent rows at that mark forever. _push now advances only to the greatest mark in the batch that is strictly below a shared value on the next unsent row, or leaves the mark where it was when every row in the batch carries it. The rows the mark stops short of are resent next run, absorbed by the server's own >= as a duplicate rather than lost. Also: a throw from pending, adoptRow or the ledger after a batch landed used to report pushed: 0. run() now tracks accepted rows in a variable outside the try and reports that instead.
|
Fixed both findings in 787edd7 ( Major (data loss): Minor: Tests added in
Added one clause to the existing
@kodizm review |
|
Note Kodizm (AI-generated). May contain mistakes; verify before acting. Both earlier findings are fixed in 787edd7 and I found nothing new, so this looks ready to merge. This is a re-review. The only new commit is 787edd7, which touches
TestsTwo tests were added in
CI
|
What is added
SyncFeed,SyncLedger,SyncBookmarks,SyncPushRow,SyncReportandCreateSyncCursorsTable: a client-side push-then-pull sync skeleton over a documented wire protocol. Ledger writes are issued in a SAVEPOINT so they nest under a caller's own transaction.Str.ascii(Latin-only diacritic fold, case preserved) andStr.squish(Laravel semantics). The User-Agent app-name folding now runs throughStr.ascii.AppLifecycle.states(), a lazy lifecycle stream.doc/digging-deeper/sync.md, the helpers doc, a README row, a CHANGELOG entry under Unreleased, the magic-framework skill references (including the starter guest claim marked unreleased) and the SKILL.md stamp.Sibling-compile note
No version bump and no publish. This targets
masterfor local override consumption bymagic_starterandwatchoolswhile those sibling PRs are open.example/ is deliberately not updated
example/is knowingly not updated here, against magic's own CLAUDE.md rule that a structural or feature change gets an example wired to it. The sync skeleton needs a backend that speaks its wire protocol, whichexample/does not have;Str.ascii,Str.squishandAppLifecycle.statesare plain helpers with no UI surface to demonstrate in the example app.Local gates
1836 tests, analyze and format clean.