Skip to content

8. Receitas

English | Português (Brasil)

Tradução do original em inglês; quando os dois divergirem, vale o inglês.

← Conformidade e leitores · Índice · Solução de problemas →

Escrever o primeiro grafo

Uma pergunta e a evidência que a sustenta. A evidência é confirmed, então leva provenance.

meta:
  schema_version: "1"
  id: example
  baseline: "2026-10-12"
  review_after: "2027-01-12"
nodes:
  - id: Q_CACHE_TTL
    node_type: question
    plane: DEV
    status: open
    impact: 3
    confidence: 0.5
    label: Does the session cache need a TTL?
  - id: E_CACHE_GROWTH
    node_type: evidence
    plane: DEV
    status: confirmed
    impact: 3
    confidence: 0.9
    label: Without a TTL, cache memory grows 40 MB per hour in the load test.
    trace: bench/cache-load.md
    verified_at: "2026-10-12"
    provenance:
      source: bench/cache-load.md
      locator: table 2
      method: "measurement: 4-hour load test"
edges:
  - from: E_CACHE_GROWTH
    to: Q_CACHE_TTL
    edge_type: SUPPORTS

O method começa pela classe, measurement, seguida do detalhe.

Todo nó precisa de pelo menos uma aresta: um nó solto reprova como integrity.orphan-node. Por isso um grafo de um nó só não passa, e o seu primeiro grafo já nasce com uma pergunta e o que a sustenta.

Com o venv da adoção ativo (. .venv/bin/activate), ou com .venv/bin/python3 no lugar de python3:

python3 -I -B vendor/kg-ssot/tools/kg_validate.py docs/example.kg.yaml
PASSA   docs/example.kg.yaml
· 1 arquivos; 1 passam no MUST; 0 com aviso SHOULD (kg-contract-v4.schema.json + kg-contract-v4.should.schema.json)

Consertar um nó que reprova

Este nó de produção reprovou com form.required.node.provenance e form.unknown-key.node.priority, e alertou com form.required.node.verified_against:

  - id: C_RETRY_SAFE
    node_type: claim
    plane: PROD
    status: confirmed
    impact: 4
    confidence: 0.8
    label: The payment retry is idempotent.
    verified_at: "2026-10-01"
    owner: payments-team
    priority: high

O conserto: a sua chave própria ganha o prefixo x_, o carimbo ganha alvo, e a proveniência diz de onde veio a afirmação.

    verified_at: "2026-10-01"
    owner: payments-team
    x_priority: high
    verified_against: tests/payment_retry_test.py
    provenance:
      source: tests/payment_retry_test.py
      locator: test_retry_is_idempotent
      method: "measurement: integration test in CI"

Registrar um relato sem inventar medição

Alguém do time disse que o retry é idempotente, e ninguém rodou nada. A classe é testimony:

    provenance:
      source: payments team
      locator: conversation on 2026-10-01
      method: "testimony: report from the payments team"

Num nó PROD, o contrato alerta (integrity.testimony-in-prod): produção apoiada só em relato é um risco que o grafo deve mostrar, não esconder.

python3 -I -B vendor/kg-ssot/tools/kg_validate.py --where testimony.kg.yaml
PASSA   testimony.kg.yaml
  SHOULD integrity.testimony-in-prod ×1
    SHOULD integrity.testimony-in-prod  nó C_RETRY_SAFE
· 1 arquivos; 1 passam no MUST; 1 com aviso SHOULD (kg-contract-v4.schema.json + kg-contract-v4.should.schema.json)

Um nó sem fonte nenhuma

Não escreva source: unknown: isso reprova. Em vez disso, mude o status do nó para unverifiable. Ele fica válido sem provenance, mesmo em PROD, e o grafo diz a verdade: aquela afirmação não tem origem recuperável.

Entregar um nó a um agente sem perder o status

O label de um nó é uma afirmação, e o status diz em que pé ela está. Um label como The supplier does not meet item 4.2 num nó open é uma afirmação em julgamento. Se a ferramenta que serve o grafo a um agente entrega só o label, o agente lê aquilo como fato. Um adotante achou esse defeito no teste de um chat: a leitura do grafo mandava o label de uma claim open, e o modelo respondeu que o fornecedor não atendia o item.

A afirmação nunca viaja sem o status dela. Quando você resume um nó para outra ferramenta (uma tool de MCP, um prompt, um relatório), leve junto ao menos o status. Quando a resposta depende da força da evidência, leve também a classe do method. E diga nas instruções do agente o que cada status quer dizer:

C_ITEM_42 [claim · open] The supplier does not meet item 4.2.
  → under review: do not assert it; say it is being analyzed.
