* 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>
5.5 KiB
<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):
QUESTIONINGRESEARCHINGDEFINING REQUIREMENTSCREATING ROADMAPPLANNING PHASE {N}EXECUTING WAVE {N}VERIFYINGPHASE {N} COMPLETE ✓MILESTONE COMPLETE 🎉
Checkpoint Panels
User action required.
### CHECKPOINT: {Type}
{Content}
---
**→ {ACTION PROMPT}**
Types:
CHECKPOINT: Verification Required→→ Type "approved" or describe issuesCHECKPOINT: Decision Required→→ Select: option-a / option-bCHECKPOINT: 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>