Commit Graph
998 Commits
Author SHA1 Message Date
Martin BallandClaude Opus 5.5 61105d293a proof: no comma mark after ister or gerek (verb and noun uses)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:46:00 +00:00
Martin BallandClaude Opus 5.5 e91b2dbb97 proof: drop the unused binding in the pronoun-prefix arm
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:46:00 +00:00
Martin BallandClaude Opus 5.5 d279c8a99c proof: a pack's ru/bg/tr patterns need every letter of the word, else the built-in rules
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:46:00 +00:00
Martin BallandClaude Opus 5.5 83a4d73c69 proof: affix_check generators give up on a dictionary with no usable stems
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:46:00 +00:00
Martin BallandClaude Opus 5.5 7c3f45dd5e proof: skip a licence file that isn't UTF-8 instead of failing the build
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:46:00 +00:00
Martin BallandClaude Opus 5.5 9b6ef1199a CP7.8: suggestion steps charge the work done; big homonym aliases load once
A step now counts a rule, a condition class, a split's suffix lookup,
16 flags of a set looked through and a group visit, so hostile rules
whose steps were cheap to count but costly to run hit the budget in
time. Retuned: 2^13 steps per candidate, 2^25 per suggest call; the
81 packs' typo sets suggest exactly as at d0c341c8.

Condition character sets are sorted and looked up by binary search.
A stem's sets are worked out once per distinct entry list when its
entries hold 256+ flags (16 kept-apart homonyms of 8,190 flags on
17,576 stems: 55 s load, now 57 ms). A near-word candidate whose
steps ran out counts as a word, so suggest never offers a compound
check() would refuse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 05:55:02 +00:00
Martin BallandClaude Opus 5.5 c6c5386c6b CP7.7: one suggest call shares one simple-word budget
Every TRY/KEY/typo candidate got a fresh 65,536-rule check, so a hostile
.aff with a 128-letter TRY line took ~20 s per suggest call. Now a
suggest call shares 2^23 affix rules across its simple-word checks, each
capped at 2^11; prefix-rule collection counts against the budget and
mixed-case lookups try at most MAX_HOMONYMS stems. Suggestion lists are
unchanged on the 77 packs and the recall sets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 04:56:18 +00:00
Martin BallandClaude Opus 5.5 d0c341c88f CP7.6: craft-libs#497 re-review — prefix flags sorted before lookup; one step budget per simple-word check
- simple_word sorts the grouped prefix flags (non-cross then cross flags were unsorted, so
  `redo`/`rework` from a no-cross prefix beside cross ones were missed).
- One budget of 65,536 affix rules per simple-word check, shared by every prefix group and
  suffix walk; past it the word is taken for no word. Prefixes that each strip their own
  text (h2.aff: 1,000 roots) no longer cost a full walk each: 1.7 s → 1.1 ms per two
  words, suggest 14.9 s → 65 ms. The 77 fetched spelling packs answer as without a budget
  on 6,000 generated words each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 04:22:14 +00:00
Martin BallandClaude Opus 5.5 188c3154ae CP7.5: craft-libs#497 re-review — prefixes leaving one root share one suffix walk; all-caps mixed-case stems are no compounds; homonym flags written; compact format WCAFF2
- simple_word groups the prefix rules that leave the same root (circumfix and NEEDAFFIX
  alike) and answers them in one stem lookup, one chain walk and one suffix walk with all
  their flags (FlagProbe): 1,000 or 16,000 prefixes adding nothing no longer cost one walk
  each (h1.aff: 1.6 s → 17 ms per two words; 16k prefixes 22 s → 19 ms).
- Deferred suggestion candidates are not looked up again before their compound check.
- A word in capitals matches a mixed-case stem as a simple word only (`JQUERYKABEL`,
  `MSCFOO` wrong, as in the CLI).
- to_bytes writes the flags only the kept-apart homonyms use (NEEDAFFIX beside a compound
  flag survives a round trip).
- MAGIC WCAFF2: compact data from before homonyms were kept apart is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 03:59:36 +00:00
Martin BallandClaude Opus 5.5 b8efc5add9 CP7.4: craft-libs#497 re-review — hu prefixed suffix chains, homonyms kept apart, all-caps mixed-case stems; compound suggestions cheapest-first in one budget
- A prefix with two chained suffixes (hu `meg`+`épít`+`és`+`e`, eo `enjugo`): every rule
  cross, the prefix flag from the stem or a continuation class (CLI answers).
- Homonyms with different flags are kept apart (and written apart in the compact form):
  a prefix and a suffix, or a compound flag and a suffix, must come from one homonym
  (nl `afstopje`, `schuurpoederden` wrong in the CLI). nl now 100% in both comparisons.