C_ITEM_17 [claim · confirmed · leitura] The supplier meets item 1.7.
  → confirmed by reading the document.

A ferramenta kg_get do kg_mcp.py devolve o grafo inteiro, com o status de cada nó. O risco está na camada que você escreve em cima dele, quando resume.

Ligar uma decisão a uma pergunta de outro grafo

meta:
  schema_version: "1"
  id: decision
nodes:
  - id: D_CACHE_TTL_15MIN
    node_type: decision
    plane: DEV
    status: open
    impact: 3
    confidence: 0.7
    label: A 15-minute TTL on the session cache.
    trace: docs/adr/0009-cache-ttl.md
edges: []
external_edges:
  - from: D_CACHE_TTL_15MIN
    to: docs/example.kg.yaml#Q_CACHE_TTL
    edge_type: TRACES_TO

Confira com o corpus, para o leitor checar a ponta externa. Num repositório git, o corpus são os grafos rastreados, então o grafo alvo precisa estar no git:

git add docs/example.kg.yaml
python3 -I -B vendor/kg-ssot/tools/kg_validate.py --corpus . docs/decision.kg.yaml

Com um id que não existe no outro grafo, o leitor reprova o arquivo:

REPROVA docs/wrong.kg.yaml
  MUST   integrity.dangling-external ×1
· 1 arquivos; 0 passam no MUST; 0 com aviso SHOULD (kg-contract-v4.schema.json + kg-contract-v4.should.schema.json)

Travar o ganho depois de pagar dívida

Consertou um grafo herdado? O gate passa e pede --update. Rode no mesmo PR:

python3 -I -B vendor/kg-ssot/tools/kg_gate.py --update

Sem isso, um PR futuro pode voltar a quebrar aquele grafo sem que o gate perceba, porque o grafo continuaria na dívida herdada.

Achar todos os nós com um código

