guia

Federação

Tradução assistida por agentes de IA. Em caso de divergência, prevalece a página em inglês. Se você encontrar algum problema no texto, abra uma issue ou envie um pull request.

A federação permite que as equipes consultem, em conjunto, camadas de contexto de donos diferentes sem fundi-las nem transferir a responsabilidade de mantê-las atuais.

Por que compor em vez de centralizar

Uma camada de contexto se mantém atual porque seus donos a consultam e corrigem durante o trabalho. Centralizar o conteúdo de outra equipe afasta esse conteúdo das pessoas responsáveis por ele. A federação preserva o repositório, o dono e o fluxo de revisão de cada camada. A justificativa defende esse argumento por completo.

O que é um mount irmão

Uma irmã é a camada de contexto de outra equipe, declarada pela hospedeira em federation.mounts. A declaração fixa o commit completo e imutável que será lido pela hospedeira, além de registrar a propriedade e o roteamento de tarefas. As ferramentas carregam em um cache ignorado a projeção da camada irmã definida pelo manifesto dela naquele pin. O conteúdo da irmã nunca é copiado para a hospedeira.

A projeção é a união do que o próprio manifesto da irmã torna legível no pin: seu leji.json, sua raiz do contexto, seu perfil de boot, seus arquivos de índice de categoria, os perfis que suas associações de agents nomeiam, suas árvores de perfis de agente e de registros de decisão, seu índice e changelog de máquina, e todo caminho governado que o índice gerado dela lista, onde quer que essas coisas estejam.

Em geral, uma irmã fica dentro de um repositório de produto maior. Essa fronteira impede que um mount incorpore o produto como dependência apenas para ler o contexto dele.

Um mount é uma referência, não uma bifurcação nem uma concessão de acesso. A irmã continua autoritativa e o controle de versão dela continua determinando quem pode lê-la. O mount apenas torna a relação e a revisão escolhida visíveis para quem já tem acesso.

"federation": {
   "mounts": [
      {
         "name": "product-context",
         "source": "https://github.com/acme/product-context",
         "pin": "7d3f2a19c4e8b6a0d5f1c2e9b8a7f6d5c4b3a2e1", // id completo do commit: a versão de referência
         "trackingRef": "refs/heads/main",                    // a desatualização é avaliada em relação a esta ref
         "owner": { "name": "Product team", "contact": "product@acme.example" },
         "role": "product-side context, owned by the product team",
         // roteamento: quando este mount é relevante para uma tarefa
         "categories": ["domain", "decisions"],
         "requiredWhen": ["a task changes how a plan or entitlement is represented"]
      }
   ]
}

As atualizações de pin são mudanças revisadas no leji.json. A hospedeira declara a relação; a irmã mantém repositório, dono, processo de revisão e aprovação, changelog e declaração de conformidade próprios.

Trabalhando com os mounts

leji mounts hydrate --fetch      # materializa a projeção de cada camada irmã em seu pin
leji mounts status               # disponibilidade, integridade e atraso de cada pin
leji mounts update-pin <name>    # avança um pin até o commit testemunhado
leji mounts locate <name>        # onde um leitor deve ler a camada irmã

Use hydrate --fetch para materializar cada projeção no seu pin, com uma busca de rede explícita. Use status para inspecionar disponibilidade, integridade e desatualização de pin. Use locate para obter o caminho gerenciado pelo resolvedor onde um leitor deve abrir uma irmã.

Para manter um mount atualizado, repita este ciclo: use hydrate --fetch para consultar as origens, status para ver quanto cada pin ficou para trás e update-pin para avançar um pin até o commit que o resolvedor testemunhou, e então hydrate de novo para materializar a projeção no novo pin. Avançar o pin e materializá-lo são ações separadas. Assim, a reescrita aparece como um diff que pode ser revisado antes de qualquer mudança no conteúdo em uso.

update-pin é offline por padrão: ele promove a última referência observada de fato por uma execução e deixa isso explícito na saída, sem sugerir que ela esteja atualizada. Acrescente --fetch para consultar a origem declarada durante a execução, o que entra em contato com aquela origem e com nada mais; se qualquer parte disso falhar, a execução se recusa e deixa o leji.json intocado. O pin só anda para a frente. Um alvo que não seja descendente do pin atual é recusado, a menos que você o nomeie explicitamente com --to <oid> e acrescente --allow-non-fast-forward. Um branch upstream que foi reescrito é o motivo habitual para recorrer a esse par; um retorno deliberado a um commit anterior também precisa dele, porque a verificação é de ascendência, e não de saber se o histórico foi reescrito. Essa combinação gera um aviso toda vez, e é registrada na saída JSON, porque move um pin para um commit que não pode ser alcançado a partir do atual. Use --dry-run para ver a comparação e a reescrita sem reescrever o manifesto; combinada com --fetch, ela ainda executa as operações de armazenamento e de rede daquela flag, então os objetos e refs buscados de fato chegam ao armazenamento gerenciado.

Apenas os bytes do próprio pin são reescritos. Assim, a ordem dos campos, a formatação e quaisquer chaves que o schema não modele sobrevivem à edição inalteradas. A entrada de cache do pin antigo fica onde está: ela é endereçada por conteúdo, então simplesmente deixa de ser referenciada. Não existe comando de limpeza; remova manualmente as entradas antigas em .leji/mounts/ quando quiser recuperar o espaço.

A hidratação não publica projeção parcial. O cache fica sob .leji/mounts/, que o init adiciona ao .gitignore da raiz. Trate esse caminho como detalhe de implementação: locate informa onde ler uma irmã, e fixar um caminho de cache no código quebra quando a publicação muda.

O visualizador mostra o mesmo estado sem exigir o terminal. leji viewer gera uma página de Manifesto que exibe o grafo da hospedeira e de suas irmãs, seguido de uma linha por mount: disponibilidade, desvio, dono, pin e origem. Gere-a de novo depois de hidratar.

Declarando federated

Um mount não hidratado é um aviso, nunca uma falha de build. O CI pode ativar a imposição de disponibilidade com leji validate --federation=available|required. A validação comum não busca nem exige todo mount.

Disponibilidade local não é conformidade. O pin precisa ser alcançável a partir de uma ref anunciada de source, o que exige rede. Rode leji conformance --federation=verify para essa verificação. Se a verificação não conseguir alcançar a origem, ela reporta unknown; unknown nunca concede o nível.

Essa verificação é necessária, mas não suficiente. federated também exige que esta camada de contexto seja ela própria consumida por outro repositório como um mount fixado, que o relato de pin desatualizado esteja em funcionamento, e que o perfil de boot e o índice gerado exponham toda irmã.

Os dois primeiros requisitos são atestados por processo, por isso verifiedLevel nunca os declara em seu nome. A materialização em uma máquina não conta para a conformidade.

Escolha primeiro o padrão de distribuição

Um submódulo git somente documentação permite que muitos repositórios consumam uma camada de contexto. A federação conecta várias equipes que já possuem uma camada cada. Esses padrões respondem a perguntas diferentes, então a federação não substitui o submódulo. O guia de adoção mantém o procedimento completo do submódulo.

Leia distribuição para a definição normativa da projeção, os limites de falha e as regras completas de federação.