Repository navigation
fix(core): keep a front-matter type that names no type as a property - #2260
Conversation
aicayzer
left a comment
There was a problem hiding this comment.
Review: ready to merge
Summary. A note whose front-matter type is a word Marfa could never use as a type, as Obsidian vaults write, now syncs as the folder's default type with the word kept as a property and written back unchanged; a valid identifier the copy does not hold is still refused. Safe to merge.
First draft: 4/5. 1 blocking issue found, fixed in c226c718e; one Reason corrected in 56ed122a9.
Found.
- Blocking: where an app had set the item's
typeproperty to a valid identifier, a person who changed the line to a word lost it: the held property overwrote the word, nothing was sent, and the write-back reverted the file (reproduced). Fixed: the word on the line wins, stated infolders/uncarried-preserve, with a fixture seen failing first. folders/foreign-type-emptygave an untrue reason for an empty value. Corrected.
Checked. A retype made on another device is not undone by the next scan (run): the line stays and no type change is sent. Create, write-back, a second device, a retype in either direction, rewording and removing the line keep or carry the person's value. hydrate::type_id gives the same answer as the checks it replaced. Numbers, lists, empty values, whitespace, wrong case, a., .b and null all become a property.
Trade-off, by decision. While a word is on the line the file does not show the item's Marfa type.
Summary
A Markdown note whose front matter says
type: reference, as many Obsidian vaults do, was held with "reference is not a type this copy holds" and never synced. A type identifier always has at least two dot-separated segments (types/id-grammar), so atypevalue that the grammar refuses can never name a Marfa type. A folder now makes such a note a document of its default type, keeps the value as the item propertytype, and writes the file'stypeline back as the person wrote it. A value that is a valid identifier but names a type the copy does not hold, such as a mistypedcore.notes, is still refused.Changes
folders.md):folders/foreign-type-property(atypevalue that is not an identifier is carried as the propertytype, and the item's type is unchanged),folders/foreign-type-write(a write shows that property in thetypeline in place of the item's type) andfolders/foreign-type-empty(an emptytype:line stays empty).folders/retype-unsuitedto a type identifier the copy does not hold, with its reason.folders/own-field-linesandfolders/default-document-typeto match.folders/own-field-validation: such a line is no longer unreadable.folders/uncarried-preservenow excepts atypeproperty that thetypeline replaces with a non-identifier value, so the person's word wins over atypeproperty an app set.folders/foreign-type-propertycross-references it.folder/fields.rs):names_typedecides whether atypevalue is an identifier, using the grammar's own validator.readcarries any other value (string, number, list, empty or null) as a property.lines_ofshows that property in thetypeline, and keeps an empty line empty.carriedsays which reserved-name properties a file carries.presentationcompares a non-identifier value as written instead of trimmed.folder/push.rs): a whole save no longer puts back a heldtypeproperty that the file carries, so changing the line to a real type or removing it clears the property. A held reserved-name property is put back only where the file read no value under that name, so a word the person writes replaces an app's identifier-valuedtypeproperty instead of being overwritten by it.folder/mod.rs, one line): the render passes the file's front matter tolines_of. PR fix(core): finish a push after a key change, keep waits at hand-over #2255 also changes this file, but not this line.hydrate.rs,catalog.rs,scaffold.rs):type_idis the single check for "a type identifier and not a.*pattern". The two places that spelled it out now call it.a type line that names no typegroup (eight fixtures, includingreplaces an app's type property with the word the person writes on the line) indevice/folders-frontmatter.test.ts, unit tests infields.rs, andUntyped.md(type:) taken out of the unreadable cases ofreads own-field lines in each form a file can hold them.Testing
replaces an app's type property with the word the person writes on the lineseeds a note whosetypeproperty iscore.bookmark(the file showstype: core.note), edits the line totype: referenceand expects an update withproperties.type: "reference"and the line kept. Before the fix it failed: no update was sent, so the write-back would have reverted the line. It passes with the fix.mainfirst. The create was flaggedrefused, and each edge case was flaggedunreadable. All seven pass with the change.cargo fmt --check,cargo clippy --workspace --all-targets -- -D warnings, andcargo test -p marfa-core -p marfa-cli: all clean, 1,242 tests passed (rerun after the review fix: all passed).folders-frontmatter,folders,folders-contract-a,-b,-c,-extra-c): 355 of 355 passed. After the review fix,folders-frontmatter,foldersandfolders-contract-a,-b,-c: 333 of 333 passed.spec-citations,spec-formandspec-statements: 48 passed. After the review fix,spec-formandspec-citations: 34 passed.tsc --noEmitand Prettier onconformanceare clean.core/scripts/server-up.sh, the builtmarfabinary, two folder directories as two machines):Reading.md(type: reference),Stub.md(type:) andBook.md(type: [book, source]) becamecore.noteitems with propertiestype: "reference",type: nullandtype: ["book", "source"].Misspelt.md(type: core.notes) was held with "core.notes is not a type this copy holds".typeline was written back unchanged. A second push sent nothing and left every file byte for byte the same.type: referencethe same. Its YAML layout for the other lines differs:type: ~for the empty line, block lists, and property order. Every new file is written this way, so this change does not cause it.type: referencetotype: core.bookmarkretyped the item and dropped the property. Changing the list totype: articlesent only the property. Removing thetype:line cleared the property and left the type ascore.note. The second directory followed the retype and the new word. I did not pull it again after the removal.typeholding a string, a list, a number, an empty string or null.cli/folder.test.tsscenario suite was not run.Notes for reviewers
type. The server forbidstypeonly as a field a type declares (types/field-shadows-item), not as an item property, and stores one as written. So no new name is needed, and the line round-trips exactly. If a client sets atypeproperty that is itself a valid identifier, the file does not carry it. The file shows the item's type, and the property is kept on a whole save (folders/uncarried-preserve), unless the person writes a non-identifier word on the line: that word replaces the property.typeproperty is present, the file does not show the item's Marfa type. A retype made elsewhere does not change the line. This is deliberate, so a person's vault stays as they wrote it.read_view_changed; hydrate againafter a second folder was added under the same key. The next push delivered the queued edit. The read view is outside this change, and fix(core): finish a push after a key change, keep waits at hand-over #2255 rebuilds the copy within the same push. I did not reproduce it onmain.typeline that is not a Marfa type identifier becomes the propertytypeon a note of the folder's default type, and the file keeps its line.typevalues are read as a type and which are kept as a property.typemakes a file unreadable.Checklist