render: the bidi marker fires on Fluent's routine FSI/PDI isolates #258
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis#258
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
The REQ-909 bidi marker fires on every U+2066–U+2069 occurrence, including the well-formed
FSI … PDIpair thatfluent-bundlewraps around every placeable. Fluent'sFluentBundlehasuse_isolating = trueby default, so any Fluent-localized program emits these on ordinary output —fjdoes it on most of its messages. The result is a yellow marker on routine, non-hostile text.This is a scope question about the flag rule, not a detection error. Split out of #257, which covers
the separate rendering defect (the marker overwrites the preceding character).
Why this is worth revisiting
The nine codepoints really are the Trojan Source primitives, and
bidi::is_overrideflagging allnine matches what rustc's deny-by-default
text_direction_codepoint_in_literal/text_direction_codepoint_in_commentlints do. But rustc lints source code, where a bidi controlis almost never legitimate. A terminal renders program output, where a balanced
FSI … PDIaroundan LTR span is routine and produces no visual reordering at all.
What makes Trojan Source an attack is reordering the reader actually sees: an unbalanced isolate or
embedding, or an explicit override (
LRO/RLO). A closedFSI … PDIpair whose content holds noRTL characters and no other bidi control changes nothing on screen.
So the current rule marks a large volume of text that carries no attack, and a marker that appears on
ordinary output stops being read as a warning. That erodes the reader protection REQ-909 exists to
provide.
Constraint
felis performs no UAX#9 paragraph reordering, and that is a recorded non-goal
(
docs/explanation/non-goals.md:103,docs/explanation/rendering/text-shaping.md:305). Anynarrowing must not smuggle paragraph bidi in through the back door. Today's check is per-cell and
stateless (
cell_contains_bidi_override,crates/felis-render-wgpu/src/instances.rs:1070).Directions to weigh
FSI/LRI/RLI…PDIpair that closes onthe same line and whose enclosed span contains no RTL character and no further bidi control. Flag
everything else, including every
U+202A–U+202Eand every unbalanced isolate. This needs linestate, not paragraph reordering, so it stays inside the non-goal.
security-model.md"Text rendering" and REQ-909 both say themarker renders "by default", but no config key turns it off — the wording promises a knob the
implementation does not have. Either add the key or drop the words.
Whatever lands
The decision belongs inline in
docs/explanation/security-model.md"Text rendering" (rationale,rejected alternatives, revisit trigger), with REQ-909 in
docs/reference/spec.mdrestated to match.The
felis-vtunit tests fix the accept-set at exactly nine codepoints(
exactly_nine_codepoints_are_overrides), so a narrowed rule needs its own tests at whichever layergains the line context.