Kanon — the named, versioned, non-Turing-complete rule-expression language + the declarative evaluator that replaces hardcoded Go checkers
Document format reference: meta/docs/stack/policies/document-format.kmd
Status: ACCEPTED 2026-06-11 (owner) — variante c da deliberação
/k-archde 2026-06-11 (sessão notebook), que fundiu deliberadamente "EBNF da gramática" (B1 do levantamento t25) com "RFC do motor" (C1): gramática-sem-motor e motor-sem-gramática são o mesmo erro em direções opostas. Naming: "Kanon" (gr. kanōn, régua/regra — Pattern B, K-word distinto) RATIFICADO pelo owner em 2026-06-11 (/k-gosobre a recomendação desta sessão); registrado emcomponent-names.md.
1. Contexto e problema
O avaliador da Stack existe — koder-spec-audit — mas cada regra é um checker Go hardcoded (imports.go, naming.go, topbar_placement.go, always_on.go, self_hosted.go, project_layout.go, sidebar_order.go, …). Regra nova = código novo + release do koder-tools. E as expressões que o plano de governança precisa (applies_when, forall, refines, verify_by) já estavam nascendo como strings ad-hoc em frontmatter — uma DSL de fato, sem nome, sem gramática, sem versão, sem corpus. Esse é o pior dos dois mundos.
2. Decisão — embutir o transporte, formalizar a carga
A deliberação do dia (t21–t23 + síntese da sessão notebook) fixou o desenho estratificado:
- Obrigações (Requirement/Scenario — texto humano-primeiro) ficam *mbutidas
no
.kmd*(RFC-013). Não há segundo documento; zero dupla-representação. - Expressões de regra (predicados, quantificadores, composição, binding) são
uma linguagem nomeada — Kanon — com EBNF, versão e corpus de teste próprios desde o dia 1, mesmo que o transporte seja frontmatter/fences dentro do
.kmdpor anos. Embutir o transporte; formalizar a carga.
Esse é o seam motor↔conteúdo da D9 (reversibilidade): se a fase de produto (RFC-016 F3) exigir Kanon em arquivo próprio, a extração move texto entre portadores — a semântica, o parser e os testes não se reescrevem.
3. Requisitos normativos
- R1 (não-Turing-completa, desde a fase 1 — não só pra tenants). Kanon é
total e decidível: sem recursão definida pelo usuário, sem iteração ilimitada; quantificadores só sobre domínios finitos (o grafo de componentes/arquivos). Terminação garantida = analisabilidade (D11) e detecção de conflito (fase 4).
- R2 (válvula de escape é Go, não extensão). Regra que não cabe na
expressividade de Kanon vira checker Go nomeado — nunca se estende a linguagem para um caso. Extensões da gramática exigem revisão desta RFC (bump de versão da linguagem).
- R3 (versionamento). Todo documento que carrega Kanon declara
kanon: "<major.minor>"; o avaliador rejeita versão que não suporta (erro nomeado, nunca silêncio). - R4 (uma linguagem, um avaliador). Kanon é avaliada exclusivamente pelo
motor no
koder-spec-audit(extraível depois, RFC-016 F1). Proibido segundo interpretador parcial (hookCI reusam o motor via CLIlib, não reimplementam). - R5 (corpus como contrato). O corpus de expressões (fase 1) é o teste de
conformidade do motor; toda feature de linguagem nova entra com casos positivos E negativos no corpus antes do motor.
4. Critério de absorção (medida de sucesso)
A fase 3 deve provar a absorção de regras estruturais reais com saída idêntica (golden) antes de regra nova nascer em Kanon. Retificação (2026-06-11, slice 1): sidebar_order foi RECLASSIFICADO — é heurística de conteúdo de código de UI, não query estrutural; permanece Go por aplicação da própria R2 (válvula de escape). Alvos golden válidos: as regras de EXISTÊNCIA do projectlayout (LAYOUT-README provada golden no slice 1 e ABSORVIDA de fato no slice 2 — regra Go removida, dona é a kanon_rules: em specs/code/project-layout.kmd) e regras de grafo tipo "Sector com app/ tem landing/" (domínio sector — shippado como extensão 0.5 no slice 2; 0.30.4 foram consumidas no meio-tempo por refinesbindings). Meta de regime ATINGIDA: regra estrutural nova entra como dado (kanon_rules: no frontmatter, avaliada por structural em lote), sem release do koder-tools.
5. Não-objetivos
Substituir o .kmd (Kanon é carga, não portador); authoring multi-tenant e sandbox de tenant (RFC-016 F3 — herdam R1 prontos); reimplementar o kmd lint (RFC-013 fase 2 segue em engines/lang/kmd#008, e o lint apenas valida que fences kanon parseiam, delegando ao motor).