Commit Graph
1005 Commits
Author SHA1 Message Date
Martin BallandClaude Opus 5.5 3e37fbcd7e craft-proof it, pt — an object placeholder between the mark and a real closing quote keeps the narration exemption («Vai?\u{1}» disse lui.) (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 23:56:09 +00:00
Martin BallandClaude Opus 5.5 4c8cb404ab craft-proof it — a space after the dialogue dash no longer hides the capital mark (Finì. — domani partiamo.) (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 23:48:04 +00:00
Martin BallandClaude Opus 5.5 f3d411638d craft-proof it — the dialogue-dash exception applies after ? and ! only, so Finì. —domani partiamo. gets its capital mark again (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 23:47:08 +00:00
Martin BallandClaude Opus 5.5 a8b3bb74c8 craft-proof it, pt — the object placeholder is not a closing quote, so Chi era?\u{1} era Marco. still gets its capital mark (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 23:23:15 +00:00
Martin BallandClaude Opus 5.5 cb82e91428 craft-proof — a run of spaces is one double-space issue over the whole run in every language, through one shared space_runs helper (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 23:23:15 +00:00
Martin BallandClaude Opus 5.5 7b64b78cb0 craft-proof english — Australian English also takes a word in SCOWL's en-GB list, and without SCOWL every en_AU source is read before any en_GB one (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 23:23:09 +00:00
Martin BallandClaude Opus 5.5 54ac5fbc4c craft-proof — README: embedded_locales() and the SCOWL byte count match build.rs with en-AU; ru: drop an unused binding (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:56:44 +00:00
Martin BallandClaude Opus 5.5 466919a8a5 craft-proof english — with SCOWL embedded, a dictionaries-folder en_GB no longer outranks the embedded en-AU (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:56:44 +00:00
Martin BallandClaude Opus 5.5 d2563a77d4 craft-proof tr — te and ta are the locative suffix, not a detached particle, so kitapte is not offered as kitap te (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:56:44 +00:00
Martin BallandClaude Opus 5.5 bd3db196a5 craft-proof es — a run of spaces is one Espacio doble issue over the whole run (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:56:44 +00:00
Martin BallandClaude Opus 5.5 15d3c0d370 craft-proof it, pt — narration after a quoted or dashed question or exclamation is not a new sentence («Vai?» disse lui) (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:56:44 +00:00
Martin BallandClaude Opus 5.5 61030150dc craft-proof cs, hr, it — a hyphenated word is looked up whole before its parts, and an elision (l'ex-amico) is read in each part (#496 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:56:44 +00:00
Martin BallandClaude Opus 5.5 9ef9185131 FU.8: craft-proof cs — regression test from wordcraft#4683: a letter that lowercases to two chars (İ) still gets its one-letter edits
The shared suggestion code already edits across the whole lowercased word, so no code change is needed; the test keeps it that way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:43:25 +00:00
Martin BallandClaude Opus 5.5 65ce4f882a FU.7: craft-proof pack languages — another script is told by the letters' Unicode scripts, not the dictionary's letter inventory, so a misspelling in the dictionary's own script (zzzz in Dutch) is always checked
Found by a local CodeRabbit review of #496 (major).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:18:42 +00:00
Martin BallandClaude Opus 5.5 8712aa105a FU.6: craft-proof affix — the stems' flags are budgeted while a dictionary is read (running counts of flag text and keys), so a huge .dic fails early instead of after holding every entry's flags (#495 P3)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:18:42 +00:00
Martin BallandClaude Opus 5.5 1f345ea809 FU.5: craft-proof id, ru — the cased-letter rule for words in capitals (craft-libs#485): a caseless part is no abbreviation; shared in_capitals / capitals_part
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:18:42 +00:00
Martin BallandClaude Opus 5.5 86345ebcf5 FU.4: craft-proof packs — remembered hyphenation patterns keep to a 256 MB budget of their own; a pack's spelling files are never candidates through a symbolic link
Follow-ups from craft-libs#485: up to 256 languages' pack patterns (64 MB files each) were kept
by count only; `hunspell::ordered` checked pack files with `is_file`, which follows links,
while the pack scan refuses them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:18:42 +00:00
Martin BallandClaude Opus 5.5 87defe169f FU.3: craft-proof pack languages — missing-dictionary list forgets its oldest, not all; a panic inside a check unpins its dictionaries; a word in another script than the dictionary's isn't marked
Follow-ups from craft-libs#485: `CHECK_FROM` is reset by a drop guard; `remember_missing` drops
the oldest of 256; a word none of whose letters the dictionary's words use (a Cyrillic word in
a Dutch run) is left alone, as Word does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:18:42 +00:00
Martin BallandClaude Opus 5.5 820695e951 FU.2: craft-proof — Australian English reads SCOWL's own en-AU dictionary (ProofLang::EnAu), with en-GB's spelling policy; en-NZ stays on en-GB
SCOWL en-AU has 238 words en-GB lacks (billabong, brumby, larrikinism, Australian place
names) and spells program, inquiry, livable, licorice, verandah the Australian way (no
programme, enquiry, liveable, dialog or veranda, as Hunspell en_AU says); -ise/-ize policy and
affix file are the same as en-GB's. craft-i18n already ships language-data/en-au.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:18:42 +00:00
Martin BallandClaude Opus 5.5 e36fb5d069 FU.1: craft-proof — British English never swaps -yze for -yse (reanalyze, breathalyzer, paralyzingly stay American, as Hunspell en_GB says)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:18:42 +00:00
Martin BallandClaude Opus 5.5 89fa1559e9 CP6.13: craft-libs#495 review — Windows drives are probed for LibreOffice once per process; sr@latin is sr-latn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:06:58 +00:00
Martin BallandClaude Opus 5.5 c5cc9c4b7a CP6.13: craft-libs#495 review — cs: ne ne, ano ano, už už and to to are no repeated words; ru: no comma asked for inside тем более что, при условии что, в то время как; -ой adjectives take и after г, к, х, ж, ш, ч, щ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:06:58 +00:00
Martin BallandClaude Opus 5.5 05acd513cc CP6.13: craft-libs#495 review — tr suggest: the diacritic and typo steps find names the dictionary capitalizes (istanbu → İstanbul)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:06:58 +00:00
Martin BallandClaude Opus 5.5 724d541856 CP6.13: craft-libs#495 review — tr grammar: Turkish case folding (İst., Işık ışık), initials (A.Ş., T.C.) end no sentence, and a repeated word with an apostrophe (Ankara'da Ankara'da) is marked again
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:06:58 +00:00
Martin BallandClaude Opus 5.5 d2d5c737a6 CP6.13: craft-libs#482/#485/#488 review — NOTICE carries the embedded Portuguese patterns' BSD notice; README: the usage example defines text, the eight-candidate limit, what the default build embeds; en_words writes under crates/proof
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:27:37 +00:00
Martin BallandClaude Opus 5.5 5bd21c0509 CP6.13: craft-libs#482/#485/#487 review — en.UTF-8 and pl@euro resolve to their language; the German, Bulgarian and no-data English tests hold on a machine with Hunspell dictionaries installed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:27:37 +00:00
Martin BallandClaude Opus 5.5 64bd43db1d CP6.13: craft-libs#487 review — a trailing combining mark stays on its word; Italian and Portuguese look a hyphenated word up whole before its parts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:27:37 +00:00
Martin BallandClaude Opus 5.5 be52680c9c CP6.13: craft-libs#495 review — an oversized pack licence is skipped alone; a score (3 : 1) keeps its spaces in hr, it, pl, pt and ru; ' ,,' (a typed quote) is left to the quote rule in pl and ru; pt narration after a dialogue dash is no new sentence
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:27:37 +00:00
Martin BallandClaude Opus 5.5 fdb52ec3c6 CP6.13: craft-libs#495 review — MAP variants are made by number of changes, so the 4,096 cap drops the most-changed ones, never a single slip
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:27:37 +00:00
Martin BallandClaude Opus 5.5 cb5d7310ec CP6.13: craft-libs#495 review — tr: Ignore words in UPPERCASE reaches Turkish's own check; a comma after de/da, ne or ya is fine; repeated numbers are no repeated words; table suggestions keep the word's case
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:27:37 +00:00
Martin BallandClaude Opus 5.5 c5daa8d16c CP6.13: craft-libs#495 review — it grammar: pp., tab. and dr. are abbreviations, so the next word starts no sentence
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:57:37 +00:00
Martin BallandClaude Opus 5.5 806ed6a561 CP6.13: craft-libs#495 review — tr grammar: a space before ?, ! or a colon or semicolon that starts no emoticon is flagged (Not :bu, Ne ?Bu, Peki ;Dün); :D and ;P are emoticons only before a space or the end
A number before a period still reads as an ordinal (Puanım 100. bu iyi. is missed): Turkish
writes ordinals that way and no clean rule tells the two apart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:57:37 +00:00
Martin BallandClaude Opus 5.5 2dc51d7866 CP6.13: craft-libs#495 review — a .dic entry may carry up to 8,192 flags (was 1,024), so LibreOffice's Turkish stems with thousands (abart, savaş, inan: up to 3,926) are words again
The total flag-set bound (MAX_SET_DATA, 8.4M) stays the hostile-input guard: LibreOffice's
tr_TR loads with 5.2M of it in 0.6 s, and abart, abartmıştım, savaşıyor, inandım, aranıyor,
açılamadı and bilinmiyor are right, as hunspell 1.7 answers. The merged-homonym cap is now
4 × the entry cap (32,768), under the 65,536 distinct flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:57:01 +00:00
Martin BallandClaude Opus 5.5 f723abff6d CP6.13: tr hyphen — â, î and û are vowels (dük-kân, hi-kâ-ye); the module doc's examples are the ones the rules give (CodeRabbit on craft-libs#484)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 d1cebf89eb CP6.13: tr suggest — suggestions in capitals use Turkish capitals (KİTAP, not KITAP); three table entries that suggested the word itself are gone (CodeRabbit on craft-libs#484/#489)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 8d3a9366db CP6.13: tr grammar — emoticons, decimals and scores aren't stray spaces before punctuation; ordinals (5. sınıf) and file or web names (rapor.txt) don't end a sentence (CodeRabbit on craft-libs#484/#489)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 0b292e955c CP6.13: tr dict — Turkish is read by the shared affix engine: suffix conditions apply (kalelar is no word), homonyms keep each line's flags, and an entry ends before its morphological fields, as hunspell 1.7 reads them (CodeRabbit on craft-libs#484/#489)
TrDict keeps its API (from_hunspell, contains, is_empty) over AffixDict, which reads
FLAG num since #487; the hand-written one-suffix parser and TrSuffixRule are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 6057debe6e CP6.13: hunspell.rs — Windows drives are probed for LibreOffice only when its language folders are wanted (CodeRabbit on craft-libs#489)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 9614ab270d CP6.13: hyphen.rs — a Turkish word with a suffix after an apostrophe (Ankara'dan) is hyphenated by the Turkish rules, part by part, not as English (CodeRabbit on craft-libs#484/#489)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 76f9a55f01 CP6.13: it grammar — a sentence after the first starts with a capital: the rule reads the gap before the next word, not the rest of the paragraph (CodeRabbit on craft-libs#484/#489)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 8f16fe5a13 CP4.2: review — test dictionaries installed in memory hold the dictionary-tests lock until the test ends, so a pack or folder reload in another test can't drop them mid-test (the with-data ru suggestion flake)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 30f0f2a0e8 CP4.2: review — pack licences and licence file names are plain text; missing_dictionary documents that every language is named; past 256 pack names the hint names a generic dictionary
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 9d48d8145f CP4.2: review — the bare es and de packs are Spain's and Germany's; de-CH/de-LI and pt-PT read their own region's dictionary (sharing German's and Portuguese's hyphenation, grammar and messages); a region's text reads the system's exact region before the language's bare pack
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 f67dd7761e CP4.2: review — "Ignore words in UPPERCASE" skips only words with a cased letter, so a misspelt Hebrew or Arabic word is marked
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 ba11ccd855 CP4.2: review — English never takes another dialect's dictionary or pack: each English reads its own names in the dictionaries folder, an exactly named pack and the system, else the built-in Moby list; the British-spelling test runs unconditionally again
hunspell::candidates_exact (folder → exact-locale pack → system, own names only) for English without SCOWL; packs::exact_spelling_dirs. Other languages keep the region-ordered cross-region tiers. Drops has_british_source().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 d905406fe3 CP4.2: review — the default build keeps the carry-over locales embedded until Language packs ship; CRAFT_PROOF_EMBED=en is the English-only build (CP4.4); licence notices name the real built-in sources
- build.rs: unset CRAFT_PROOF_EMBED embeds de, pl, pt, it patterns and ru-extra as before (DEFAULT_EMBED); `en` embeds English and our supplements only; `de,pl` and `all` as before. Making `en` the default is CP4.4, in the release that publishes and pins language-packs-1. The default-build data tests cover pl/it/de/pt again; CI's extra step is now the English-only build.
- licence_texts: one Moby entry (the data's, else the built-in en-words.dic) and en-extra.txt (WordCraft contributors, MIT OR Apache-2.0); the deleted core-list notice is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 3893192e88 CP4.2: review — en-GB British-spelling test skips a US-only Hunspell source (the CI goitre failure); German, Bulgarian and pack languages name their missing dictionary
The goitre failure was not a race: GitHub's Ubuntu runners have a system en_US Hunspell dictionary, which en-GB uses without the Language data (by design), and it marks goitre. Reproduced locally with a fake system en_US; the test now checks British words only when en-GB reads the Moby list or a British dictionary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 ee3be01b73 CP4.2: review — English tests hold the dictionaries lock; another region's pack never beats the system's exact region; bounded pack hyphenation lookups; NFC hyphenation; licences budgeted before reading; pack languages report like the others
P2:
- Every test whose English results depend on installed dictionaries takes DICTIONARY_TESTS (the en-GB goitre CI failure: tiny en_US fixtures raced unlocked en-GB tests).
- hunspell::candidates/find order: dictionaries folder, the first name's region pack (or the language alone), the system's exact-region dictionary, any other region's pack, the system's other names. pt_BR system beats a pt-pt pack; de_DE / de-ch, nl_NL / nl-be, es_ES / es-mx, en_US / en-gb likewise.

P3:
- Pack hyphenation lookups: a map, at most 256 languages (cleared when full); 3000 tags stay bounded and fast.
- A decomposed word (a + U+0301) is hyphenated composed (NFC) and the breaks mapped back; combining marks stay in their word.
- licence_texts checks each file's size against what is left before reading it; never reads past 16 MB.
- German, Bulgarian and pack languages: spelling message in the language where we have it; missing_dictionary/unreadable_dictionary report them like the others.
- build.rs: a missing file no longer says nothing is embedded; ru ignore message says CRAFT_I18N_DIR is enough. Built-in English list notice names the whole Moby list (en-words.dic).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 409c8facfd CP4.2: review — ProofLang::tag() names each pack language (its locale) for keys, settings and reported values; code() stays 'static and empty for packs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:33 +00:00
Martin BallandClaude Opus 5.5 664af9bc6f CP4.2: review — on 48ed6f8 English without data looks in the dictionaries folder, then an English Language pack, then the system's Hunspell, then the built-in list
hunspell::candidates (which English now loads from) searches the pack tier between the dictionaries folder and the system, as find() does; pack-loaded English goes through the same reloads guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 22:34:32 +00:00