Skip to content

spec: improve default proportional font readability (#9953)#10226

Open
lonexreb wants to merge 5 commits intowarpdotdev:masterfrom
lonexreb:spec/9953-proportional-font
Open

spec: improve default proportional font readability (#9953)#10226
lonexreb wants to merge 5 commits intowarpdotdev:masterfrom
lonexreb:spec/9953-proportional-font

Conversation

@lonexreb
Copy link
Copy Markdown
Contributor

@lonexreb lonexreb commented May 6, 2026

Spec for #9953. New appearance.proportional_font_{family,size,line_height} settings with GitHub-baseline defaults (system-ui/Segoe UI Variable/Inter, 14px, 1.55). Settings → Appearance subsection with live preview.

Closes (spec-only) #9953.

@cla-bot cla-bot Bot added the cla-signed label May 6, 2026
@github-actions github-actions Bot added the external-contributor Indicates that a PR has been opened by someone outside the Warp team. label May 6, 2026
@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 6, 2026

@lonexreb

I'm starting a first review of this spec-only pull request.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This spec defines new proportional typography appearance settings, defaults, UI controls, acceptance criteria, and tests for Settings panes and rendered Markdown.

Concerns

  • The Linux default relies on Inter while the spec explicitly excludes bundling Inter, so default-install behavior is nondeterministic and may not meet the GitHub-baseline acceptance goal.
  • The font-family setting accepts arbitrary strings and syncs globally, but the spec does not define validation, missing-font fallback, cross-platform synced font behavior, or reset/default behavior.
  • The line-height setting name is inconsistent with the proportional_font_* naming pattern used for the other new settings.
  • Acceptance only checks size 18 even though the behavior contract permits size 24 and the test plan claims max-size coverage.

Verdict

Found: 0 critical, 3 important, 1 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread specs/GH9953/SPEC.md Outdated

- B1. New setting `appearance.proportional_font_family: String`
(default `"system-ui"` on macOS, `"Segoe UI Variable"` on
Windows, `"Inter"` then system fallback on Linux).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] This conflicts with the out-of-scope statement that Inter will not be bundled: a default Linux install without Inter will fall back unpredictably, so A1 cannot be deterministic. Specify a bundled-independent font stack or a tested platform fallback.

Comment thread specs/GH9953/SPEC.md Outdated
- B1. New setting `appearance.proportional_font_family: String`
(default `"system-ui"` on macOS, `"Segoe UI Variable"` on
Windows, `"Inter"` then system fallback on Linux).
Same `SyncToCloud::Globally(RespectUserSyncSetting::Yes)` as
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] Global sync for a platform-specific font family needs behavior for unavailable, empty, or OS-specific synced values. Define validation/fallback semantics and how users reset to the platform default.

Comment thread specs/GH9953/SPEC.md Outdated
`appearance.proportional_font_size: f32`
(default `14.0`, clamped to `[10.0, 24.0]`).
- B3. New setting
`appearance.proportional_line_height: f32`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 [SUGGESTION] The line-height setting drops the font_ segment used by appearance.proportional_font_family and appearance.proportional_font_size. Use one naming pattern so implementers do not create incompatible setting keys.

Comment thread specs/GH9953/SPEC.md Outdated
- A2. User can change the family in Settings → Appearance and the
change applies to Settings panes and rendered Markdown without
restart.
- A3. Increasing the size to 18 doesn't break Settings layout
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] The spec allows font size up to 24 but acceptance only requires layout safety at 18. Make the acceptance criterion cover the configured maximum, matching T5, so implementations cannot pass with broken max-size layout.

Co-Authored-By: Warp <agent@warp.dev>
@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 7, 2026

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 7, 2026

@lonexreb

I'm re-reviewing this spec-only pull request in response to a review request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This spec defines new proportional font family, size, and line-height settings intended to make Settings panes and rendered Markdown more readable.

Concerns

  • The target surface is ambiguous: the acceptance criteria mention Settings and Markdown, but the implementation pointer routes through app-wide Appearance state that many UI surfaces consume.
  • Size and line-height settings need the same persistence/sync metadata clarity as the family setting.
  • The test plan should align with the promised visual comparison and cover clamp boundaries for manually edited or synced values.

Verdict

Found: 0 critical, 1 important, 3 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread specs/GH9953/SPEC.md Outdated
Comment on lines +58 to +60
- A2. User can change the family in Settings → Appearance and the
change applies to Settings panes and rendered Markdown without
restart.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] The spec never defines whether these settings apply only to Settings/Markdown or to every consumer of the app-wide proportional Appearance font; clarify the intended surface area and any explicit exclusions so implementation does not unintentionally re-font or resize unrelated UI.