- Hungarian syllable rule leaves out a last suffix with no continuation classes;
  COMPOUNDROOT counts on the stem only.
- Near-word check: a word listed as an ONLYINCOMPOUND/NEEDAFFIX stem counts only with a
  suffix, not a prefix (de `Fahrradverkehr` right).
- A word in capitals may be a mixed-case stem (`KB`/`KBS` from `kB/S`, hu `DNY`, nl `BSC`).
- Mixed-case retry keeps KEEPCASE for the first part; KEEPCASE kept apart from the other
  exclusions (NOSUGGEST sharing its flag is no longer cleared); overflow of the homonym
  groups counts as dropped.
- Suggestions: candidates are checked as simple words first; the rest get the compound
  check cheapest first, those changed where the word stops being parts before others, in
  one step budget per call, with piece analyses shared between candidates. The suggestions'
  stem scan makes forms in one shared budget (mn).
- affix_check example: `suggest` command; AffixDict::suggest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 03:18:31 +00:00
Martin BallandClaude Opus 5.5 3eaa276786 CP7.3: craft-libs#497 review — compounds as the hunspell CLI answers: ONLYINCOMPOUND homonyms keep their flags, triples after SIMPLIFIEDTRIPLE, KEEPCASE and capitals in parts, CHECKCOMPOUNDPATTERN 0, a forbidden prefix, FORCEUCASE; suggestions and many-way pieces stay cheap
- ONLYINCOMPOUND homonyms beside others are kept apart (compound parts only), so their suffixes
  make no standalone words (de verfilmungs, sv norges); round-trips as a second stem line.
- CHECKCOMPOUNDTRIPLE also checks a SIMPLIFIEDTRIPLE join (busssen, booob wrong).
- KEEPCASE holds for the first part only; a capitalized stem is a part (FooQux).
- CHECKCOMPOUNDPATTERN `0`: no suffix (a prefix doesn't count): unfoobar wrong.
- COMPOUNDFORBIDFLAG on a prefix: no part anywhere (bardefoo wrong).
- FORCEUCASE: from the stem only; wrong only without any capital (fooQuxbar right).
- Suggestion candidates: 2,048 compound steps each, compounds for the first 128 only.
- A piece's ways are hashed, capped at 256 and counted (with the patterns) against the budget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 02:08:35 +00:00
Martin BallandClaude Opus 5.5 9a442e7048 CP7.2: affix_check example — compare the affix engine with another checker's answers (black-box)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:43:54 +00:00
Martin BallandClaude Opus 5.5 87c7d1874a CP7.1: craft-proof reads flag-based compounding (COMPOUNDFLAG/BEGIN/MIDDLE/END, PERMITFLAG, FORBIDFLAG, ROOT, WORDMAX, SYLLABLE, CHECKCOMPOUND*, SIMPLIFIEDTRIPLE, FORCEUCASE), as the hunspell CLI answers
Black-box: every rule pinned to hunspell 1.7.5's answers on synthetic dictionaries and on
the Language packs' own files. Bounded work per word (16 parts, 65,536 steps). Also:
ONLYINCOMPOUND belongs to its homonym like NEEDAFFIX; COMPOUNDRULE reads the Swedish `)k`
and the Mongolian `[..]`, `%?`, `.` as the CLI does; COMPOUNDMORESUFFIXES is refused only
with flag-based compounding (Korean keeps loading).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:43:54 +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
Martin BallandClaude Opus 5.5 66d4dd3a5d CP4.2: review — pack names drop bidi/format characters, licence texts are capped in all, code() documented for Pack
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
Martin BallandClaude Opus 5.5 867f44a3d8 CP4.2: review — pack hyphenation patterns only take words in the language's script; others fall through as before
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
Martin BallandClaude Opus 5.5 930365bb6d CP4.2: review — a tag in its language's default script reads the script-less pack (sr-Cyrl → sr, bs-Latn → bs); scripts must be letters
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
Martin BallandClaude Opus 5.5 e35f35ef76 CP4.2: review — our own *-extra.txt supplements (ru-extra) stay embedded in the default build
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
Martin BallandClaude Opus 5.5 db341c5e15 CP4.2: review — pack dictionaries share a memory budget and a paragraph never evicts its own, so many languages load once
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
Martin BallandClaude Opus 5.5 2495fad496 CP4.2: review — German and Bulgarian are spelled from their pack; pack languages are checked in any script
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
Martin BallandClaude Opus 5.5 afbdede88e CP4.2: from_tag docs name ProofLang::Pack
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