Degrade a bundle from a newer version instead of refusing it whole - #95
Merged
Merged
Conversation
`Note` carries two closed enums, so one note's `"language": "rust"` made serde fail and took the other 499 with it. `read_bundle` now walks the raw JSON first and brings any value this build cannot name down to the default, counting the notes it touched; `ImportReport.notes_degraded` reports them, counted on what was actually inserted so a re-import says nothing a second time. This is the stance the database read already took. The bridge stays strict. An added enum variant is not a format break, so it does not bump FORMAT_VERSION — which is now read off the raw JSON, before the bundle is built, so a genuinely future format answers with its own message.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #27.
transfer::model::BundledeserialisesVec<Note>directly, andNotecarries two closed enums. One note's"language": "rust"made serde fail,read_bundlereturnedImportFormat, and the whole import went down — not the one note that carried it.FORMAT_VERSIONexists precisely to handle this gracefully, but it only ever fired on theversionfield, and adding an enum variant does not bump it.This has to land before #17, which adds
rust,go,javaand friends toLanguage.The decision: degrade, and say so
The ticket asks for the choice between refusing, degrading and skipping to be made deliberately and written down. This takes degrading, for three reasons:
notes::store,TryFrom<NoteRow>:row.language.parse().unwrap_or_default(), commented as "a newer version may have written a value this build does not know". The bundle read refused. A bundle is the same data through another door, so it now answers the same way.rustnote imported astxtkeeps its title, body, tags, source and deadline; only the colouring is dropped, and one click in the editor restores it. Skipping the note loses all of it.FORMAT_VERSIONper variant (option 1) is the worst of the three for the user — 500 notes refused over one field — and it turns the version number into a changelog of enum edits.The ticket's objection to degrading is that it is "lossy in a way the report does not mention". So the report mentions it:
ImportReport.notes_degraded, and a message that names the cause.What stays strict is the bridge. A
languagethe front end cannot name is still a deserialisation failure at the IPC boundary — that is what lets the generated TypeScript union be trusted.How
read_bundlewalks the raw JSON before building theBundle, and replaces anylanguageorkindwhose string this build cannotFromStrwith the default, collecting the ids it touched. It returns anIncomingBundle { bundle, degraded }.degrade_fieldis generic overFromStr + Default + Display, so no variant spelling is written twice —closed_enum!already guarantees the single spelling.mergecounts a degraded note only when it actually inserted it. Re-importing the same file imports nothing, so it reports nothing degraded either — otherwise the warning would repeat itself forever on a file the user already has.What the user sees
One status line, since
StatusNotifierholds one message at a time. A third key joinsfile.importedandfile.importedNothing:In both locales.
Tests
transfer::model): an unknown language and an unknown kind each degrade and are listed; a known value is untouched; a non-string language is still a format error; the version guard now answers on a file whose notes this build could not have parsed.tests/transfer.rs): a bundle whose first note is"rust"imports both notes withnotes_degraded: 1and the language back at the default; same for an unknownkind; and a second import of the same file reports0degraded.notesDegradedcrosses as camelCase.10-library-transfer): a bundle written from Node with"language": "rust"imports through the real bridge, reports one degraded, and the note comes back astxt.Checked
cargo test— 165 + 34 + 83 + 14 + 10 passing.cargo clippy --all-targets -- -D warningsandcargo fmt --check— clean.npm test— 917 passing.npm run lint— clean.01and10— green.docs/architecture.mdandCLAUDE.mdrecord the stance and theFORMAT_VERSION.Also in here: the comment on the
unicode-normalizationdependency line from #16 is dropped — it merged before that follow-up push landed.