Comment thread specs/GH9953/SPEC.md Outdated
Comment on lines +36 to +41
- B2. New setting
`appearance.proportional_font_size: f32`
(default `14.0`, clamped to `[10.0, 24.0]`).
- B3. New setting
`appearance.proportional_font_line_height: f32`
(default `1.55`, clamped to `[1.0, 2.5]`).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 [SUGGESTION] State the persistence and SyncToCloud behavior for size and line height just like B1 does for family; otherwise implementers may sync only the family or choose inconsistent storage behavior for the other two settings.

Comment thread specs/GH9953/SPEC.md
`appearance.proportional_font_line_height: f32`
(default `1.55`, clamped to `[1.0, 2.5]`).
- B4. The default values are chosen to match GitHub's typography
baseline (1.5–1.6 line-height, 14–16px). Verified by side-by-side
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 [SUGGESTION] B4 says this is verified by a side-by-side screenshot in the test plan, but no test-plan item requires that screenshot; add the visual comparison step or remove this claim.

Comment thread specs/GH9953/SPEC.md Outdated
Comment on lines +77 to +78
- T1–T3. Setting round-trips for family / size /
proportional-font line-height.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 [SUGGESTION] Add tests for clamp boundaries and manually edited or synced out-of-range values for size and line height; round-trip coverage alone does not verify the [10, 24] and [1.0, 2.5] contracts.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

Round-1 fixes for oz-for-oss review: (1) Linux default now uses system-available stack (Cantarell/Ubuntu/Liberation Sans) since Inter isn't bundled; (2) added font-family validation rules, missing-font cascade behavior, per-platform sync schema with reset-to-default semantics; (3) renamed proportional_line_height to proportional_font_line_height for naming consistency; (4) added explicit size-24 + clamp-boundary acceptance and tests; (5) added Surface Scope subsection limiting V1 to Settings panes + rendered Markdown; (6) all three new settings now share persistence/sync metadata; (7) tests cover clamp, synced-unsupported-family fallback, and visual comparison.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 8, 2026

@lonexreb

I'm re-reviewing this spec-only pull request in response to a review request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

Reviewed the spec-only PR for GH-9953. The spec covers the problem, V1 surfaces, new appearance settings, per-platform sync behavior, acceptance criteria, implementation pointers, and test coverage.

Concerns

  • The default font stack is internally ambiguous around whether Inter participates in the default fallback order, which can lead to different platform behavior and unstable visual expectations.
  • The font-family validation contract allows quoted family names but does not specify canonical serialization or escaping before CSS use.

Security

  • The user-supplied and synced font-family value should be rendered from parsed, canonical family tokens rather than reused as a raw CSS string.

Verdict

Found: 0 critical, 2 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread specs/GH9953/SPEC.md Outdated
- Linux: a system-available stack —
`system-ui, "Cantarell", "Ubuntu", "Liberation Sans",
"DejaVu Sans", "Noto Sans", sans-serif`.
Inter is preferred where the user has installed it, but is
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] This says Inter is preferred when installed, but the platform stacks above do not include Inter and A1 says a default install uses the platform Default stack. Specify the exact stack/order per OS, including whether Inter is ever part of Default, so implementation and visual tests are deterministic.

Comment thread specs/GH9953/SPEC.md Outdated
- B1a. **Validation.** A non-empty user-supplied value is parsed
as a CSS family-list string. Allowed characters per family:
alphanumerics, ASCII spaces, hyphens, periods, and underscores.
Family names containing other characters MUST be quoted with
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] [SECURITY] Quoted family names can include characters outside the allowlist, but the spec does not require canonical serialization or escaping before CSS use. Require rendering from parsed tokens with quotes, backslashes, and control characters escaped or rejected, and add injection-like validation tests.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

Round-2 fixes: (1) per-platform defaults explicitly stated WITHOUT Inter — macOS uses -apple-system, SF Pro Text, Windows uses Segoe UI Variable, Segoe UI, Linux uses Cantarell, Ubuntu, Liberation Sans; spec note clarifies Inter must be opted-in by user config; (2) canonical serialization for font-family per CSS Fonts L4 — unquoted for simple identifiers, double-quoted with backslash-escaping for special chars; storage/sync use canonical form with round-trip identity; (3) render path is parsed-token-list -> CSS-string via dedicated serializer (no raw-string interpolation), preventing CSS injection; family-list parser/serializer module exposed and renderer takes &FamilyList not &str to enforce at the type level; added tests T_canonical_serialization, T_canonical_quoting, T_inter_not_in_default, T_render_no_injection.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 8, 2026

