Skip to content

feat(0.2): internal/uitokens/ design system foundation (Track 10.1)#136

Open
pmclSF wants to merge 1 commit intomainfrom
feat/0.2-design-tokens
Open

feat(0.2): internal/uitokens/ design system foundation (Track 10.1)#136
pmclSF wants to merge 1 commit intomainfrom
feat/0.2-design-tokens

Conversation

@pmclSF
Copy link
Copy Markdown
Owner

@pmclSF pmclSF commented May 2, 2026

Summary

Foundational deliverable for Track 10 (Visual & design system) from the 0.2.0 parity-gated release plan. `internal/uitokens/` is the design-system shim every user-visible renderer in 0.2.0 will consume from — terminal output, HTML report, PR-comment markdown, SARIF tags.

After this lands, ad-hoc styling outside the package becomes a parity-gate violation on the V1 (visual consistency) axis. Track 10.2 follows: migrate existing renderers + add a vet rule that flags raw ANSI codes outside `internal/uitokens/`.

What's in the package

  • Color tokens — six semantic colors (muted / accent / ok / warn / alert / bold). Names describe roles, not shades.
  • TTY / NO_COLOR detection — stdout TTY check + `NO_COLOR` env var + `TERM=dumb` fallback. Tests flip the flag to assert plain-text output.
  • Symbol vocabulary — one vocabulary (✓ ✗ ⚠ ⓘ → • — · ─) used across every command.
  • Severity model + badges — `SeverityBadge()` for the CRITICAL → INFO ladder; CRITICAL and HIGH bolded.
  • Verdict badges — `VerdictBadge("PASS"|"WARN"|"FAIL")` returns the canonical glyph + label combo.
  • Spacing & rules — `SectionWidth = 60`; `Heading()` / `Subheading()` return two-line blocks.
  • ASCII bar renderer — `Bar()` auto-colors by proportion; `BarPlain()` for inverse-polarity callers (e.g. coverage).
  • Text helpers — `Truncate` / `PadRight` / `PadLeft`; rune-aware.

Zero dependencies. Stateless. ~310 lines of code + ~280 lines of tests.

Tests (15 total, all passing)

  • Color wrappers respect `ColorEnabled` in both directions
  • Color wrappers no-op on empty strings (avoid escape-sequence noise)
  • Severity badges produce right labels and bold ≥ HIGH
  • Verdict badges canonicalize case + whitespace
  • Bar rendering: full / empty / half / overflow / negative / zero-max / zero-width
  • Bar coloring threshold transitions at 0.4 and 0.8
  • Truncate / PadRight / PadLeft handle unicode (e.g. "café" → "café…")
  • Rule and SubRule render at `SectionWidth`
  • `Heading` produces two lines (title + rule)
  • Color composition (`Bold(Alert(...))`) preserves both escapes

Test plan

  • `go test ./internal/uitokens/ -count=1` — all 15 tests pass
  • `go build ./...` clean
  • `go vet ./internal/uitokens/` clean

Plan link

`/Users/pzachary/.claude/plans/kind-mapping-turing.md` (Track 10.1).

Next: Track 10.2

Renderer audit + migration. Existing `internal/reporting/` / `internal/changescope/render.go` / etc. switch to consuming from this package; a static check flags any `\x1b[` outside `internal/uitokens/`. Separate PR.

🤖 Generated with Claude Code

Foundational deliverable for Track 10 (Visual & design system). Every
user-visible renderer in 0.2.0 — terminal output, HTML report,
PR-comment markdown, SARIF tags — consumes from this package. Ad-hoc
styling outside `internal/uitokens/` becomes a parity-gate violation
on the V1 (visual consistency) axis; Track 10.2 migrates existing
renderers to the tokens.

