kds-sidebar-order
Corpo da especificação
Spec: KDS sidebar order
Defines the ordering criterion for entries within each @SidebarGroup
of the KDS site sidebar (tools/design-gen/internal/render/layout.templ)
and any code-side mirror lists (internal/kinds/<group>.go).
R1 — Default: alphabetical by slug
Within every @SidebarGroup, links MUST be rendered in alphabetical order
by slug (the URL segment passed to @SidebarLink), locale-independent.
- Rationale: scales to N>5 without re-litigating order on each addition; applies uniformly across all groups; mechanically auditable in CI; preserves muscle memory across locale switches (slug is locale-stable even though label is translated).
- The slug list argument to
@SidebarGroup(…, "a/", "b/", …)MUST match the order of the@SidebarLink(…)calls inside the body, and BOTH MUST be alphabetical.
Worked example:
@SidebarGroup(loc, loc.T("nav.group.foundations"),
"a11y/", "performance/", "privacy/", "security/", "usability/") {
@SidebarLink(loc, "a11y/", loc.T("nav.a11y"))
@SidebarLink(loc, "performance/", loc.T("nav.performance"))
@SidebarLink(loc, "privacy/", loc.T("nav.privacy"))
@SidebarLink(loc, "security/", loc.T("nav.security"))
@SidebarLink(loc, "usability/", loc.T("nav.usability"))
}
R2 — Editorial-order exceptions
A group MAY override R1 with editorial ordering when a semantic sequence exists. Currently grandfathered:
| Group slug (i18n key) | Justification |
|---|---|
nav.group.start (INÍCIO) | Onboarding flow: Primeiros passos → Sobre o KDS → Histórico de mudanças. Order is a learning sequence, not an alphabetical surface. |
nav.group.styles (Styles) | Editorial — current order: verge / style / themes / icons / motion. Grandfathered 2026-05-16: shipped pre-spec via ticket #011; owner has not yet decided whether to alphabetize. Audit treats this as an exception until owner ratifies. |
nav.group.components (Components) | Editorial — current order: components / patterns / flows / anti-patterns. Grandfathered 2026-05-16: shipped pre-spec via ticket #011. Same status as above. |
nav.group.develop (Develop) | Editorial — current order: voice / media / coverage / reference. Grandfathered 2026-05-16: shipped pre-spec via ticket #011. Same status as above. |
nav.tools (Tools) | Editorial — current order: tools / themer / contrast / style-builder / playground / migrate. The first "tools" entry is the catalog index; tools follow. Grandfathered 2026-05-16: shipped pre-spec via ticket #011. Same status as above. |
Owner-decision pending: the four
Grandfathered 2026-05-16entries remain as editorial exceptions until owner reviews and either ratifies the editorial order (keeping the exception) or alphabetizes them (removing the exception). Tracked intools/design-gen/backlog/pending/018-…kmdfollow-up section.
Adding a new exception requires updating this table in the same commit as the layout.templ change. The audit script (see R5) treats the table as the source of truth — any group not listed here MUST be alphabetical.
R3 — Mirror lists MUST agree
Code that mirrors a SidebarGroup (e.g. internal/kinds/principle.go:: canonicalPrinciples mirrors the nav.group.foundations group) MUST list
entries in the same order as the SidebarGroup, which by R1 is alphabetical
unless R2 grants an exception.
Known mirror lists (audit MUST cover all):
| Mirror | Mirrors group |
|---|---|
tools/design-gen/internal/kinds/principle.go::canonicalPrinciples | nav.group.foundations |
Discovery for new mirrors (implemented 2026-05-18, R3-auto-discovery
check): the audit walks tools/design-gen/internal/kinds/*.go and
registers any var canonical* = []T{ {Slug: "…"}, … } whose slug set
has majority overlap with a SidebarGroup's slug set. Match thresholds:
shared slugs ≥ 2 AND ≥ 50% of the mirror's own slugs. The thresholds
exist to keep canonicalPresets (19 entries, one slug "verge" that
coincidentally matches the styles group) out of the mirror list. The
discovered mirror set is emitted in the JSON report under
discovered_mirrors. New canonical* mirrors are picked up
automatically — no edit to the audit code is required.
When the matched group is in the §R2 exception table (editorial order), R3-part-A (mirror is itself alphabetical) is skipped — the mirror MUST follow the same editorial sequence as the group.
R4 — Locale labels MAY break alphabetical
The slug ordering is locale-independent. Translated labels in i18n
(en-US.json, pt-BR.json, future locales) may render in apparent
non-alphabetical order in one or more locales. This is a deliberate
trade-off: locale-stable muscle memory > per-locale alphabetical
prettiness.
Example: in pt-BR, the FOUNDATIONS group renders as Acessibilidade, Performance, Privacidade, Segurança, Usabilidade — alphabetical by slug
(a11y < performance < privacy < security < usability), but NOT alphabetical
by pt-BR label (where Performance would come after Privacidade).
R5 — Audit script
koder-spec-audit sidebar-order (severity: hard as of 2026-05-16
when the subcommand shipped — see products/dev/koder-tools/backlog/done/ 012-sidebar-order-audit-subcommand.kmd) MUST:
- Parse all
@SidebarGroup(loc, loc.T("…"), "a/", "b/", …)blocks intools/design-gen/internal/render/layout.templ. - Extract the i18n key from the second argument.
- Check that the slug list is alphabetical UNLESS the i18n key has an exception in §R2.
- Auto-discover mirror lists (per §R3) by scanning
tools/design-gen/internal/kinds/*.go, then verify slug order against the matched SidebarGroup. - Exit 1 on any drift; exit 0 if clean.
The script is declared in the audit: block of this spec's frontmatter,
so koder-spec-audit run (the generic dispatcher) picks it up
automatically once implemented.
R6 — Spec ↔ code exception-table sync
The set of i18n keys exempted in §R2 above MUST equal the set of keys in
the Go map exceptionGroups of
products/dev/koder-tools/cmd/koder-spec-audit/sidebar_order.go.
The two live in different files (markdown vs Go) for legibility — the spec table carries rationale; the Go map is the runtime check. Drift between them is a silent contract bug: a group could be exempted in spec text but still flagged by the audit, or vice versa.
The audit script (R5) MUST parse the §R2 table and the Go map and report any asymmetric difference (key in one but not the other).
T1 — Conformance test
Audit on a clean checkout (post-commit 690463b3ac) MUST report zero
drifts.
T2 — Drift detection test
Manually swap two consecutive SidebarLinks in layout.templ and re-run
the audit. MUST exit 1 and identify the affected group + the violating
slug pair.
T-R6 — Spec/code sync drift test
Edit the §R2 table to add a fake key (e.g. nav.group.foobar) or
remove an existing key without updating exceptionGroups. Audit MUST
exit 1 with R6-spec-code-sync failures naming both sides of the
asymmetry.
T3 — Mirror drift test
Manually reorder canonicalPrinciples in principle.go. MUST exit 1
and identify the mirror file + the mismatched slug list vs the
canonical SidebarGroup.
T-R3-auto — Mirror auto-discovery test
Run the audit on a clean checkout. The text output MUST contain
mirrors: N (auto-discovered) with N ≥ 1, and the JSON output MUST
include discovered_mirrors[] listing
tools/design-gen/internal/kinds/principle.go::canonicalPrinciples → nav.group.foundations. False-positive guardrail: canonicalPresets
in uistyle.go (whose "verge" slug coincides with the styles group)
MUST NOT appear in discovered_mirrors.
Non-goals
- This spec does NOT govern cross-group ordering (i.e. the order of
the top-level groups themselves: INÍCIO / Foundations / Visual / etc.).
That stays editorial per
tools/design-gen#011ratification. - This spec does NOT govern the labels used in i18n keys. Curation
is owner-driven per
policies/document-format.kmdandfeedback_kds_owner_curated_content.
History
- 2026-05-16 — Initial draft, v0.1.0. Ratified alongside the
alphabetical reorder of FOUNDATIONS (commit
690463b3acof the koder monorepo) per owner question "qual critério vc usou pra ordenar o menu lateral?". - 2026-05-18 — R3 auto-discovery shipped. Audit now scans
tools/design-gen/internal/kinds/*.goand registers majority-overlap mirrors without per-mirror hardcoding. T-R3-auto added. Completestools/design-gen/backlog/pending/018-…kmdR3 final acceptance item.