---
title: "fak UI/UX-quality scorecard - the terminal-surface stick"
description: "fak's deterministic UI/UX-quality scorecard: does every fak console pane, the fak info overlay, and fak guard --split render correctly and legibly - rune-safe truncation, cell-aware column pads, empty-state branches, full info-legend and console-help coverage - folded into a ui_quality_debt count."
---

# UI/UX-quality scorecard

_Auto-generated by `fak ui-quality-scorecard --markdown`. Do not hand-edit; re-run the tool._

The sibling scorecards each watch one surface — `code_quality_scorecard` the Go
module, `observability_scorecard` the metrics plane, `docs_scorecard` the curated
docs. None of them watch the surface an operator actually **looks at**: the
`fak console` panes, the `fak info` overlay beside a guarded session, and the
`fak guard --split` launcher. "Improve the guard TUI" was a vibe; this is the
number that makes it a falsifiable target.

It grades the render source on mechanical KPIs in three groups, cross-checked
against the tree so the score cannot be gamed by editing a data file — the render
source itself is the oracle:

- **correctness** — the bytes the terminal draws are right: `rune_safety` (no
  byte-indexed truncation that can split a multibyte rune; cell-aware width
  helpers present), `width_consistency` (no width-padded `%-Ns` verb consuming a
  bare `trimTUI` column, which would shear every column to its right on a
  multibyte row), `empty_state` (every list pane has an explicit no-rows branch),
  `header_alignment` (a list pane's literal column header and its row format are a
  matched pair, pinned aligned — a change to one without the other is flagged as
  silent header drift).
- **legibility** — a reader can decode what they see: `legend_coverage` (every
  term on the `fak info` line is expanded in the legend), `help_completeness`
  (every `fak console` subcommand is documented in the usage text).
- **hygiene** — output stays clean across contexts: `ansi_discipline` (raw ANSI
  escapes only in the one documented redraw helper), `tty_degradation` (the
  in-place redraw is gated on a terminal probe so a piped/captured run never has
  escapes leaked into it).

The headline metric is **ui_quality_debt**: the count of HARD defects — a
byte-sliced column that can emit a half rune, a renderer that byte-pads a trimmed
column, a pane with no empty-state line, an info-line term with no legend entry,
a subcommand missing from help. Driving it toward zero is what lets an operator
trust what the panes draw. Re-run with `--compare base.json` to prove the number
moved.

The first ship retired 4 units: the `trimTUI` truncation byte-sliced multibyte
UTF-8 (`s[:width-3]`), so a cut inside a 3-byte em-dash or 4-byte emoji emitted a
half rune the terminal draws as a replacement glyph, silently corrupting any
column carrying non-ASCII text. The fix made truncation accumulate whole runes by
display width and added a cell-aware column pad.

**CLEAN** — ui_quality_debt=0, score 100 (A)

> every graded render KPI is clean: rune-safe truncation, honored width budgets, empty-state branches, complete legend + help.

| KPI | group | score | hard | detail |
|---|---|---:|:---:|---|
| rune-safe truncation | correctness | 100 | ✓ | truncation accumulates whole runes by display width; columns pad cell-aware |
| width-budget honored | correctness | 100 | ✓ | no width-padded verb consumes a bare trimTUI column; multibyte rows stay aligned |
| empty-state branch | correctness | 100 | ✓ | every list pane has an explicit no-rows branch |
| header/column alignment | correctness | 100 | ✓ | 2 fixed-header pane(s) still aligned to their pinned row format |
| info legend coverage | legibility | 100 | ✓ | every info-line term is expanded in the legend |
| console help coverage | legibility | 100 | ✓ | all 7 console subcommands documented in help |
| ANSI escape discipline | hygiene | 100 |  | raw ANSI confined to the documented redraw path |
| TTY-gated redraw | hygiene | 100 |  | in-place redraw gated on term.IsTerminal; piped output stays clean |

**ui_quality_debt:** 0

**Next:** keep the panes clean on the next render change; re-run with --compare to prove no regression.
