Repository navigation
v0.4.6
FeatherReader 0.4.6 stops renames from losing data:
- Renaming a subscription can no longer erase another atproto client's edit made at the same moment.
- Renaming a folder now changes only its name instead of rebuilding the record.
Full engineering detail is in CHANGELOG.md.
Upgrade notes
- No schema change and no new settings. Upgrading from 0.4.5 is a deploy, and rolling back to 0.4.5 is a redeploy. Both were rehearsed on a fork of a production volume: 0.4.6 booted with
db: okand served its pages, and 0.4.5 then booted on the result, also withdb: ok. - Rename writes now carry
swapRecord. A rename that races another client's edit is retried once against the fresh record, and the other client's change is kept. If it still conflicts, the reader sees "changed elsewhere … Reload and try again" instead of a false success. A folder rename that fails now shows an error. It used to redirect as if it had worked. - The manage page posts the values it showed (
seen_url,seen_title,seen_folder,seen_name), so a change made elsewhere after the page loaded is detected too. A form posted without them still works.
Fixed
- A subscription rename could erase another client's concurrent edit (#267, closes #149).
- Every write path:
putRecordtakesswapRecordon the Rust OAuth client, the app-password client and the sidecar. - The rename: it writes against the CID it read. On
InvalidSwapit re-reads and merges per field against what the reader first saw:- a field the reader didn't touch keeps the fresh value;
- a field only the reader changed takes the reader's value;
- a field both sides changed to different values is reported as a conflict.
- Repeated saves: a double-submitted Save reports success and writes once.
- Cache ordering: the local cache is updated only after the PDS write lands.
- Every write path:
- Renaming a folder overwrote the folder record (#269, closes #268). A rename rebuilt the record, which reset
position, replacedcreatedAtwith the rename time and dropped any field another client had added. Now it changes onlyname, keeps unknown fields through a catch-all onFolder, writes with compare-and-swap, uses the same merge-and-retry, and never re-creates a folder that was deleted elsewhere.
Known
Subscriptionhas no catch-all for unknown fields either, so a subscription rename still drops fields the struct doesn't name. The fields it does name are kept. This is a follow-up.