You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The French guillemets rule is prompt prose, and #81 already measured that this mechanism does not work for invisible characters. Filing it as its own issue, as proposed in #97's thread on 2026-07-16 ("probably its own issue rather than scope creep here") and never actually filed.
The rule as it exists today
src/language-config.ts carries it as instruction text in additionalRules for fr:
Use French guillemets « » (with a non-breaking space inside each, e.g. « citation ») for quotations rather than straight or curly double quotes
That is the entire enforcement. applyTypography() handles spacing around high punctuation but does not produce the interior form « mot », so nothing deterministic ever writes or checks it.
Why prompt prose cannot carry this rule
Closed #81 measured the analogous NBSP-before-high-punctuation rule and found 0% compliance across two models, identical on Sonnet 5 and Opus 4.8. The finding generalises: the model cannot perceive whether it emitted U+00A0 or U+0020, so no amount of prompt refinement fixes it and no model upgrade will either. This is the same class as #182 — a correctness rule expressed in prose to a component structurally unable to verify its own compliance.
Proposed fix
A deterministic transform: normalise « + optional whitespace → « , and optional whitespace + » → », on French output.
Implementation home is #172's write-path choke point, and the placement constraints recorded there are load-bearing — apply on raw model output before the heading map is built (heading matching is exact ===, so a post-map transform desynchronises map from body and silently drops or retranslates sections), and never map the transform over translatedFiles wholesale (it carries verbatim-English TOC files and bare-YAML state files that a frontmatter skip will not protect).
The French guillemets rule is prompt prose, and #81 already measured that this mechanism does not work for invisible characters. Filing it as its own issue, as proposed in #97's thread on 2026-07-16 ("probably its own issue rather than scope creep here") and never actually filed.
The rule as it exists today
src/language-config.tscarries it as instruction text inadditionalRulesforfr:That is the entire enforcement.
applyTypography()handles spacing around high punctuation but does not produce the interior form« mot », so nothing deterministic ever writes or checks it.Why prompt prose cannot carry this rule
Closed #81 measured the analogous NBSP-before-high-punctuation rule and found 0% compliance across two models, identical on Sonnet 5 and Opus 4.8. The finding generalises: the model cannot perceive whether it emitted U+00A0 or U+0020, so no amount of prompt refinement fixes it and no model upgrade will either. This is the same class as #182 — a correctness rule expressed in prose to a component structurally unable to verify its own compliance.
Proposed fix
A deterministic transform: normalise
«+ optional whitespace →«, and optional whitespace +»→», on French output.Implementation home is #172's write-path choke point, and the placement constraints recorded there are load-bearing — apply on raw model output before the heading map is built (heading matching is exact
===, so a post-map transform desynchronises map from body and silently drops or retranslates sections), and never map the transform overtranslatedFileswholesale (it carries verbatim-English TOC files and bare-YAML state files that a frontmatter skip will not protect).Notes
fronly for now, but the transform belongs in a per-language typography rule list rather than a French special case — that gets cheaper after tech-debt T5: WidenLanguageConfigand build rule lists once #174 widensLanguageConfig.Refs #97 (origin thread), #81 (why the prompt-side mechanism cannot work), #172 (implementation home), #182 (same failure class).