Files
msd-core/gsd-core/references/ui-brand.md
Tom Boucher cf15682d1c enhance(#3028): responsive Markdown separators instead of fixed-width rules (#3789)
* feat(#3028): responsive Markdown separators instead of fixed-width rules

Stage banners, checkpoints, completion and error panels used fixed-width
runs of box-drawing characters -- a 53-column heavy rule and a 62-column
double-line box. Those runs are ordinary text to a Markdown-rendering
host, so in a narrower pane they wrap and the border comes apart from
the heading it framed.

Shipped content now emits an ATX heading for a titled section and a
blank-line-delimited --- for a break between sections, both of which
adapt to the available width. The same convention is applied to the
three code sites that built these strings at runtime: the UAT
checkpoint renderer, the milestone-close audit report, and the TDD
review checkpoint table.

Removing the box also removes its only reason to exist -- the
east-asian-width padding helpers that kept its right border aligned
(checkpointBoxLine, displayWidth, isWideCodePoint, ZERO_WIDTH_MARK_RE,
CHECKPOINT_BOX_WIDTH). RTL directional isolation is unchanged.

The convention is specified in gsd-core/references/ui-brand.md and
enforced across all shipped content by tests/responsive-separators.test.cjs.

Refs #3028

* test(#3028): pin the heading form in checkpoint and audit-report assertions

These suites asserted the exact box borders and the 62-column padded
banner interior. With the box gone they assert the ### heading form,
the --- break and the bolded instruction line, and each now carries a
positive assertion that no box character remains -- which is what pins
the fix rather than merely tolerating it.

Language coverage is converted, not dropped: Japanese, Chinese, Korean,
Hindi and Arabic all still assert their rendered banner, and the Arabic
case still asserts the RTL directional isolates the box removal must
not disturb. Adds a case for a banner longer than the old inner width,
which previously produced a ragged border and now has none.

Refs #3028

* chore(#3028): acknowledge execute-plan.md growth from the checkpoint display spec

The checkpoint_protocol display spec described the drawn box; it now
describes the heading, the --- break and the bolded action prompt,
which costs 22 bytes (40111 -> 40133, 827 under the cap).

Appended to the existing #3370 fragment rather than filed as a new one:
a growth ack keys on the bare filename and #3370 already declares
execute-plan.md, so a second source naming it would be a hard
duplicate-key error. Same supersede-by-append route #3370 took for the
spent #2652 fragment.

Refs #3028

* docs(#3028): state the load-bearing half of the separator rule, and amend the zh-CN reference

Review found three things.

The rule as first written demanded a blank line above AND below every
---. Only the one above is load-bearing: it is what stops CommonMark
reading the rule as a setext underline for the line above. The one below
is cosmetic, because a thematic break is a leaf block. The rule now says
that, with the reason, instead of asserting a stricter form the content
does not keep.

The zh-CN reference had received the mechanical box-to-heading swap but
none of the prose behind it: it still claimed a 62-character checkpoint
width and still listed --- among forbidden mixed banner styles, so it
contradicted the convention it was translating. It now carries the
separator section, the setext reasoning, the unconditional-vs-per-runtime
rationale and a corrected anti-pattern list, in Chinese.

The user guide asserted that a heading is not a degradation anywhere.
That is an assertion, not a demonstration. It now says what was actually
traded away in a plain terminal, points at the recorded rationale, and
invites the report that would justify the capability flag instead.

Refs #3028

* chore(#3028): backfill changeset PR number

Refs #3028

---------

Co-authored-by: sim <sim@local>
2026-08-23 22:38:12 -04:00

5.5 KiB
Raw Blame History

<ui_patterns>

Visual patterns for user-facing GSD output. Orchestrators @-reference this file.

Separators and Banners

Never emit a fixed-width run of box-drawing characters. A run of ━, ─ or ═ is ordinary text to the host that renders your output. In a narrower pane it wraps, leaving orphan glyphs on a second line and coming apart from the heading it was meant to frame. Markdown adapts to the available width; a 53-character rule does not.

Three forms, and nothing else:

Need Emit
A titled section — stage, phase, checkpoint, completion, error ### {TITLE} (ATX heading)
A break between two sections --- on its own line, with a blank line above it
A framed panel of rows ### {TITLE} followed by the rows as plain lines

The blank line above --- is load-bearing, not cosmetic. A --- placed directly under a line of text is parsed as a setext heading underline for that line, not as a thematic break — the rule silently swallows the line above it. A blank line is what makes it a thematic break. (A blank line after --- is optional: a thematic break is a leaf block, so whatever follows starts a new block either way. Add one where it reads better.)

A stage banner is a heading alone — do not put a --- above it. An ATX heading already separates, and it cannot be misparsed the way a bare --- can.

Why this is unconditional, not per-runtime

The alternative considered was a rendersMarkdown capability key, keeping line-art for terminal-oriented runtimes and Markdown for Markdown hosts. It was rejected: it needs a new descriptor key across every runtime plus the resolver, and it leaves two output conventions to keep in sync forever — the divergence class this repo already has a defect entry for. A heading and a thematic break carry the same structure in a plain terminal that a rule pair did, without committing to a width, so the second convention buys nothing. If a runtime ever turns up that genuinely needs line-art, add the key then, against that evidence.


Stage Banners

Use for major workflow transitions.

### GSD ► {STAGE NAME}

Stage names (uppercase):

  • QUESTIONING
  • RESEARCHING
  • DEFINING REQUIREMENTS
  • CREATING ROADMAP
  • PLANNING PHASE {N}
  • EXECUTING WAVE {N}
  • VERIFYING
  • PHASE {N} COMPLETE ✓
  • MILESTONE COMPLETE 🎉

Checkpoint Panels

User action required.

### CHECKPOINT: {Type}

{Content}

---

**→ {ACTION PROMPT}**

Types:

  • CHECKPOINT: Verification Required → → Type "approved" or describe issues
  • CHECKPOINT: Decision Required → → Select: option-a / option-b
  • CHECKPOINT: Action Required → → Type "done" when complete

Status Symbols

✓  Complete / Passed / Verified
✗  Failed / Missing / Blocked
◆  In Progress
○  Pending
⚡ Auto-approved
⚠  Warning
🎉 Milestone complete (only in banner)

Status symbols are single characters, not runs — they do not wrap and are unaffected by the separator rule above.


Progress Display

Phase/milestone level:

Progress: ████████░░ 80%

Task level:

Tasks: 2/4 complete

Plan level:

Plans: 3/5 complete

The bar itself is a fixed 10-cell gauge, not a separator; it is intentionally fixed-width and stays as it is.


Spawning Indicators

Liveness convention: Every spawn announcement must carry the canonical phrase runs in a subagent inline so users know that silence during a subagent run is expected. Without this, a healthy 1–5 minute agent looks identical to a frozen session. Single spawns use the singular form; parallel spawns use the plural form.

◆ Spawning researcher... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)

◆ Spawning 4 researchers in parallel... (each runs in a subagent — no output until they return, ~1–5 min; expected, not a freeze)
  → Stack research
  → Features research
  → Architecture research
  → Pitfalls research

✓ Researcher complete: STACK.md written

Next Up Block

Always at end of major completions.

---

## ▶ Next Up

**{Identifier}: {Name}** — {one-line description}

`/clear` then:

`{copy-paste command}`

---

**Also available:**
- `/gsd-alternative-1` — description
- `/gsd-alternative-2` — description

Error Panel

### ERROR

{Error description}

**To fix:** {Resolution steps}

Tables

| Phase | Status | Plans | Progress |
|-------|--------|-------|----------|
| 1     | ✓      | 3/3   | 100%     |
| 2     | ◆      | 1/4   | 25%      |
| 3     | ○      | 0/2   | 0%       |

Table rules use ASCII -, never box-drawing characters.


Anti-Patterns

  • Fixed-width runs of ━, ─ or ═ as separators — they wrap in a narrow pane
  • Box panels drawn with double-line box characters (U+2554, U+2557, U+255A, U+255D, U+2551, U+2560, U+2563) — the borders wrap independently of their contents. They are named here by code point rather than shown, because the guard below rejects the characters themselves anywhere in shipped content.
  • A --- directly under a line of text with no blank line between — that is a setext heading underline, not a break, and it swallows the line above
  • Boxing a heading between two rules — the heading is the separator
  • Mixing banner styles (===, ***)
  • Skipping GSD ► prefix in banners
  • Random emoji (🚀, ✨, 💫)
  • Missing Next Up block after completions

Enforced by tests/responsive-separators.test.cjs.

</ui_patterns>