Audit Frontmatter

audit specs/audit/frontmatter.kmd

Convenção do bloco `audit:` em frontmatter YAML de specs e policies. Permite que a engine `koder-spec-audit` descubra dinamicamente quais módulos auditar contra cada spec/policy, sem hardcoding em comando. Toda spec/policy auditável segue este schema.

When this spec applies

All triggers

Specification body

Spec — Audit Frontmatter

Toda spec ou policy que pode ser auditada automaticamente declara um bloco audit: no frontmatter YAML. A engine koder-spec-audit percorre todos os arquivos .kmd em meta/docs/stack/{specs,policies}/, lê este bloco, e executa o audit script contra os módulos que casam com applicable_to.

Schema

audit:
  applicable_to:                # required: lista de seletores
    - "<glob de paths>"         # ex: "products/**/app/{mobile,desktop,web,tv}"
    - "component_type in [<types>]"   # alternativa: tipo da coverage-matrix
    - "always"                  # caso especial: aplica a tudo
  script: ./<filename>.sh       # required: sibling do .kmd
  severity: hard | advisory     # required: hard bloqueia commit; advisory reporta
  exit_codes:                   # optional: customizar exit codes
    pass: 0
    drift: 1
    error: 2
  output_format: json           # optional: default json (RFC-001 §4)

Campos

applicable_to (required)

Lista de seletores que define quais módulos do monorepo são auditados contra esta spec/policy.

Forms aceitas:

Form Exemplo Semântica
Glob de path "products/**/app/{mobile,desktop,web,tv}" shell glob; expande pra lista de paths
component_type in [...] "component_type in [app/desktop, app/web]" tipos canônicos da coverage-matrix meta/docs/stack/specs/testing/coverage-matrix.md
always "always" aplica a Stack toda (ex.: policies/stack-principles.kmd)
never "never" spec não-auditável programaticamente (raríssimo)

Combinação: múltiplas linhas em applicable_to são tratadas como união (OR). Pra interseção, expressar no script.

script (required)

Path relativo do audit script, sibling do arquivo .kmd. Convenção: mesmo basename do .kmd + -audit.sh.

Ex.: policies/code-first.kmdpolicies/code-first-audit.sh.

Tipo do arquivo: shell script (preferred), Python script, ou binário. Tem que ser executável.

Contrato:

#!/usr/bin/env bash
# Recebe: $1 = path absoluto do módulo a auditar
# Stdout: JSON com formato RFC-001 §4 (applied / deferred / errors)
# Stderr: warnings/info pra debug humano
# Exit:
#   0 = pass (sem drift)
#   1 = drift detectado (severity:hard bloqueia; severity:advisory reporta)
#   2 = erro interno do script (sempre abortar com mensagem)

severity (required)

Valor Quando Audit failure
hard spec normativa, conformidade testável aborta pre-commit; bloqueia release
advisory policy comportamental, princípio só reporta no /k-housekeep Fase 0.5; não bloqueia

Ver policies/stack-principles.kmd pra distinção spec vs policy.

exit_codes (optional)

Override padrão se o script tem semântica diferente. Default:

exit_codes:
  pass: 0
  drift: 1
  error: 2

output_format (optional)

Default json per RFC-001 §4 do dev/koder-tools. Outras opções (text, tap) podem ser adicionadas no futuro.

Exemplo completo

meta/docs/stack/specs/themes/ui-style.kmd (a criar em ETAPA 2.2):

---
name: UI Style
type: spec
mandatory: true
audit:
  applicable_to:
    - "products/**/app/{desktop,web}"
    - "services/**/app/{desktop,web}"
  script: ./ui-style-audit.sh
  severity: hard
summary: |
  Toda app Desktop/Web Koder expõe KoderUIStylePicker em Settings,
  consumindo do enum KoderUIStyle do koder_kit v0.6.0+.
---

Audit script ui-style-audit.sh:

#!/usr/bin/env bash
# Verifica que módulo $1 importa KoderUIStylePicker e renderiza-o em alguma
# Settings page.
MODULE="$1"
if grep -rq "KoderUIStylePicker" "$MODULE/lib/" 2>/dev/null; then
  echo '{"applied":[],"deferred":[],"errors":[]}'
  exit 0
fi
echo '{"applied":[{"action":"missing-ui-style-picker","module":"'"$MODULE"'"}]}'
exit 1

Engine

koder-spec-audit (binário Go a criar em ETAPA 1.5):

1. Walk meta/docs/stack/{specs,policies}/**/*.kmd
2. Parse YAML frontmatter; skip if no `audit:` block
3. Resolve `applicable_to` to module list (expand glob, lookup coverage-matrix)
4. For each module: invoke `script` with module path as $1
5. Collect JSON outputs; aggregate by severity
6. Output consolidated report (json or text)
7. Exit:
   - 0 if no hard severity drifts
   - 1 if any hard severity drift
   - 2 if any script errored

Subcomandos do /k-audit (a criar em ETAPA 1.6):

/k-audit                    # full sweep (todas specs/policies × todos módulos)
/k-audit specs              # só severity=hard de specs/
/k-audit policies           # só severity=advisory de policies/
/k-audit <module>           # full sweep, módulo específico
/k-audit --spec=<glob>      # filtra por glob de spec

Anti-patterns

Don't:

  1. Hardcodar lista de specs no comando — toda nova spec deveria ser auto-descoberta via frontmatter
  2. Misturar audit logic com declarationsapplicable_to é declarativo; lógica imperativa fica no script
  3. Skipping o severity — campo obrigatório; sem ele não dá pra distinguir "bloqueia commit" de "só reporta"

Do:

  1. Toda spec/policy nova ganha audit: block — mesmo que script ainda não esteja escrito (pode ser stub que retorna pass)
  2. Audit scripts ficam ao lado do .kmd — descoberta por convenção
  3. Severity reflete a natureza — spec testável = hard; princípio = advisory

Relação com policies/stack-principles.kmd

  • Specs (severity=hard) ↔ rules deterministic, conformance testável
  • Policies (severity=advisory) ↔ princípios, julgamento, conflicts_with

Esta separação é estrutural (ver §3 de policies/stack-principles.kmd) e refletida na semântica de severity.

Origem

Convenção definida durante a sessão de 2026-05-01 documentada em projects/koder-stack/backlog/pending/101-stack-framework-ui-styles-settings-spec-audit.md, ETAPA 1.4. Pivot do framework koder-spec-audit (ETAPA 1.5).

References