{
  "tipo": "formato-escuta",
  "nome": "siscore-protocolo-objetos",
  "versao": 1,
  "descricao": "Protocolo canonico de comunicacao assincrona entre objetos internos do siscore via diretorio espaco. Agentes, conectores, sistemas e objetos nunca falam diretamente entre si e nunca colocam mensagens diretamente no espaco; devem solicitar publicacao por pp --api, que monta este envelope, registra a publicacao e a escuta valida, roteia, aciona e audita.",
  "regraCentral": "Uma mensagem possui exatamente um destino. Fan-out deve ser feito criando varias mensagens com mesmo processoId/correlacao e mensagemId distinto.",
  "entidades": {
    "prefixosPermitidos": ["agente__", "conector__", "sistema__"],
    "identificador": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$",
    "exemplos": ["agente__seguranca", "conector__github", "sistema__escuta"]
  },
  "layoutEspaco": {
    "entrada": "espaco/entrada/*.json recebe mensagens novas publicadas exclusivamente por pp --api usando escrita atomica tmp+rename. Mensagens colocadas diretamente por atores devem ser recusadas pela escuta e enviadas para quarentena.",
    "caixas": "espaco/caixas/<destino>/<destino>__<mensagemId>.json contem mensagens validadas e entregues. A fila é particionada por destinatário para reduzir contenção e custo de varredura em rajadas grandes; o destinatário também permanece no nome do arquivo para compatibilidade.",
    "processando": "espaco/processando/<destino>__<mensagemId>.json contem mensagens reivindicadas por execucao em andamento. O destinatario fica no nome do arquivo, nao em subdiretorio.",
    "concluidas": "espaco/concluidas/YYYYMMDD/*.json contem mensagens finalizadas com sucesso.",
    "erro": "espaco/erro/YYYYMMDD/*.json contem mensagens que excederam tentativas ou falharam de forma terminal.",
    "quarentena": "espaco/quarentena/YYYYMMDD/*.json contem mensagens invalidas, inseguras ou sem destinatario valido.",
    "duplicadas": "espaco/duplicadas/YYYYMMDD/*.json contem mensagens recusadas por mensagemId ou idempotencyKey ja vistos.",
    "apiPublicadas": "espaco/api-publicadas/<mensagemId>.idx contem marcadores gerados exclusivamente por pp --api/api.php para provar que a mensagem nao foi colocada diretamente por um ator.",
    "estado": "espaco/estado/concluidas, espaco/estado/terminais e espaco/estado/respondida contem marcadores usados pelo escalonador para dependencias e correlacao de respostas.",
    "processos": "espaco/processos/<processoId>/<numeroMensagem>.idx contem o mapeamento ordinal das mensagens do processo.",
    "vinculos": "espaco/vinculos/<pai>__<filho>.idx e <filho>__<pai>.rev registram a relacao bidirecional de resposta entre mensagens.",
    "eventos": "espaco/eventos/YYYYMMDD.jsonl contem auditoria append-only das transicoes."
  },
  "envelope": {
    "tipo": "object",
    "adicionais": true,
    "campos": {
      "_sistema": {
        "tipo": "object",
        "obrigatorio": true,
        "campos": {
          "id": { "tipo": "string", "obrigatorio": false },
          "criadoEm": { "tipo": "string", "obrigatorio": false },
          "criadoPor": { "tipo": "string", "obrigatorio": false },
          "transporte": { "tipo": "string", "obrigatorio": false }
        }
      },
      "_protocolo": {
        "tipo": "object",
        "obrigatorio": true,
        "campos": {
          "nome": { "const": "siscore-protocolo-objetos", "obrigatorio": true },
          "versao": { "const": 1, "obrigatorio": true },
          "processoId": { "tipo": "string", "obrigatorio": true },
          "mensagemId": { "tipo": "string", "obrigatorio": true },
          "respostaA": {
            "tipo": ["string", "null"],
            "obrigatorio": false,
            "descricao": "mensagemId da mensagem anterior que esta sendo respondida. A escuta valida que a mensagem referenciada existe no indice e cria vinculo bidirecional em espaco/vinculos e marcador de respondida em espaco/estado/respondida. Se a referencia for invalida, a mensagem vai para quarentena."
          },
          "origem": { "tipo": "string", "obrigatorio": true },
          "destino": { "tipo": "string", "obrigatorio": true },
          "tipo": {
            "enum": ["solicitacao", "resposta", "evento", "erro", "comando", "consulta"],
            "obrigatorio": true
          },
          "prioridade": {
            "enum": ["baixa", "normal", "alta", "critica"],
            "obrigatorio": false,
            "descricao": "Ordem operacional: critica, alta, normal, baixa."
          },
          "numeroMensagem": {
            "tipo": "int",
            "obrigatorio": false,
            "descricao": "Numero ordinal dentro do processo. Usado para ordenacao deterministica; quando sequencialNoProcesso=true, numeros anteriores precisam concluir antes."
          },
          "sequencialNoProcesso": {
            "tipo": "bool",
            "obrigatorio": false,
            "descricao": "Se true, a escuta bloqueia numeroMensagem N ate todos os numeros anteriores do mesmo processo estarem concluidos."
          },
          "dependeDe": {
            "tipo": "array",
            "obrigatorio": false,
            "descricao": "Lista de mensagemId que devem estar concluidos antes desta mensagem ser acionada. Se dependencia termina em erro/quarentena, esta mensagem vai para erro."
          },
          "naoProcessarAntesDe": {
            "tipo": "string",
            "obrigatorio": false,
            "descricao": "Timestamp UTC ISO-8601. A mensagem fica bloqueada ate este instante."
          },
          "expiraEm": {
            "tipo": "string",
            "obrigatorio": false,
            "descricao": "Timestamp UTC ISO-8601. Se vencer antes do processamento, a mensagem vai para erro."
          },
          "criadoEm": { "tipo": "string", "obrigatorio": false },
          "escopo": {
            "tipo": "object",
            "obrigatorio": false,
            "campos": {
              "tenantId": { "tipo": "string", "obrigatorio": false },
              "usuarioId": { "tipo": "string", "obrigatorio": false },
              "sessaoId": { "tipo": "string", "obrigatorio": false }
            }
          },
          "idempotencia": {
            "tipo": "object",
            "obrigatorio": false,
            "campos": {
              "chave": { "tipo": "string", "obrigatorio": true },
              "escopo": { "tipo": "string", "obrigatorio": false }
            }
          },
          "historico": {
            "tipo": "array",
            "obrigatorio": false,
            "descricao": "Historico leve. Nao deve carregar payloads grandes; use ids, origem, destino e timestamps."
          }
        }
      },
      "payload": {
        "tipo": "object",
        "obrigatorio": true,
        "descricao": "Conteudo de negocio da mensagem. O formato especifico pode ser validado futuramente contra formatos-agentes ou conectores/formatos do destinatario."
      }
    }
  },
  "estadosFisicos": [
    "entrada",
    "caixa_destinatario",
    "processando",
    "concluida",
    "erro",
    "quarentena",
    "duplicada",
    "bloqueada_por_dependencia",
    "bloqueada_por_sequencia",
    "bloqueada_por_tempo"
  ],
  "escalonamento": {
    "cerebroOperacional": "escuta.c",
    "ordem": [
      "descartar expiradas",
      "respeitar naoProcessarAntesDe",
      "resolver dependeDe",
      "resolver sequencialNoProcesso/numeroMensagem",
      "ordenar por prioridade critica > alta > normal > baixa",
      "ordenar por numeroMensagem menor dentro do lote",
      "ordenar por criadoEm mais antigo",
      "desempatar por nome fisico do arquivo"
    ],
    "indices": {
      "mensagemId": "espaco/indice/<mensagemId>.idx impede duplicidade global de mensagemId",
      "idempotencia": "espaco/idempotencia/<hash>.idx e criado na publicacao por pp --api/api.php quando ha chave e impede repeticao de efeito no mesmo escopo; a escuta valida/reutiliza o marcador do mesmo mensagemId e recusa duplicatas",
      "apiPublicadas": "espaco/api-publicadas/<mensagemId>.idx registra que a mensagem foi publicada por pp --api/api.php; a escuta recusa entrada sem este marcador. Em alta carga a escuta usa validação rápida por existência; --validar-marcador-api ativa conferência estrita do conteúdo do marcador",
      "processoNumero": "espaco/processos/<processoId>/<numeroMensagem>.idx registra sequencia ordinal",
      "concluidas": "espaco/estado/concluidas/<mensagemId>.idx libera dependencias",
      "terminais": "espaco/estado/terminais/<mensagemId>.idx propaga falhas para dependentes",
      "respondida": "espaco/estado/respondida/<mensagemId>.idx marca que a mensagem ja recebeu uma resposta",
      "vinculos": "espaco/vinculos/<pai>__<filho>.idx + <filho>__<pai>.rev registram o grafo bidirecional de respostas"
    }
  },
  "acionamento": {
    "regra": "A escuta nao injeta identidade da mensagem por variaveis de ambiente. O controlador recebe o caminho do arquivo reivindicado, ou no modo de lote um arquivo-lista contendo um caminho de mensagem por linha. Cada ator deve ler processoId, mensagemId, origem, destino e demais dados exclusivamente do JSON de cada mensagem.",
    "agente": "<controlador-agente> --ler-mensagem <arquivo-mensagem>. O manifesto do agente deve declarar controlador.executavel explicitamente quando operar mensagem a mensagem.",
    "conector": "<controlador-conector> ler-mensagem <arquivo-mensagem>. O manifesto do conector deve declarar controlador.executavel explicitamente quando operar mensagem a mensagem.",
    "agenteLote": "Opcional para alta carga: se o manifesto declarar controlador.executavelLote/comandoLote/handlerLerMensagens, a escuta chama <controlador-lote-agente> --ler-mensagens-arquivo <arquivo-lista>. O campo controlador.loteMaximo pode limitar o tamanho do lote do ator.",
    "conectorLote": "Opcional para alta carga: se o manifesto declarar controlador.executavelLote/comandoLote/handlerLerMensagens, a escuta chama <controlador-lote-conector> ler-mensagens-arquivo <arquivo-lista>. O campo controlador.loteMaximo pode limitar o tamanho do lote do conector.",
    "compatibilidadeRuntime": "Os runtimes nativos runtime-agente e runtime-conector aceitam o modo de lote e percorrem a lista chamando a leitura individual, preservando compatibilidade; handlers de lote reais podem otimizar inicialização e conexões."
  },
  "garantias": {
    "entrega": "at-least-once com idempotencia obrigatoria para efeitos externos",
    "concorrencia": "claim por rename atomico e lock global da escuta",
    "auditoria": "eventos append-only em JSONL",
    "seguranca": "origem/destino validados contra registries locais de agentes e conectores",
    "fonteDeVerdade": "A identidade e a correlacao da mensagem vivem exclusivamente no envelope JSON; variaveis de ambiente nao fazem parte do protocolo.",
    "publicacaoObrigatoria": "Nenhum ator deve escrever mensagens diretamente em espaco/entrada. As formas operacionais aceitas sao pp --api e api.php, que resolvem o destino exclusivamente via web-api/catalogo-mensagens.json, criam o envelope canonico, registram espaco/api-publicadas/<mensagemId>.idx e registram espaco/idempotencia quando houver chave. Catalogos individuais web-api/<id>.json nao sao fonte valida de publicacao."
  }
}
