Skip to content

Phase 31 slice A: the desktop-app type, the 24px spacing exception, folded results - #245

Merged
vicmaster merged 4 commits into
masterfrom
phase-31-slice-a
Nov 9, 2026
Merged

vicmaster merged 4 commits into
masterfrom
phase-31-slice-a

Conversation

@vicmaster

Copy link
Copy Markdown
Owner

Slice A of Phase 31 (docs/specs/PHASE-31-SPEC.md, FR-A1 to FR-A9 and FR-I1). It adds a third canvas type for application screens and fixes three things the viewer baseline found wrong on every type. The spec's "Slice A — as built" block records one approved spec change and twelve build decisions.

What changes

  • A desktop-app type. It is for a tool you work in, such as an editor, an admin console or a file browser, whether it runs in a browser tab or a native window. canvas_create({ type: "desktop-app" }) gives a 1440×900 window from the window-1440 profile, with no insets. canvas_set_type, list_structures and apply_structure accept the new type. A profile is taken only from the table that matches its type, so a phone profile on a desktop-app canvas is refused. Declaring the type never changes the render.
  • A rule id a type can switch off. The adjacent font-size ratio check becomes the default rule type-scale-ratio. The desktop-app ruleset turns it off, because dense apps step 12, 13 and 14px on purpose. A new base rule, desktop-app-artboard, warns when a desktop-app canvas is narrower than 1024px.
  • The 24px floor gains WCAG 2.5.8's spacing exception, on web and desktop-app. Every pointer target is now measured: the four controls and the clickable primitives (button, list-row, the tab-bar tabs, the nav-bar actions). A lone control still grows to its padded row first. A target that is still below 24px passes only when a 24px circle centred on it reaches no other target. That test needs rendered positions, so detailed mode runs it and reports an error when it fails. Fast mode warns instead, and the warning names detailed mode. Mobile keeps its 44px rule unchanged.
  • Navigation lists stop reading as tables, on every type. A list whose every row starts with an icon, a dot or a small image is navigation, not data. The viewer's project sidebar no longer demands empty and loading variants. A table with a text header row still detects, even when every data row starts with an avatar.
  • Results an agent can read. canvas_evaluate now folds repeated warnings and infos into one entry that carries nodeIds, count and fixes. Findings that carry a fix fold on the shape of their message, because each fix op holds its own node's values. Findings without a fix fold only when they read the same. Errors never fold, and canvas_autofix still works from the unfolded list. The import tools now return snapped, literals and scaleMatches grouped by token or value, and a new verbose: true input returns the full lists.
  • Generation. generate_design_system gives a desktop-app canvas a 14px body, or 13px for data-dense. Every generated system now writes a state section of element-state opacities (Material 3's values) and two control colors. focus-ring reaches 3:1 against every surface and tint token, and border-strong reaches 3:1 against the page and surface, in both themes.
  • The viewer opens a desktop-app canvas with window-width breakpoints (1024, 1280 and its own width) instead of the phone and tablet buttons.

The identity-dot correction (FR-A6) moved to slice B, because it depends on the nav-item primitive that slice adds.

Decisions worth a look

  1. The folding change went past the original spec, with your approval. Folding only infos could not shrink results enough, because most of the volume on an app screen is repeated spacing warnings that carry fixes. Warnings now fold too, and every fix stays in fixes. Verification then found that the first fold key merged findings with different numbers under one message. For example, a 1.07 ratio and a 2.67 ratio appeared as one warning. The final key never does that, which costs a few points of compression: the baseline detail page goes from 74,609 to 41,008 characters (55%). The spec's acceptance is amended to at most 58% and records the measured numbers.
  2. Fast mode now warns where it used to error. On web, a control still below 24px after its padded row used to be an error in both modes. It is now a fast-mode warning, and a detailed-mode error only when the circle test fails. The warning still blocks presenting. test-usability.ts is the only existing test whose expectations moved; it now checks both modes.
  3. A target the layout cannot place keeps blocking. When detailed mode cannot place a target, or a target's neighbour, the spacing exception cannot be proven, so the target keeps a blocking warning. This covers each tab in a too-narrow tab bar and anything nested deeper than the layout walker reaches.
  4. A known gap: a table whose header row also starts with a spacer reads as a list. The rule asks whether every row, including the first, starts with a mark. It is recorded as D9 in the spec, to revisit if a real table hits it.

Fixtures

The four viewer pages imported from framesmith 2.4.0 on 2026-11-08 are committed under test-fixtures/viewer-baseline/. Each embeds the repo workspace's design system so it resolves in the isolated test store. SHA-256:

  • archive.json 02c57c249c7d17a6ed81c77c90b5641a07588782a827ab240139d70da2cb34b5
  • detail-mobile-ridgeline.json 0845969623551d9f1c50c33189b82b035bdefc5f82da115b4bd50343390a8c40
  • detail-web-dashboard.json 30bc603a44946c2fcaa09bf6117ff5f00823c56cb89e1e287d2bdd8d75c6b851
  • gallery-pattern-library.json 2dc6523fda7eecec53542e24fc1acdf7731d6ff2fda20b1dfa714b087725800a

Testing

  • New test-desktop-app.ts (fast tier) covers the type, the ruleset, the artboard rule, the fast-mode census, the table discriminator, folding, the import summary, generation and contrast across four personalities, six seeds and both themes, the fixtures, and the viewer buttons.
  • New test-pointer-targets.ts (Chrome tier) covers the circle test in detailed mode on web and desktop-app. It checks spaced, touching and only-touching targets, overlapping circles, disabled neighbours, a too-narrow tab bar, and a neighbour the layout cannot place.
  • Four verifiers checked the first build: spec conformance, mutation testing, a bug review and a docs audit. Every confirmed finding is fixed, and a second-round verifier checked the fixes. The mutation run left survivors in the circle test, the window boundary, the fold key, the state values, the import grouping, the viewer buttons and the table discriminator; each one that mattered now has a test that kills it.
  • npm run test:fast: 83/83. npm run test:full: 121/121.

Phase 31 slice A. A third canvas type for tools you work in, with a window
profile and a ruleset that turns off the type-scale ratio. On web and
desktop-app the 24px floor measures every pointer target with WCAG 2.5.8's
spacing exception (detailed mode tests it, fast mode warns). Lists that lead
with a mark stop reading as tables. Evaluate folds repeated findings with
their fixes, import groups its report, and generation adds state tokens,
focus-ring and border-strong. The viewer baseline is committed as fixtures.
Verify round 1 on slice A. Unfixed findings fold only when they read the
same (a looser key showed one ratio for three). An undersized target whose
neighbour, or whose own tab, the layout cannot place keeps a blocking
warning. Docs, spec as-built notes and the stale usability test follow.
@vicmaster
vicmaster merged commit 6d71277 into master Nov 9, 2026
3 checks passed
@vicmaster
vicmaster deleted the phase-31-slice-a branch November 9, 2026 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant