A gallery titled past its lexicon is indexed whole and shown cut
ClosedThis pull lets the index keep galleries whose title or description is past its lexicon bound. Lexicons::validate_indexed checks a copy with those top-level strings cut to maxLength, so every other rule still refuses. Index::parsed takes strict: check (writes) passes true, put passes false. Views, notifications and the OG card cut the title to 100 graphemes, and getGallery cuts the description to 1000.
I found nothing that must change.
- Edge cases. The byte cut backs up to a char boundary, so it can't split a character. A non-object record falls through to the normal validator, which refuses it. Non-string, bad-format and nested-string failures still refuse, and the tests cover them.
- Scope. Only
social.grain.galleryis loosened. - Cut sizes. The lexicon's
maxLengthcounts bytes and the view cuts by graphemes, so a view can show up to 100 graphemes even when that is over 100 bytes. That fits the stated intent. - Checks. I didn't read the CI results.
- Known gaps. The pull body already lists the search and space-gallery gaps.
The only change since my last review is in a test, an_index_keeps_a_gallery_that_runs_long. The strict-refusal assertion now uses a gallery with a long title and no long description. Before, it used the gallery that also had a 1001-byte description. The test therefore shows that the title alone is refused by the strict validator, and that message is now the title's. This makes the assertion more precise and doesn't change any behaviour. My earlier approval stands, and I found nothing that must change.
Landed on feature/rust in batch/four (…/3mzbjho3qgd2b, 785dbe4), with its head 0362694 unchanged.
What changes
Indexing. A
social.grain.gallerywhose own strings (title,description) run past their lexiconmaxLengthis indexed, by Jetstream, backfill andgrain-importalike, instead of refused. It goes through one function,Lexicons::validate_indexedincrates/grain/src/lexicon.rs: for a gallery it checks a copy with those top-level strings cut to their bound, so every other rule (formats, required fields, nested strings such asaddress.country, other collections) still refuses as before. The index keeps the whole record, sorecordin a view round-trips.Writes.
Index::check, which web and space writes go through before they reach the PDS, stays strict: grain never writes a title past 100.Views.
galleryView.titleis the first 100 graphemes of the title andgalleryView.descriptionthe first 1000 of the description, with nothing appended (lexicon::cut,views::gallery_title). The notification list's gallery title and the OG card's are cut the same way; the card's own ellipsis on width is unchanged.Why
Six galleries on the network have titles over 100 (e.g. at://did:plc:7dgiqud6mtxy7kat43rh4c2c/social.grain.gallery/3mymoygaeefbg). The import refused them with
title: string too long (max 100)where the old server had them. The owner decided to index them and cut the title where it is shown. Description went with it because it is the same check on the same record; nothing else is loosened.Mirrored from knotless:
theme.rs's colours, which take a value one way "as a reader takes them" and another "as a writer must give them", with astrictflag. HereIndex::parsedtakesstrictthe same way:check(writers) passes true,put(the network) false. knotless has no lexicon validator with an exception like this, so the exception itself is new.How it was checked
check,harness,rust,testandlexiconspass at0362694. Tests added:grain::lexicon:an_index_keeps_a_gallery_that_runs_long(long title and description pass; a badcreatedAt, a non-string title, a long nestedaddress.countryand a long profiledisplayNamestill refuse) anda_view_cuts_by_graphemes(combining marks count as one).grain-serveindex:a_gallery_titled_past_its_lexicon_is_indexed_whole_but_not_written(check refuses, put takes it whole);records_that_do_not_fit_are_refusednow uses a bad datetime where it used a long title.grain-serveread:a_gallery_titled_past_its_lexicon_is_shown_cut(getGallery cuts by graphemes,recordwhole).grain-import:a_gallery_titled_past_its_lexicon_is_imported_whole(imported whole; one with a badcreatedAtstill refused).Shortcomings
The six galleries come in at the next import or backfill of their repos; nothing re-fetches them by itself. A gallery's search entry holds the whole title, so search matches words past the cut. Space galleries read from member repos (
spaces/pool.rs,spaces/gallery.rs) are not cut.Review
Start at
validate_indexedincrates/grain/src/lexicon.rs, thenparsedincrates/grain-serve/src/index/mod.rs.🤖 Generated with Claude Code