@lonexreb

I'm re-reviewing this spec-only pull request in response to a review request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This spec defines new proportional font appearance settings, per-platform defaults, sync behavior, Settings UI controls, and rendering/test expectations.

Concerns

  • The font resolution contract treats fallback entries as installed fonts, but the default/user stacks include CSS generic families, leaving cross-platform resolution undefined.
  • Canonical serialization has an ambiguous case-normalization requirement, so implementations and tests may disagree on stored values.

Security

  • The CSS-injection guard assumes quoted CSS strings prevent </style> breakouts; that is not safe if CSS is ever written into a style text context. The spec should require CSSOM/style-property assignment or escaping HTML end-tag sequences and test the actual render insertion path.

Verdict

Found: 0 critical, 3 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread specs/GH9953/SPEC.md
rule id (never the raw value).

- B1b. **Missing-font fallback.** Resolution proceeds left-to-right
through the parsed family list. If no listed family matches an
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] This fallback rule is undefined for generic CSS families in the default/user stacks (system-ui, sans-serif): they are not installed font names, so specify whether generic families bypass installed-font matching and are delegated to the platform renderer.

Comment thread specs/GH9953/SPEC.md Outdated
always `String -> ParsedFamilyList -> CssString`, never
`String -> CssString`. This eliminates CSS injection vectors
via crafted family names (e.g., a family name containing
`</style><script>` cannot break out of the CSS context because
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] [SECURITY] Quoting as a CSS string and escaping only quotes/backslashes is not enough if this declaration is ever emitted into a <style> text node: the HTML parser can still terminate on </style>. Require CSSOM/style-property assignment or escaping </end-tag sequences, and test that exact render path.

Comment thread specs/GH9953/SPEC.md Outdated
with an inline error; the previous canonical value is retained.
- A7. Canonical-form round-trip: writing
`inter , "Open Sans" ,Arial` (with stray spaces) is stored as
`Inter, "Open Sans", Arial` (or the user's preferred case).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] B1a never defines case normalization, but A7 allows either Inter or the user's preferred case; choose one deterministic rule (preserve input case or normalize with explicit rules) so canonical storage and tests cannot diverge.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

Addressed all 3 important concerns from latest oz-for-oss review:

Generic-family resolution defined (important #1)
Added 'Generic-family entries in the cascade' subsection classifying every family-list entry into 3 classes:

  • Class 1 (CSS generic keywords: system-ui, sans-serif, etc.) — emitted as-is, font engine resolves; NOT subject to the installed-font check (this was the gap the bot flagged).
  • Class 2 (vendor-prefixed: -apple-system) — recognized on matching platform, treated missing elsewhere.
  • Class 3 (named families) — the ONLY class B1b's installed-font cascade applies to.

Walks the macOS Default stack on Linux as a worked example. New test T_generic_families_resolve exercises each platform Default stack plus deliberate misses to confirm the cascade does NOT fall through past class-1 entries on the basis of 'not installed.'

Canonical case-normalization disambiguated (important #2)
B1a now has explicit, ordered normalization rules:

  • Internal whitespace in unquoted identifiers collapsed to single ASCII space.
  • Case preserved verbatim from user input for both unquoted and quoted named families. (The round-2 'or the user's preferred case' parenthetical was the ambiguity.)
  • Class-1 generic and class-2 vendor-prefixed identifiers normalized to lowercase (closed-set canonicalization).

Full case-rule table added showing all combinations. A7 rewritten: inter, ... stays inter. Writing SYSTEM-UI stores system-ui. New test T_canonical_case enforces byte-for-byte the canonicalized values.

CSS-injection guard at actual render path (important #3 / security)
B1e now has two layers: Layer 1 (CSS quoting) is necessary; Layer 2 (insertion-context safety) is REQUIRED. Two safe paths:

  • (a) CSSOM / style-property assignment — V1 default. Browser parses through CSS parser, never HTML tokenizer; </style> is inert.
  • (b) <style>-text-node fallback — only allowed when the serializer additionally emits \\3c\\2f (or equivalent) for every </ inside quoted family tokens, defeating the HTML tokenizer's </style lookahead.

Two entry points: to_css_for_style_property() and to_css_for_inline_style_tag(). Type system enforces declaration of which path. A8 rewritten to test the actual render path. T_render_no_injection split into T_render_no_injection_property_path (drives real DOM render, asserts window.__injected_alert__ is unset) and T_render_no_injection_style_tag_path (asserts \\3c\\2f escape, no HTML breakout).

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

/oz-review

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

Labels

cla-signed external-contributor Indicates that a PR has been opened by someone outside the Warp team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant