Pular para o conteúdo

kds-sidebar-order

tools specs/tools/kds-sidebar-order.kmd

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-16 entries remain as editorial exceptions until owner reviews and either ratifies the editorial order (keeping the exception) or alphabetizes them (removing the exception). Tracked in tools/design-gen/backlog/pending/018-…kmd follow-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):

MirrorMirrors group
tools/design-gen/internal/kinds/principle.go::canonicalPrinciplesnav.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:

  1. Parse all @SidebarGroup(loc, loc.T("…"), "a/", "b/", …) blocks in tools/design-gen/internal/render/layout.templ.
  2. Extract the i18n key from the second argument.
  3. Check that the slug list is alphabetical UNLESS the i18n key has an exception in §R2.
  4. Auto-discover mirror lists (per §R3) by scanning tools/design-gen/internal/kinds/*.go, then verify slug order against the matched SidebarGroup.
  5. 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#011 ratification.
  • This spec does NOT govern the labels used in i18n keys. Curation is owner-driven per policies/document-format.kmd and feedback_kds_owner_curated_content.

History

  • 2026-05-16 — Initial draft, v0.1.0. Ratified alongside the alphabetical reorder of FOUNDATIONS (commit 690463b3ac of 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/*.go and registers majority-overlap mirrors without per-mirror hardcoding. T-R3-auto added. Completes tools/design-gen/backlog/pending/018-…kmd R3 final acceptance item.