What's in the package:

  Color tokens
    Six semantic colors (muted / accent / ok / warn / alert / bold).
    Names describe ROLES not specific shades, so the underlying ANSI
    codes can change without rewriting callers. Wrappers (Muted, Ok,
    Warn, Alert, Bold) emit only when ColorEnabled is true; empty-
    input wraps are no-ops to avoid stray escape sequences.

  TTY / NO_COLOR detection
    ColorEnabled initialized once via stdout TTY check + NO_COLOR
    env var (https://no-color.org/) + TERM=dumb fallback. Pipes /
    file redirects automatically suppress color. Tests can flip the
    flag to assert plain-text output.

  Symbol vocabulary
    SymOK / SymFail / SymWarn / SymInfo / SymArrow / SymBullet /
    SymDash / SymDot / SymRule / SymSubrule. One vocabulary used
    across every command — the V2 (information rhythm) axis depends
    on this consistency.

  Severity model + badges
    SeverityCritical / High / Medium / Low / Info ladder with
    SeverityBadge() rendering. CRITICAL and HIGH bold so blocking
    findings stand out at a glance.

  Verdict badges
    VerdictBadge("PASS"|"WARN"|"FAIL") returns the canonical glyph +
    label combo used by the parity-gate matrix, AI risk review hero
    block, and policy check.

  Spacing & rules
    SectionWidth = 60 — every renderer uses this width for section
    rules so headings line up across commands. Heading() / Subheading()
    return ready-to-print two-line blocks.

  ASCII bar renderer
    BarChar / BarEmpty constants; Bar() with auto-coloring by
    proportion (≥80% alert, ≥40% warn, < muted); BarPlain() for
    callers that want inverse-polarity coloring (e.g. coverage,
    where high is good).

  Text helpers
    Truncate / PadRight / PadLeft — rune-aware, unicode-safe. Used
    by every table layout in the codebase once Track 10.2 migrates.

Tests (15 total, ~280 lines):
  - Color wrappers respect ColorEnabled in both directions
  - Color wrappers no-op on empty strings (avoid escape-sequence
    noise around "")
  - Severity badges produce the right labels
  - Severity badges bold ≥ HIGH
  - Verdict badges canonicalize case + whitespace
  - Bar rendering covers full / empty / half / overflow / negative /
    zero-max / zero-width
  - Bar coloring threshold transitions at 0.4 and 0.8
  - Truncate / PadRight / PadLeft handle unicode correctly
  - Rule and SubRule render at SectionWidth
  - Heading is two lines (title + rule)
  - Color composition (Bold(Alert(...))) preserves both escapes

Zero dependencies. Stateless. Tested at 100% coverage of public API.

Track 10.2 (renderer audit + migration) is the follow-on PR that
moves existing internal/reporting/* code paths to consume from here.
A vet rule that flags raw ANSI codes outside this package is also
on the Track 10.2 list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 2, 2026

[RISK] Terrain — Merge blocked

Significant protection gaps in changed code require attention.

Metric Value
Changed files 2 (1 source · 1 test)
Impacted units 22
Protection gaps 3
Tests selected 1 of 773 (0% of suite)

Coverage gaps in changed code

  • internal/uitokens/uitokens.go [MED] — Exported function BarChar has no observed test coverage.
    → Add unit tests for exported function BarChar — this is public API surface.
  • internal/uitokens/uitokens.go [MED] — Exported function BarEmpty has no observed test coverage.
    → Add unit tests for exported function BarEmpty — this is public API surface.
  • internal/uitokens/uitokens.go [MED] — Exported function Subheading has no observed test coverage.
    → Add unit tests for exported function Subheading — this is public API surface.

Pre-existing issues (2)

  • internal/uitokens/uitokens_test.go [MED] — [fixtureFragilityHotspot] Fixture 'runWithColor' is used by 15 tests across 1 files. A single change cascades widely.
  • internal/uitokens/uitokens_test.go [MED] — [fixtureFragilityHotspot] Fixture 'runWithoutColor' is used by 15 tests across 1 files. A single change cascades widely.

Recommended tests

1 test(s) with exact coverage of 19 impacted unit(s). 3 impacted unit(s) have no covering tests in the selected set.

Test Confidence Why
internal/uitokens/uitokens_test.go exact exact coverage of Accent, Alert, Bar + 16 more

Owners: PMCLSF

Limitations
  • No coverage artifacts provided; protection gaps reflect missing data, not measured absence. Provide --coverage to improve accuracy.
  • Mixed test cultures reduce cross-framework optimization confidence. Consider standardizing on fewer frameworks.

Generated by Terrain · terrain pr --json for machine-readable output

Targeted Test Results

Terrain selected 1 test(s) instead of the full suite.

  • Go tests: passed

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 2, 2026

Terrain AI Risk Review

Metric Value
AI surfaces 13
Eval scenarios 16
Impacted scenarios 0
Uncovered surfaces 13

Decision: PASS — AI surfaces are covered.

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