python3 -I -B vendor/kg-ssot/tools/kg_validate.py --where docs/*.kg.yaml

Cada linha indentada traz o código e o nó, e dá para filtrar com grep.

Uma regra de negócio ligada ao código

Num app, a regra fica no grafo, junto com a decisão de onde veio e o código que a implementa. Aqui, a regra da sequência de um app de hábitos: a decisão de produto, a regra de domínio com o teste que a mede, e o arquivo do código.

meta:
  schema_version: "1"
  id: streak
  baseline: "2026-10-13"
  review_after: "2027-01-13"
nodes:
  - id: D_STREAK_RESET
    node_type: decision
    plane: PROD
    status: done
    impact: 4
    confidence: 0.9
    label: The streak resets after one full day with no entry, in the user's time zone.
    trace: docs/decisions/2026-10-streak.md
    verified_at: "2026-10-13"
    provenance:
      source: docs/decisions/2026-10-streak.md
      locator: Decision section
      method: "reading: product decision record"
  - id: R_STREAK_RESET
    node_type: rule
    layer: domain
    plane: PROD
    status: confirmed
    impact: 4
    confidence: 0.9
    label: streak.reset() runs when the last entry is older than yesterday in the user's time zone.
    verified_at: "2026-10-13"
    provenance:
      source: tests/test_streak.py
      locator: test_resets_after_a_day_with_no_entry
      method: "measurement: pytest tests/test_streak.py, 6 cases passing"
  - id: A_STREAK_CODE
    node_type: artifact
    layer: domain
    plane: PROD
    status: confirmed
    impact: 3
    confidence: 0.9
    label: The streak implementation lives in app/streak.py.
    verified_at: "2026-10-13"
    verified_against: app/streak.py
    provenance:
      source: app/streak.py
      locator: reset function
      method: "reading: code at the release commit"
edges:
  - from: R_STREAK_RESET
    to: D_STREAK_RESET
    edge_type: TRACES_TO
  - from: R_STREAK_RESET
    to: A_STREAK_CODE
    edge_type: TRACES_TO
python3 -I -B vendor/kg-ssot/tools/kg_validate.py docs/streak.kg.yaml
PASSA   docs/streak.kg.yaml
· 1 arquivos; 1 passam no MUST; 0 com aviso SHOULD (kg-contract-v4.schema.json + kg-contract-v4.should.schema.json)

O contrato confere a forma, as arestas e a proveniência. Ele não roda o seu teste nem lê o seu código: quem roda tests/test_streak.py é o CI do app. O grafo registra o que foi medido, quando e como (method), e o verified_at diz há quanto tempo. Quando a regra mudar, o PR que muda o código muda o nó também, e o diff mostra os dois juntos.

Registrar um evento externo que chegou por mensagem assinada

Um e-mail, uma mensagem de chat, uma edição de wiki ou um aviso de nuvem muitas vezes chega ao Company Brain por um inbox, depois que um envelope assinado foi conferido e aceito. Registre-o como nó evidence, sem tipo novo de nó: o tipo event já existe, e quer dizer um evento de domínio, que muda um state.

  • Os atributos do evento vão em x_event, com os nomes dos atributos de contexto do CloudEvents 1.0.2. O CloudEvents exige specversion, id, source e type, e deixa opcionais subject, time, datacontenttype e dataschema. O contrato não julga o x_event: essas regras vêm do CloudEvents. Um reenvio deve manter o mesmo source + id, para que o consumidor o reconheça como duplicata.
  • A provenance aponta o documento que o inbox aceitou. O sha256 dela é o hash desse arquivo, então o kg_trace.py check pega uma edição feita depois do aceite. O method diz que o aceite conferiu a assinatura e o hash do corpo.
  • O identificador da entrega (o jti do token assinado) e o hash do corpo da mensagem vão como x_jti e x_body_sha256 dentro da provenance. O contrato aceita chaves x_ ali sem alerta. O hash do corpo não é o sha256 da fonte, porque o documento aceito embrulha o corpo.

O documento aceito, docs/inbox/2026-10-30-a2a-billing-agent-3f9c2a1b7d4e5f60.md:

---
from: billing-agent
---
Invoice 4512 was paid on 2026-10-29.

O arquivo termina com uma quebra de linha, e o sha256 é o hash do arquivo inteiro. O corpo é a última linha, sem a quebra de linha, e o x_body_sha256 é o hash dele.

meta:
  schema_version: "1"
  id: events
nodes:
  - id: Q_INVOICE_4512_PAID
    node_type: question
    plane: DEV
    status: open
    impact: 3
    confidence: 0.5
    label: Was invoice 4512 paid?
  - id: E_INVOICE_4512_PAID
    node_type: evidence
    plane: DEV
    status: confirmed
    impact: 3
    confidence: 0.9
    label: Invoice 4512 was paid on 2026-10-29, as the billing agent reported.
    verified_at: "2026-10-30"
    verified_against: the accepted inbox document, with the signature and the body hash checked again on acceptance
    x_event:
      specversion: "1.0"
      id: "pay-4512-001"
      source: "https://billing.example.com/invoices"
      type: "com.example.billing.invoice.paid"
      subject: "invoice/4512"
      time: "2026-10-29T14:03:00Z"
    provenance:
      source: docs/inbox/2026-10-30-a2a-billing-agent-3f9c2a1b7d4e5f60.md
      locator: "the last line"
      method: "measurement: the accept step checked the signed envelope and the body hash again"
      sha256: "56a7861a08417a4fc45bd86f5268f33f8e38836cff6a98678151ff71c87ed281"
      x_jti: "nb-7c1e9a04d2b3"
      x_body_sha256: "fe4fcd74067bb4a644273109f601905615c27fc964cfb41d8201840fd7f746a6"
      locality: repo
edges:
  - from: E_INVOICE_4512_PAID
    to: Q_INVOICE_4512_PAID
    edge_type: SUPPORTS
python3 -I -B vendor/kg-ssot/tools/kg_validate.py docs/events.kg.yaml
python3 -I -B vendor/kg-ssot/tools/kg_trace.py check --root .
PASSA   docs/events.kg.yaml
· 1 arquivos; 1 passam no MUST; 0 com aviso SHOULD (kg-contract-v4.schema.json + kg-contract-v4.should.schema.json)
· 1 fonte(s) lida(s) pelo scheme ou pelo sha256: 1 ok, 0 com falha (1 sha256 conferido(s)); não julgado (contado): 0 só pela forma, 0 URL sem --with, 0 fonte não achada, 0 scheme, locator ou hash malformado, 0 outro(s)
· 0 trace(s) julgado(s): 0 resolve(m), 0 faltando; fora de julgamento (contados): 0 absoluto(s) ou URL, 0 raiz externa, 0 não caminho, 0 fora de texto

Se alguém editar o documento aceito depois, o kg_trace.py check reprova (rc 1):

integrity.trace-sha256-mismatch  docs/events.kg.yaml#E_INVOICE_4512_PAID  → docs/inbox/2026-10-30-a2a-billing-agent-3f9c2a1b7d4e5f60.md [sha256] the last line  O provenance.sha256 do nó difere do hash do arquivo que ele nomeia: a fonte mudou depois de lida.

Um nó sozinho reprova como integrity.orphan-node: um evento sempre serve a uma pergunta ou a uma decisão, então ligue-o. A forma recomendada do x_event, e quando ela vira perfil canônico, está no capítulo 3.