Skip to content

French guillemets interior NBSP is prompt-only — needs a deterministic transform #217

Description

@mmcky

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).

Notes

  • Scope is fr only 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: Widen LanguageConfig and build rule lists once #174 widens LanguageConfig.
  • Worth a deterministic reviewer check alongside it, so existing French content can be audited rather than only new output being corrected.
  • The prose rule should stay in the prompt as a hint; the transform is what makes it true.

Refs #97 (origin thread), #81 (why the prompt-side mechanism cannot work), #172 (implementation home), #182 (same failure class).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions