/*
 * atualizar-manual-conector - recria a arvore operador-manual-conector em sisc/arvores/
 * Uso: pp --atualizar-manual-conector
 *
 * Este comando sempre usa pp --sa para materializar a arvore. Antes de recriar
 * o manual, vasculha fontes, executaveis e ajudas dos comandos relacionados a
 * conectores, API, front-api AJAX e escuta, registrando assinaturas na propria arvore
 * para que alteracoes futuras aparecam no fluxograma gerado.
 */
#define _DEFAULT_SOURCE
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "manual-dinamico.h"

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

typedef struct {
    char pai[32];
    char texto[1400];
    char spec[800];   /* "spec_xxx.json § C<N>: citacao" ou "" */
} ItemArvore;

typedef struct {
    ItemArvore *v;
    size_t n;
    size_t cap;
} ListaItens;

typedef struct {
    const char *nome;
    const char *papel;
    const char *flags;
} ComandoRelacionado;

static const ComandoRelacionado COMANDOS[] = {
    {"criar-sistema", "cria sistemas ja com api.php, front-api.php, cliente publico e catalogos base", "--criar-sistema=<nome>"},
    {"empacotar-conector", "cria pacote autocontido do conector em core/biblioteca-conectores", "--empacotar-conector=<nome>"},
    {"importar-conectores", "importa pacotes autocontidos de core/biblioteca-conectores", "--importar-conectores"},
    {"atualizar-catalogo-mensagens", "monta web-api/catalogo-mensagens.json a partir de catalogos modulares web-api/catalogo-*.json", "--dry-run --verificar"},
    {"api", "publica mensagem declarativa no espaco nativo a partir do agregado web-api/catalogo-mensagens.json; front-api.php usa a mesma rota segura via cliente SISC", "--api=<idmensagem> --dados=<json|arquivo> --dry-run"},
    {"ligar-escuta", "liga a escuta continua que entrega mensagens a agentes e conectores", "--base= --intervalo= --paralelo="},
    {"status-escuta", "confere pid/log/status da escuta do sistema atual", "--json --base="},
    {"pulsar-escuta", "executa um ciclo unico da escuta para teste controlado", "--base= --lote= --timeout-ator="},
    {"desligar-escuta", "desliga a escuta continua", "--base="},
    {"setar-escuta", "comando legado que aponta para ligar/status/pulsar/desligar", "--ajuda"},
    {"agente-at", "apoio para manutencao/triagem de mensagens quando a escuta aponta falha", "--ler-mensagem"}
};

static const char *ARQUIVOS_SISTEMA_RELACIONADOS[] = {
    "escuta/runtime-conector.c",
    "escuta/runtime_comum.c",
    "escuta/escuta.c",
    "formatos-escuta/protocolo-mensagem-siscore.v1.json",
    "conexao-externo/front-api.php",
    "conexao-externo/api.php",
    "public/sisc-api-cliente.php",
    "web-api/catalogo-mensagens.json",
    "web-api/catalogo-conector-email.json",
    "conectores/conector-email/conector-email.json",
    "conectores/conector-email/formatos/formato-conector-email.json",
    "conectores/conector-email/handlers/conector-email.php",
    "core/biblioteca-conectores/conector-email.tar.gz"
};

static const char *ARQUIVOS_CORE_RELACIONADOS[] = {
    "core/biblioteca-specs/spec_integracoes_externas_e_conectores.json",
    "core/biblioteca-specs/spec_contratos_de_mensagem_espaco.json",
    "core/biblioteca-specs/spec_orquestracao_processos_assincronos.json",
    "core/biblioteca-specs/spec_comunicacao_espaco_sisc_nativo.json",
    "core/biblioteca-specs/spec_api_declarativa_catalogo_mensagens.json",
    "core/biblioteca-specs/spec_idempotencia_correlacao_e_ordem.json",
    "core/biblioteca-specs/spec_resiliencia_timeout_retry_backpressure.json",
    "core/biblioteca-specs/spec_segredos_configuracao_e_ambientes.json",
    "core/biblioteca-specs/spec_seguranca_zero_trust_web_api.json",
    "core/biblioteca-specs/spec_operacao_runbooks_e_incidentes.json",
    "core/biblioteca-specs/spec_documentacao_adrs_e_catalogo_servicos.json",
    "core/biblioteca-specs/spec_testes_microservicos_web_api_espaco.json",
    "core/biblioteca-front/conectar_email/testeweb/index.php",
    "ajuda-conectores/manual-conectores.html",
    "gitprog/manual-conector.html",
    "gitprog/conectores/conector-modelo/manual-conector-modelo.html"
};

static void uso(void)
{
    fputs(
        "Uso:\n"
        "  pp --atualizar-manual-conector\n"
        "  pp --atualizar-manual-conector --ajuda:<grupo>\n"
        "\n"
        "Descrição:\n"
        "  Recria, do zero, a árvore sisc/arvores/operador-manual-conector.json\n"
        "  no estilo fluxograma para orientar LLMs internas no ciclo completo de\n"
        "  construção de conectores sob demanda: criação/importação, manifesto, formato, handler, catálogo,\n"
        "  clone GitHub git@github.com:jrcostarrear/gitprog.git em qualquer diretório de trabalho do programador,\n"
        "  manual técnico do conector, validador local, pacote interno validado, selos de validação/sandbox, exemplos diversos,\n"
        "  front-api AJAX, escuta, teste, diagnóstico e manutenção. Regra registrada:\n"
        "  objeto visual atualizado por AJAX deve ter o mesmo nome do conector.\n"
        "  Antes de escrever a árvore, vasculha comandos e arquivos relacionados e grava uma seção de varredura\n"
        "  com assinaturas de fonte/executável/ajuda para refletir alterações.\n"
        "  Também percorre sisc/ e harmoniza os HTMLs *manual-conector*. Cada\n"
        "  manual mantém o tom/finalidade já usados nele: manual público continua\n"
        "  amplo, manual do gitprog continua instrutivo para programadores, e manual\n"
        "  de conector específico continua direto para consumidores do conector.\n"
        "\n"
        "Grupos de ajuda: uso, comportamento, varredura, arquivos, exemplos.\n"
        "\n"
        "1) Uso e ajuda [uso ajuda]\n"
        "  --ajuda, --help, -h            Exibe esta ajuda\n"
        "  --ajuda:<grupo>                Filtra um grupo. Ex: pp --atualizar-manual-conector --ajuda:varredura\n"
        "\n"
        "2) Comportamento [comportamento]\n"
        "  Remove operador-manual-conector.json existente e recria o fluxograma\n"
        "  usando pp --sa=operador-manual-conector --ag=... [--em=...].\n"
        "  Depois percorre sisc/ para atualizar HTMLs *manual-conector* mantendo\n"
        "  o tom e alvo de cada arquivo.\n"
        "  Não executa conectores, agentes, chamadas de API ou escuta; apenas lê\n"
        "  metadados dos comandos relacionados e atualiza a árvore operacional e\n"
        "  documentação HTML de conectores.\n"
        "\n"
        "3) Varredura automática [varredura comandos]\n"
        "  A cada execução confere fontes .c, executáveis/scripts e ajuda/*.json de\n"
        "  criar-sistema, empacotar-conector, importar-conectores, API, front-api e escuta. A assinatura\n"
        "  registrada muda quando arquivo relacionado muda, forçando o manual gerado\n"
        "  a refletir a revisão operacional corrente.\n"
        "  Lei fonte-código: usa como fonte apenas código/contratos/configs operacionais;\n"
        "  não usa árvores/mapas/manuais JSON gerados como fonte de pesquisa.\n"
        "\n"
        "4) Arquivos [arquivos saida]\n"
        "  Saída principal: sisc/arvores/operador-manual-conector.json\n"
        "  Saídas harmonizadas: todos os HTMLs cujo nome contenha manual-conector\n"
        "  encontrados desde sisc/, por exemplo ajuda-conectores/manual-conectores.html,\n"
        "  gitprog/manual-conector.html e conectores/<nome>/manual-conector-<nome>.html.\n"
        "  O manual amplo de operador fica fora de <sistema>/public para não ser\n"
        "  distribuído como material de programador externo.\n"
        "\n"
        "5) Exemplos [exemplos]\n"
        "  pp --atualizar-manual-conector\n"
        "  pp --sa=arvores/operador-manual-conector\n",
        stdout);
}

static void lista_add(ListaItens *l, const char *pai, const char *spec, const char *fmt, ...)
{
    if (l->n == l->cap) {
        size_t nc = l->cap ? l->cap * 2 : 128;
        ItemArvore *nv = realloc(l->v, nc * sizeof(ItemArvore));
        if (!nv) { fprintf(stderr, "atualizar-manual-conector: sem memoria\n"); exit(2); }
        l->v = nv;
        l->cap = nc;
    }
    if (pai && *pai) snprintf(l->v[l->n].pai, sizeof(l->v[l->n].pai), "%s", pai);
    else l->v[l->n].pai[0] = '\0';
    if (spec && *spec) snprintf(l->v[l->n].spec, sizeof(l->v[l->n].spec), "%s", spec);
    else l->v[l->n].spec[0] = '\0';
    va_list ap;
    va_start(ap, fmt);
    vsnprintf(l->v[l->n].texto, sizeof(l->v[l->n].texto), fmt, ap);
    va_end(ap);
    l->n++;
}

static int mkdir_p(const char *path)
{
    if (!path || !*path) return -1;
    char tmp[PATH_MAX * 2];
    snprintf(tmp, sizeof(tmp), "%s", path);
    size_t len = strlen(tmp);
    while (len > 1 && tmp[len - 1] == '/') tmp[--len] = '\0';
    for (char *p = tmp + 1; *p; p++) {
        if (*p == '/') {
            *p = '\0';
            if (mkdir(tmp, 0775) != 0 && errno != EEXIST) return -1;
            *p = '/';
        }
    }
    if (mkdir(tmp, 0775) != 0 && errno != EEXIST) return -1;
    chmod(tmp, 0775);
    return 0;
}

static int localizar_raiz_sisc(char *out, size_t tam)
{
    char exe[PATH_MAX];
    ssize_t n = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
    if (n <= 0) return -1;
    exe[n] = '\0';

    /* .../sisc/core/comandos/atualizar-manual-conector -> .../sisc */
    char *slash = strrchr(exe, '/'); if (!slash) return -1; *slash = '\0';
    slash = strrchr(exe, '/'); if (!slash) return -1; *slash = '\0';
    slash = strrchr(exe, '/'); if (!slash) return -1; *slash = '\0';

    snprintf(out, tam, "%s", exe);
    return 0;
}

static int dir_existe(const char *path)
{
    struct stat st;
    return path && stat(path, &st) == 0 && S_ISDIR(st.st_mode);
}

static void detectar_sistema_atual(const char *raiz, char *out, size_t outsz)
{
    if (!out || outsz == 0) return;
    out[0] = '\0';
    char cwd[PATH_MAX];
    if (getcwd(cwd, sizeof(cwd)) && raiz && *raiz) {
        size_t rl = strlen(raiz);
        if (strncmp(cwd, raiz, rl) == 0 && cwd[rl] == '/') {
            const char *p = cwd + rl + 1;
            size_t n = strcspn(p, "/");
            if (n > 0 && n + 1 < outsz) {
                char cand[PATH_MAX];
                memcpy(out, p, n);
                out[n] = '\0';
                snprintf(cand, sizeof(cand), "%s/%s/espaco", raiz, out);
                if (dir_existe(cand)) return;
                snprintf(cand, sizeof(cand), "%s/%s/web-api", raiz, out);
                if (dir_existe(cand)) return;
                snprintf(cand, sizeof(cand), "%s/%s/conectores", raiz, out);
                if (dir_existe(cand)) return;
                out[0] = '\0';
            }
        }
    }
    char padrao[PATH_MAX * 2];
    snprintf(padrao, sizeof(padrao), "%s/siscore/espaco", raiz ? raiz : "");
    if (dir_existe(padrao)) snprintf(out, outsz, "siscore");
}

static int executar_sa(const char *pp_path, const char *diretorio_trabalho, const char *pai, const char *texto, int silenciar_stderr)
{
    int in_pipe[2] = {-1, -1};
    if (pipe(in_pipe) != 0) {
        perror("atualizar-manual-conector: pipe");
        return 1;
    }
    const char *confirmacao = "s\n";
    (void)write(in_pipe[1], confirmacao, strlen(confirmacao));
    close(in_pipe[1]);
    in_pipe[1] = -1;

    pid_t pid = fork();
    if (pid < 0) {
        perror("atualizar-manual-conector: fork");
        close(in_pipe[0]);
        return 1;
    }
    if (pid == 0) {
        dup2(in_pipe[0], STDIN_FILENO);
        close(in_pipe[0]);
        if (chdir(diretorio_trabalho) != 0) {
            perror("atualizar-manual-conector: chdir diretorio de arvores");
            _exit(126);
        }
        int null_fd = open("/dev/null", O_WRONLY);
        if (null_fd >= 0) {
            dup2(null_fd, STDOUT_FILENO);
            if (silenciar_stderr) dup2(null_fd, STDERR_FILENO);
            close(null_fd);
        }
        char ag_arg[PATH_MAX * 2];
        char em_arg[64];
        snprintf(ag_arg, sizeof(ag_arg), "--ag=%s", texto ? texto : "");
        char *args_com_pai[] = { (char *)pp_path, "--sa=operador-manual-conector", ag_arg, em_arg, NULL };
        char *args_sem_pai[] = { (char *)pp_path, "--sa=operador-manual-conector", ag_arg, NULL };
        if (pai && *pai) {
            snprintf(em_arg, sizeof(em_arg), "--em=%s", pai);
            execv(pp_path, args_com_pai);
        } else {
            execv(pp_path, args_sem_pai);
        }
        perror("atualizar-manual-conector: execv pp --sa");
        _exit(127);
    }

    close(in_pipe[0]);

    int st = 0;
    if (waitpid(pid, &st, 0) != pid) {
        perror("atualizar-manual-conector: waitpid");
        return 1;
    }
    if (WIFEXITED(st)) return WEXITSTATUS(st);
    if (WIFSIGNALED(st)) return 128 + WTERMSIG(st);
    return 1;
}

static uint64_t fnv1a_arquivo(const char *path, int *ok, off_t *size_out, time_t *mtime_out)
{
    *ok = 0;
    if (size_out) *size_out = 0;
    if (mtime_out) *mtime_out = 0;
    struct stat st;
    if (stat(path, &st) != 0 || !S_ISREG(st.st_mode)) return 0;
    if (size_out) *size_out = st.st_size;
    if (mtime_out) *mtime_out = st.st_mtime;
    FILE *f = fopen(path, "rb");
    if (!f) return 0;
    uint64_t h = 1469598103934665603ULL;
    unsigned char buf[8192];
    size_t n;
    while ((n = fread(buf, 1, sizeof(buf), f)) > 0) {
        for (size_t i = 0; i < n; i++) {
            h ^= (uint64_t)buf[i];
            h *= 1099511628211ULL;
        }
    }
    int erro = ferror(f);
    fclose(f);
    if (erro) return 0;
    *ok = 1;
    return h;
}

static void iso_mtime(time_t t, char out[32])
{
    if (!t) { snprintf(out, 32, "ausente"); return; }
    struct tm tmv;
    gmtime_r(&t, &tmv);
    strftime(out, 32, "%Y-%m-%dT%H:%M:%SZ", &tmv);
}

static void assinatura_path(const char *path, char *out, size_t outsz)
{
    int ok = 0;
    off_t sz = 0;
    time_t mt = 0;
    uint64_t h = fnv1a_arquivo(path, &ok, &sz, &mt);
    if (!ok) {
        snprintf(out, outsz, "ausente");
        return;
    }
    char mtiso[32];
    iso_mtime(mt, mtiso);
    snprintf(out, outsz, "ok size=%lld mtime=%s fnv=%016llx", (long long)sz, mtiso, (unsigned long long)h);
}

static int termina_com(const char *s, const char *suf)
{
    if (!s || !suf) return 0;
    size_t a = strlen(s), b = strlen(suf);
    return a >= b && strcmp(s + a - b, suf) == 0;
}

static const char *base_nome(const char *path)
{
    const char *s = path ? strrchr(path, '/') : NULL;
    return s ? s + 1 : (path ? path : "");
}

static char *ler_texto_todo(const char *path, size_t *tam_out)
{
    FILE *f = fopen(path, "rb");
    if (!f) return NULL;
    if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return NULL; }
    long n = ftell(f);
    if (n < 0 || n > 8L * 1024L * 1024L) { fclose(f); return NULL; }
    rewind(f);
    char *buf = malloc((size_t)n + 1);
    if (!buf) { fclose(f); return NULL; }
    size_t r = fread(buf, 1, (size_t)n, f);
    fclose(f);
    if (r != (size_t)n) { free(buf); return NULL; }
    buf[r] = '\0';
    if (tam_out) *tam_out = r;
    return buf;
}

static int gravar_texto_atomico(const char *path, const char *txt)
{
    char tmp[PATH_MAX * 2];
    snprintf(tmp, sizeof(tmp), "%s.tmp.%ld", path, (long)getpid());
    int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0644);
    if (fd < 0) return -1;
    FILE *f = fdopen(fd, "wb");
    if (!f) { close(fd); unlink(tmp); return -1; }
    size_t n = strlen(txt ? txt : "");
    int ok = fwrite(txt ? txt : "", 1, n, f) == n ? 0 : -1;
    if (fclose(f) != 0) ok = -1;
    if (ok != 0) { unlink(tmp); return -1; }
    chmod(tmp, 0644);
    if (rename(tmp, path) != 0) { unlink(tmp); return -1; }
    return 0;
}

static int inserir_antes_body(char **texto, const char *bloco)
{
    char *pos = strstr(*texto, "</body>");
    if (!pos) pos = *texto + strlen(*texto);
    size_t antes = (size_t)(pos - *texto);
    size_t nt = strlen(*texto), nb = strlen(bloco);
    char *novo = malloc(nt + nb + 2);
    if (!novo) return -1;
    memcpy(novo, *texto, antes);
    memcpy(novo + antes, bloco, nb);
    strcpy(novo + antes + nb, pos);
    free(*texto);
    *texto = novo;
    return 0;
}

static int manual_html_alinhado(const char *rel, const char *txt)
{
    if (!txt) return 0;
    if (strstr(txt, "SISC-MANUAL-CONECTOR-GITHUB-KIT-V2")) return 1;
    if (strstr(rel, "ajuda-conectores/manual-conectores.html") || strstr(rel, "/manual-conectores.html"))
        return strstr(txt, "git@github.com:jrcostarrear/gitprog.git") && strstr(txt, "qualquer diretório") && strstr(txt, "validar") && strstr(txt, "enviar conector");
    if (strcmp(base_nome(rel), "manual-conector.html") == 0)
        return strstr(txt, "git@github.com:jrcostarrear/gitprog.git") && strstr(txt, "qualquer diretório") && strstr(txt, "produzir, validar e enviar");
    return strstr(txt, "git@github.com:jrcostarrear/gitprog.git") && strstr(txt, "conteúdo baixado") && strstr(txt, "SISC");
}

static void bloco_manual_html(const char *rel, const char *txt, char *out, size_t tam)
{
    const int tem_callout = txt && strstr(txt, "class=\"callout");
    const int tem_aviso = txt && strstr(txt, "class=\"aviso");
    const char *abertura = "";
    const char *fechamento = "";
    if (tem_callout) { abertura = "<div class=\"callout ok\">"; fechamento = "</div>\n"; }
    else if (tem_aviso) { abertura = "<div class=\"aviso\">"; fechamento = "</div>\n"; }

    if (strstr(rel, "ajuda-conectores/manual-conectores.html") || strstr(rel, "/manual-conectores.html")) {
        snprintf(out, tam,
            "\n<!-- SISC-MANUAL-CONECTOR-GITHUB-KIT-V2 -->\n"
            "%s<b>Atualização do fluxo GitHub:</b> o programador clona <code>git@github.com:jrcostarrear/gitprog.git</code> em qualquer diretório da própria máquina. O conteúdo baixado é o kit completo para produzir, validar e enviar conector ao SISC; a instalação real continua condicionada ao funil do servidor, sandbox ativo e dois selos válidos para o SHA256 exato.%s\n",
            abertura[0] ? abertura : "<p>", abertura[0] ? fechamento : "</p>\n");
    } else if (strcmp(base_nome(rel), "manual-conector.html") == 0) {
        snprintf(out, tam,
            "\n<!-- SISC-MANUAL-CONECTOR-GITHUB-KIT-V2 -->\n"
            "%s<b>Nota de fluxo para programadores:</b> clone <code>git@github.com:jrcostarrear/gitprog.git</code> em qualquer diretório da sua máquina. Esse conteúdo baixado contém o necessário para produzir, validar e enviar conectores ao SISC; o pacote gerado deve passar no validador local e depois no funil do servidor, com sandbox ativo e selos válidos.%s\n",
            abertura[0] ? abertura : "<p>", abertura[0] ? fechamento : "</p>\n");
    } else {
        snprintf(out, tam,
            "\n<!-- SISC-MANUAL-CONECTOR-GITHUB-KIT-V2 -->\n"
            "<h2>Fluxo GitHub, segurança e sandbox</h2>\n"
            "%s<strong>Procedimento atual:</strong> o programador clona <code>git@github.com:jrcostarrear/gitprog.git</code> em qualquer diretório da própria máquina; o conteúdo baixado traz o necessário para produzir, validar e enviar o conector ao SISC. Handlers devem ficar em <code>conectores/&lt;nome&gt;/handlers/</code>, sem link simbólico, com execução direta e caminho relativo seguro. No servidor, pacotes externos só entram no SISC real depois de <code>selo-validacao</code> e <code>selo-sandbox</code> válidos para o SHA256 exato.%s\n",
            abertura[0] ? abertura : "<p>", abertura[0] ? fechamento : "</p>\n");
    }
}

typedef struct { int encontrados; int atualizados; int alinhados; int erros; } ResultadoManuais;

static int harmonizar_manual_html(const char *raiz, const char *path, ResultadoManuais *r)
{
    const char *rel = path;
    size_t rl = strlen(raiz);
    if (strncmp(path, raiz, rl) == 0 && path[rl] == '/') rel = path + rl + 1;
    r->encontrados++;

    size_t n = 0;
    char *txt = ler_texto_todo(path, &n);
    if (!txt) { r->erros++; fprintf(stderr, "  [erro] nao foi possivel ler manual: %s\n", rel); return -1; }
    if (manual_html_alinhado(rel, txt)) {
        r->alinhados++;
        free(txt);
        return 0;
    }

    char bloco[2400];
    bloco_manual_html(rel, txt, bloco, sizeof(bloco));
    if (inserir_antes_body(&txt, bloco) != 0 || gravar_texto_atomico(path, txt) != 0) {
        r->erros++;
        fprintf(stderr, "  [erro] nao foi possivel atualizar manual: %s\n", rel);
        free(txt);
        return -1;
    }
    printf("  [manual-conector atualizado] %s\n", rel);
    r->atualizados++;
    free(txt);
    return 0;
}

static void harmonizar_manuais_rec(const char *raiz, const char *dir, ResultadoManuais *r)
{
    DIR *d = opendir(dir);
    if (!d) return;
    struct dirent *e;
    while ((e = readdir(d))) {
        if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) continue;
        if (!strcmp(e->d_name, ".git") || !strcmp(e->d_name, "dist") || !strcmp(e->d_name, "tmp") || !strcmp(e->d_name, "cache")) continue;
        char p[PATH_MAX * 2];
        snprintf(p, sizeof(p), "%s/%s", dir, e->d_name);
        struct stat st;
        if (lstat(p, &st) != 0) continue;
        if (S_ISLNK(st.st_mode)) continue;
        if (S_ISDIR(st.st_mode)) { harmonizar_manuais_rec(raiz, p, r); continue; }
        if (!S_ISREG(st.st_mode)) continue;
        if (!strstr(e->d_name, "manual-conector") || !termina_com(e->d_name, ".html")) continue;
        harmonizar_manual_html(raiz, p, r);
    }
    closedir(d);
}

static ResultadoManuais harmonizar_manuais_conector(const char *raiz)
{
    ResultadoManuais r;
    memset(&r, 0, sizeof(r));
    harmonizar_manuais_rec(raiz, raiz, &r);
    return r;
}

static int garantir_ajuda_conectores_protegida(const char *raiz)
{
    char dir[PATH_MAX * 2], ht[PATH_MAX * 2];
    snprintf(dir, sizeof(dir), "%s/ajuda-conectores", raiz);
    if (mkdir_p(dir) != 0) return -1;
    snprintf(ht, sizeof(ht), "%s/.htaccess", dir);
    const char *txt =
        "# SISC: documentação interna de operação/revisão de conectores.\n"
        "# Não expor como material público do sistema nem como manual de programador externo.\n"
        "<IfModule mod_authz_core.c>\n"
        "    Require all denied\n"
        "</IfModule>\n"
        "<IfModule !mod_authz_core.c>\n"
        "    Order deny,allow\n"
        "    Deny from all\n"
        "</IfModule>\n";
    if (gravar_texto_atomico(ht, txt) != 0) return -1;
    chmod(ht, 0644);
    return 0;
}

static void adicionar_varredura(ListaItens *itens, const char *raiz, const char *sistema_atual)
{
    lista_add(itens, "2", NULL, "Varredura executada nesta atualização: fontes .c, executáveis/scripts, ajuda JSON e arquivos de runtime/contrato relacionados a conectores");
    lista_add(itens, "2", NULL, "Sistema usado para arquivos operacionais da varredura: %s", sistema_atual && *sistema_atual ? sistema_atual : "siscore");
    lista_add(itens, "2", NULL, "Regra: se uma assinatura abaixo mudar entre execuções, reexecute pp --atualizar-manual-conector e revise os passos do fluxograma afetados");

    for (size_t i = 0; i < sizeof(COMANDOS) / sizeof(COMANDOS[0]); i++) {
        const ComandoRelacionado *c = &COMANDOS[i];
        char src[PATH_MAX * 2], exe[PATH_MAX * 2], ajuda[PATH_MAX * 2];
        char sig_src[160], sig_exe[160], sig_ajuda[160];
        snprintf(src, sizeof(src), "%s/core/comandos/%s.c", raiz, c->nome);
        snprintf(exe, sizeof(exe), "%s/core/comandos/%s", raiz, c->nome);
        snprintf(ajuda, sizeof(ajuda), "%s/ajuda/%s.json", raiz, c->nome);
        assinatura_path(src, sig_src, sizeof(sig_src));
        assinatura_path(exe, sig_exe, sizeof(sig_exe));
        assinatura_path(ajuda, sig_ajuda, sizeof(sig_ajuda));
        char alerta[220] = "";
        struct stat st_src, st_exe, st_ajuda;
        int tem_src = stat(src, &st_src) == 0 && S_ISREG(st_src.st_mode);
        int tem_exe = stat(exe, &st_exe) == 0 && S_ISREG(st_exe.st_mode);
        int tem_ajuda = stat(ajuda, &st_ajuda) == 0 && S_ISREG(st_ajuda.st_mode);
        if (tem_src && (!tem_exe || st_src.st_mtime > st_exe.st_mtime)) {
            snprintf(alerta, sizeof(alerta), "; ATENÇÃO: fonte mais nova que executável/script, recompilar antes de operar");
        } else if ((tem_src || tem_exe) && tem_ajuda && ((tem_src ? st_src.st_mtime : st_exe.st_mtime) > st_ajuda.st_mtime)) {
            snprintf(alerta, sizeof(alerta), "; atenção: ajuda possivelmente desatualizada, rode pp --atualizar-ajuda-comandos=%s", c->nome);
        }
        lista_add(itens, "2", NULL, "%s — %s; flags-chave: %s; fonte: %s; executável/script: %s; ajuda: %s%s", c->nome, c->papel, c->flags, sig_src, sig_exe, sig_ajuda, alerta);
    }

    const char *sis = (sistema_atual && *sistema_atual) ? sistema_atual : "siscore";
    for (size_t i = 0; i < sizeof(ARQUIVOS_SISTEMA_RELACIONADOS) / sizeof(ARQUIVOS_SISTEMA_RELACIONADOS[0]); i++) {
        char path[PATH_MAX * 2], rel[PATH_MAX * 2], sig[180];
        snprintf(rel, sizeof(rel), "%s/%s", sis, ARQUIVOS_SISTEMA_RELACIONADOS[i]);
        snprintf(path, sizeof(path), "%s/%s", raiz, rel);
        assinatura_path(path, sig, sizeof(sig));
        lista_add(itens, "2", NULL, "Arquivo relacionado do sistema atual: %s — %s", rel, sig);
    }
    for (size_t i = 0; i < sizeof(ARQUIVOS_CORE_RELACIONADOS) / sizeof(ARQUIVOS_CORE_RELACIONADOS[0]); i++) {
        char path[PATH_MAX * 2], sig[180];
        snprintf(path, sizeof(path), "%s/%s", raiz, ARQUIVOS_CORE_RELACIONADOS[i]);
        assinatura_path(path, sig, sizeof(sig));
        lista_add(itens, "2", NULL, "Arquivo relacionado do core: %s — %s", ARQUIVOS_CORE_RELACIONADOS[i], sig);
    }
}

static int adicionar_inspecao_codigo_fonte(const char *pp_path, const char *arvores_dir, const char *raiz, const char *sistema_atual, size_t root_id)
{
    char pai[32];
    snprintf(pai, sizeof(pai), "%zu", root_id);

    int rc = executar_sa(pp_path, arvores_dir, NULL, "CÓDIGO-FONTE LIDO NESTA GERAÇÃO — manual de conector derivado do estado atual de comandos, runtime, catálogo, specs e ajudas", 0);
    if (rc != 0) return rc;
    rc = executar_sa(pp_path, arvores_dir, pai, "LEI FONTE-CÓDIGO: estes comandos só podem pesquisar arquivos integrantes do código de funcionamento do SISC: fontes C/H/PHP/scripts, comandos, ajudas JSON, specs JSON, agentes JSON, manifestos, formatos, catálogos, runtimes e configs operacionais. É proibido usar como fonte JSONs de contexto/entendimento/artefatos gerados, como arvores/operador-manual-*.json e arvores/reversao-gc.json.", 0);
    if (rc != 0) return rc;
    rc = executar_sa(pp_path, arvores_dir, pai, "Garantia operacional: esta seção lê apenas arquivos classificados pela lei como código-fonte/contrato/configuração operacional no momento da invocação; mudanças em conectores/API/escuta alteram o conteúdo gerado", 0);
    if (rc != 0) return rc;

    for (size_t i = 0; i < sizeof(COMANDOS) / sizeof(COMANDOS[0]); i++) {
        char texto[3600];
        md_resumir_comando(raiz, COMANDOS[i].nome, texto, sizeof(texto));
        rc = executar_sa(pp_path, arvores_dir, pai, texto, 0);
        if (rc != 0) return rc;
    }

    const char *sis = (sistema_atual && *sistema_atual) ? sistema_atual : "siscore";
    for (size_t i = 0; i < sizeof(ARQUIVOS_SISTEMA_RELACIONADOS) / sizeof(ARQUIVOS_SISTEMA_RELACIONADOS[0]); i++) {
        char rel[PATH_MAX * 2], texto[3000];
        snprintf(rel, sizeof(rel), "%s/%s", sis, ARQUIVOS_SISTEMA_RELACIONADOS[i]);
        md_resumir_arquivo_rel(raiz, rel, texto, sizeof(texto));
        rc = executar_sa(pp_path, arvores_dir, pai, texto, 0);
        if (rc != 0) return rc;
    }
    for (size_t i = 0; i < sizeof(ARQUIVOS_CORE_RELACIONADOS) / sizeof(ARQUIVOS_CORE_RELACIONADOS[0]); i++) {
        char texto[3000];
        md_resumir_arquivo_rel(raiz, ARQUIVOS_CORE_RELACIONADOS[i], texto, sizeof(texto));
        rc = executar_sa(pp_path, arvores_dir, pai, texto, 0);
        if (rc != 0) return rc;
    }
    return 0;
}

static void montar_itens(ListaItens *itens, const char *raiz, const char *sistema_atual)
{
    lista_add(itens, NULL,
        "spec_integracoes_externas_e_conectores § C6: E proibido criar fila proprietaria ou chamada direta para substituir o fluxo nativo escuta.c; § C8: Conectores leem pelo modo ler-mensagem e publicam so por pp --api",
        "INÍCIO — operador vai criar, revisar ou operar conector SISC");
    lista_add(itens, "1",
        "spec_integracoes_externas_e_conectores § C1: catalogo deve mapear idmensagem para entidade SISC valida agente__id, conector__id ou sistema__id",
        "Objetivo: integrar serviço externo sem quebrar o barramento nativo do SISC");
    lista_add(itens, "1",
        "spec_comunicacao_espaco_sisc_nativo § C8: Nenhum modulo deve varrer caixas de outro ator; § C9: somente pp --api pode publicar em espaco/entrada",
        "Regra absoluta: conector não escreve diretamente em espaco/entrada, caixas, processando, concluidas, erro, quarentena, indice ou estado");
    lista_add(itens, "1",
        "spec_api_declarativa_catalogo_mensagens § C5: pp --api/api.php sao os unicos mecanismos de publicacao em espaco/entrada",
        "Toda saída do conector para o SISC deve chamar api.php via POST HTTP ou, no teste do operador, usar pp --api apenas para publicar mensagem de entrada");
    lista_add(itens, "1", NULL,
        "Frontend/browser nunca chama conector nem escolhe idmensagem/destino: componentes AJAX devem chamar somente conexao-externo/front-api.php com acao declarativa e dados validados; o objeto visual atualizado deve chamar-se exatamente como o conector (ex.: conector-email atualiza id/name conector-email)");
    lista_add(itens, "1", NULL,
        "Trabalhar dentro do sistema alvo: cd /var/www/html/sisc/<sistema>");
    lista_add(itens, "1", NULL,
        "Próximo: varredura automática do manual");

    lista_add(itens, NULL, NULL,
        "1 → VARREDURA AUTOMÁTICA — detectar mudanças nos comandos relacionados");
    adicionar_varredura(itens, raiz, sistema_atual);
    lista_add(itens, "2", NULL,
        "DECISÃO — houve mudança relevante em comando/contrato de conector desde a última revisão humana?");
    lista_add(itens, "2", NULL,
        "Se SIM: ler pp --<comando> --ajuda e revisar o ramo do fluxograma correspondente antes de operar");
    lista_add(itens, "2", NULL,
        "Se NÃO: seguir o manual normalmente; as assinaturas ficam registradas como auditoria do manual gerado");
    lista_add(itens, "2", NULL,
        "Próximo: decidir criar, importar ou revisar conector existente");

    lista_add(itens, NULL,
        "spec_integracoes_externas_e_conectores § C8: Conectores devem ler mensagens pelo modo ler-mensagem e publicar respostas/eventos somente por pp --api",
        "2 → DECIDIR CRIAR, IMPORTAR OU REVISAR CONECTOR");
    lista_add(itens, "3", NULL,
        "Se for novo: usar o canal unico gitprog. O programador clona git@github.com:jrcostarrear/gitprog.git em qualquer diretorio da propria maquina; o conteudo baixado contem tudo que e necessario para produzir, validar e enviar conector ao SISC. A partir do clone, copiar o conector-modelo para conector-<nome>, preencher manifesto, formato, manual, catalogo, handler, mensagem de teste e testeSandbox obrigatório, validar com ./validar-conector e empacotar. O pacote produzido entra pelo funil gitconectores (validar-recebidos, testar-sandbox, instalar-aprovados) e so e instalado apos os dois selos validos para o SHA256 exato.");
    lista_add(itens, "3", NULL,
        "Se existir como pacote na biblioteca: pp --importar-conectores. Para reaproveitar de outro sistema, primeiro empacote na origem com pp --empacotar-conector=<nome> e depois importe pelo pacote.");
    lista_add(itens, "3", NULL,
        "Se já existir localmente: revalidar com ./validar-conector no kit gitprog para receber diagnóstico sem sobrescrever");
    lista_add(itens, "3", NULL,
        "Contrato do runtime-conector novo: o executavel ./escuta/runtime-conector so aceita handler de conector como caminho relativo seguro dentro de conectores/<conector>/handlers/, exige arquivo executavel direto e invoca via sandbox-handler quando SISC_SANDBOX_DESATIVADO nao esta definido. O handler recebe como unico argumento uma copia somente-leitura do JSON da mensagem.");
    lista_add(itens, "3",
        "spec_integracoes_externas_e_conectores § C8: Conectores leem pelo modo ler-mensagem; manifesto deve declarar handlerLerMensagem",
        "DECISÃO — manifesto e formato base existem localmente?");
    lista_add(itens, "3.5", NULL,
        "SIM: seguir para revisão do manifesto");
    lista_add(itens, "3.5", NULL,
        "NÃO: corrigir criação/importação antes de escrever handler ou ativar escuta");
    lista_add(itens, "3", NULL,
        "Próximo: preparar manifesto");

    lista_add(itens, NULL,
        "spec_integracoes_externas_e_conectores § C8: Conectores leem mensagens pelo modo ler-mensagem; § C10: Credenciais de terceiros em segredos protegidos; § C12: Mapeamento externo-interno documentado e testado",
        "3 → PREPARAR MANIFESTO DO CONECTOR");
    lista_add(itens, "4",
        "spec_integracoes_externas_e_conectores § C8: manifesto deve declarar handler real, metodoLeitura e metodoEnvio",
        "Abrir conectores/<conector>/<conector>.json e conferir nome, titulo, descricao, versao, tipo=conector e ativo=false durante preparação");
    lista_add(itens, "4", NULL,
        "Conferir controlador.executavel = ./escuta/runtime-conector");
    lista_add(itens, "4",
        "spec_integracoes_externas_e_conectores § C8: Conectores leem mensagens pelo modo ler-mensagem e publicam respostas apenas por pp --api",
        "Conferir metodoLeitura=ler-mensagem e metodoEnvio=POST api.php");
    lista_add(itens, "4", NULL,
        "Declarar handlerLerMensagem apontando para arquivo real executavel em conectores/<conector>/handlers/<conector>.php ou equivalente. Caminho deve ser relativo seguro: sem / inicial, .., componente ., //, barra invertida ou controle; scripts precisam de shebang e binarios precisam ser executaveis diretamente.");
    lista_add(itens, "4",
        "spec_segredos_configuracao_e_ambientes § C8: Segredos nunca devem ser versionados em repositorios nem expostos em payload; § C10: credenciais em arquivo protegido ou secret manager",
        "Documentar servicoExterno, credenciais por referência em secretos/ e operações aceitas");
    lista_add(itens, "4", NULL,
        "Declarar testeSandbox.permitido=true, testeSandbox.semEfeitoReal=true e descricao explicando por que a mensagem de teste e segura. Sem isso o validador local reprova, testar-sandbox nao emite selo-sandbox e instalar-aprovados recusa o siscore real.");
    lista_add(itens, "4",
        "spec_integracoes_externas_e_conectores § C12: Mapeamento entre contrato externo e payload interno deve ser documentado e testado",
        "DECISÃO — o manifesto contém handler, regras de envio, serviço externo e operações mínimas?");
    lista_add(itens, "4.6", NULL,
        "SIM: seguir para contrato/formato");
    lista_add(itens, "4.6", NULL,
        "NÃO: completar manifesto e manter ativo=false");

    lista_add(itens, NULL,
        "spec_contratos_de_mensagem_espaco § C8: Todo payload deve ter nome de contrato, versao semantica, descricao e exemplos; § C4: envelope com _sistema, _protocolo e payload",
        "4 → DEFINIR CONTRATO EM FORMATOS-CONECTORES");
    lista_add(itens, "5", NULL,
        "Abrir conectores/<conector>/formatos/formato-<conector>.json");
    lista_add(itens, "5", NULL,
        "No manifesto conectores/<conector>/<conector>.json, conferir dependencias.arquivos antes de descricao: esta lista e a fonte segura usada por importar-conectores para saber quais arquivos compoem o conector e onde aloca-los. O manual HTML do utilizador deve aparecer como manualUsuario e papel manual-usuario.");
    lista_add(itens, "5",
        "spec_contratos_de_mensagem_espaco § C8: Todo payload deve possuir nome de contrato, versao semantica, descricao e exemplos validos",
        "Definir entrada.modelos para comandos aceitos: operacao, dados, correlacao e campos obrigatórios");
    lista_add(itens, "5",
        "spec_contratos_de_mensagem_espaco § C11: Contratos devem especificar erros de negocio e respostas esperadas usando respostaA",
        "Definir saida.modelos para resultado, erro e eventos publicados de volta via api.php");
    lista_add(itens, "5",
        "spec_comunicacao_espaco_sisc_nativo § P1: fonte canonica formatos-escuta/protocolo-mensagem-siscore.v1.json",
        "Alinhar contrato com formatos-escuta/protocolo-mensagem-siscore.v1.json: _sistema, _protocolo e payload");
    lista_add(itens, "5",
        "spec_contratos_de_mensagem_espaco § C8: payload deve ter nome de contrato e exemplos; § C12: Consumidores devem ignorar campos desconhecidos",
        "DECISÃO — contrato permite validar mensagens sem depender de conhecimento implícito do handler?");
    lista_add(itens, "5.5", NULL,
        "SIM: seguir para implementação do handler");
    lista_add(itens, "5.5", NULL,
        "NÃO: completar formato antes de qualquer teste real");

    lista_add(itens, NULL,
        "spec_comunicacao_espaco_sisc_nativo § C10: consumidor deve tratar arquivo recebido como fonte unica; § C11: respostas com respostaA mantendo processoId",
        "5 → IMPLEMENTAR HANDLER LER-MENSAGEM");
    lista_add(itens, "6", NULL,
        "Criar arquivo em conectores/<conector>/handlers/<conector>.php ou caminho declarado no manifesto, sem link simbolico e sem caminho indireto. O runtime recusa handler fora da pasta handlers do proprio conector.");
    lista_add(itens, "6", NULL,
        "Assinatura obrigatória: handler recebe o caminho do arquivo de mensagem como argumento; script deve iniciar com shebang para execução direta e estar com chmod +x.");
    lista_add(itens, "6",
        "spec_comunicacao_espaco_sisc_nativo § C10: consumidor deve tratar o arquivo recebido como fonte unica de verdade e nao depender de variaveis de ambiente",
        "Ler exclusivamente o JSON da mensagem; não confiar em variáveis de ambiente para processoId, mensagemId, origem ou destino");
    lista_add(itens, "6",
        "spec_resiliencia_timeout_retry_backpressure § C8: Toda chamada externa deve ter timeout explicito; § C9: Retries so para operacoes idempotentes; spec_seguranca_zero_trust_web_api § C11: logs nao devem expor segredos",
        "Chamar serviço externo com timeout, tratamento de erro, idempotência e logs seguros sem vazar segredos");
    lista_add(itens, "6", NULL,
        "Envelope da mensagem recebida: toda mensagem entregue ao handler segue o formato canonico de formatos-escuta/protocolo-mensagem-siscore.v1.json com tres secoes obrigatorias: _sistema (id, criadoEm, transporte=pp --api), _protocolo (processoId, mensagemId, origem, destino, tipo, prioridade, respostaA, idempotencia) e payload (idmensagem, dados, _api com catalogo, destinoResolvido, formatoEscuta, regraComunicacao). O handler deve ler exclusivamente deste JSON; nunca confiar em variaveis de ambiente para correlacao.");
    lista_add(itens, "6", NULL,
        "Resposta ao SISC via api.php: handler deve fazer POST HTTP para api.php com header Authorization: Bearer <token> (token de cliente cadastrado exclusivamente em <sistema>/token-externo/<cliente>.txt). Corpo JSON: idmensagem (do catalogo), dados (resultado do processamento), origem=conector__<nome>, processoId (preservado da mensagem recebida), respostaA=mensagemId (da mensagem recebida, para correlacao). Nunca usar pp --api para envio de respostas; sempre POST HTTP direto.");
    lista_add(itens, "6",
        "spec_idempotencia_correlacao_e_ordem § C12: Respostas e erros devem manter correlacao por respostaA e processoId; spec_api_declarativa_catalogo_mensagens § C5: publicacao por api.php com idmensagem e dados",
        "Para responder ao SISC: POST em api.php com idmensagem, dados, origem=conector__<conector>, processoId preservado e respostaA=mensagemId recebido");
    lista_add(itens, "6", NULL,
        "Tornar executável: chmod +x conectores/<conector>/handlers/<conector>.php; o validador e o runtime recusam handler sem execução direta.");
    lista_add(itens, "6", NULL,
        "Não usar shell_exec/system/passthru/eval/proc_open/popen/subprocess/child_process no handler e não acessar espaco/ diretamente. No sandbox novo espaco/ fica oculto e somente secretos/<conector>.json do proprio conector fica visivel, somente leitura.");
    lista_add(itens, "6",
        "spec_idempotencia_correlacao_e_ordem § C12: respostas e erros mantem correlacao por respostaA e processoId; § C8: toda operacao com efeito externo deve ter chave de idempotencia",
        "DECISÃO — handler processa mensagem, preserva correlação e nunca publica direto no espaco?");
    lista_add(itens, "6.7", NULL,
        "SIM: seguir para segredos e catálogo");
    lista_add(itens, "6.7", NULL,
        "NÃO: corrigir handler antes de ativar conector");

    lista_add(itens, NULL,
        "spec_segredos_configuracao_e_ambientes § C8: Segredos nunca versionados; spec_api_declarativa_catalogo_mensagens § C2: catalogo mapeia idmensagem para entidade SISC valida",
        "6 → SEGREDOS, CONFIGURAÇÃO, CATÁLOGO WEB-API E FRONT-API");
    lista_add(itens, "7",
        "spec_segredos_configuracao_e_ambientes § C8: Segredos nunca devem ser versionados em repositorios, specs, mensagens do espaco, logs ou exemplos reais",
        "Guardar tokens de cliente SISC somente em <sistema>/token-externo/*.txt; guardar chaves/credenciais de servicos externos em secretos/; não gravar credenciais em conectores/<conector>/, conectores/<conector>/formatos/ ou web-api/");
    lista_add(itens, "7",
        "spec_api_declarativa_catalogo_mensagens § C2: catalogo deve mapear idmensagem para entidade SISC valida; § C3: destinos diretos como arquivo/URL/comando proibidos",
        "Cadastrar/revisar entrada em web-api/catalogo-<conector>.json apontando destino=conector__<conector>; ativar a mensagem com ativo=true somente quando o contrato estiver revisado; usar publica=true apenas para capacidade externa/descobrivel; depois rodar pp --atualizar-catalogo-mensagens para gerar web-api/catalogo-mensagens.json");
    lista_add(itens, "7", NULL,
        "Se a mensagem sera acionada por componente frontend, declarar front-api no proprio item do catalogo: acao, metodo POST, csrf, autenticacao, modo, entrada com campos obrigatorios/tipos, dadosSisc e resposta. Em resposta.atualizar usar sempre exatamente o nome do conector; exemplo conector-email atualiza somente objeto visual id/name conector-email. O bloco deve permanecer ativo=false ate existir validação servidor e permissão de uso.");
    lista_add(itens, "7", NULL,
        "Adaptador unico: conexao-externo/front-api.php recebe AJAX com {acao,dados}, procura a acao em web-api/catalogo-mensagens.json, valida entrada, monta dadosSisc e chama o SISC; o navegador nao envia token, idmensagem, destino ou origem; a resposta informa objetoVisual/atualizar com o nome do conector.");
    lista_add(itens, "7",
        "spec_idempotencia_correlacao_e_ordem § C8: Toda operacao com efeito externo deve possuir chave de idempotencia estavel por escopo de negocio",
        "Para comandos públicos/críticos, declarar idempotenciaObrigatoria=true e correlacaoObrigatoria=true");
    lista_add(itens, "7", NULL,
        "Validar publicação sem gravar: pp --api=<idmensagem> --dados='{\"operacao\":\"ping\",\"dados\":{}}' --origem=sistema__operador --dry-run");
    lista_add(itens, "7", NULL,
        "Autenticacao no api.php: o unico local canonico aceito para tokens de cliente e <sistema>/token-externo/*.txt. Variaveis de ambiente SISC_API_TOKEN/SISC_API_TOKENS e secretos/api-tokens.txt nao devem conter tokens de cliente e nao sao fonte valida. Cada arquivo pode conter token puro ou formato app=token; sem token em token-externo/ o endpoint retorna 503 desabilitado.");
    lista_add(itens, "7", NULL,
        "Catalogo modular: o kit gitprog entrega web-api/catalogo-<conector>.json com mensagem inicial ativo=false, publica=false e front-api ativo=false ate revisao. Mensagens com ativo=true entram no agregado catalogo-mensagens.json; mensagens com publica:true aparecem no endpoint GET ?mensagens=1 do api.php. Apenas mensagens de negocio devem ser publicas; mensagens internas como agente-at.executar usam publica:false e nao sao expostas. Mensagens publicas exigem idempotenciaObrigatoria=true e correlacaoObrigatoria=true.");
    lista_add(itens, "7",
        "spec_api_declarativa_catalogo_mensagens § C13: Publicadores devem resolver idmensagem exclusivamente no agregado catalogo-mensagens.json; fontes humanas ficam em web-api/catalogo-*.json e o agregado é gerado por pp --atualizar-catalogo-mensagens; § C5: escrita atomica tmp+rename",
        "DECISÃO — catálogo resolve idmensagem para conector correto, front-api expõe somente ações permitidas, resposta.atualizar é igual ao nome do conector e dry-run monta envelope válido?");
    lista_add(itens, "7.5", NULL,
        "SIM: seguir para ativação controlada");
    lista_add(itens, "7.5", NULL,
        "NÃO: corrigir web-api/catalogo-<modulo>.json, front-api.entrada/dadosSisc/resposta.atualizar ou formato de dados e regenerar com pp --atualizar-catalogo-mensagens");

    lista_add(itens, NULL,
        "spec_idempotencia_correlacao_e_ordem § C8: idempotencia estavel; spec_operacao_runbooks_e_incidentes § C9: nao editar arquivos do espaco manualmente",
        "7 → ATIVAR E TESTAR NA ESCUTA");
    lista_add(itens, "8", NULL,
        "Somente depois de manifesto, formato, manual HTML do utilizador, handler, segredos, catalogo modular com mensagem ativa, front-api revisado quando houver frontend, e agregado web-api/catalogo-mensagens.json atualizado: alterar \"ativo\": true em conectores/<conector>/<conector>.json para teste controlado");
    lista_add(itens, "8",
        "spec_idempotencia_correlacao_e_ordem § C8: operacao com efeito externo deve ter chave de idempotencia; § C14: duplicidade recusada na publicacao",
        "Testar publicação real: pp --api=<idmensagem> --dados='{...}' --origem=sistema__operador --idempotencia=<chave>");
    lista_add(itens, "8", NULL,
        "Processar ciclo controlado: pp --pulsar-escuta --lote=1");
    lista_add(itens, "8", NULL,
        "Teste frontend/AJAX: componente em biblioteca-front ou pagina do produto deve enviar apenas {acao,dados} para conexao-externo/front-api.php; confirmar que somente o objeto visual cujo id/name é exatamente o nome do conector foi atualizado e que a resposta nao expõe token, stack trace ou caminho sensivel.");
    lista_add(itens, "8", NULL,
        "Se precisar daemon: pp --ligar-escuta --intervalo=1 --paralelo=4; acompanhar com pp --status-escuta e espaco/escuta.log");
    lista_add(itens, "8",
        "spec_operacao_runbooks_e_incidentes § C9: Operadores nao devem editar manualmente arquivos do espaco sem procedimento aprovado e backup",
        "Conferir espaco/eventos/<data>.jsonl, espaco/concluidas, espaco/erro e espaco/quarentena");
    lista_add(itens, "8", NULL,
        "runtime_comum.c (siscore/escuta/runtime_comum.c): codigo compartilhado entre runtime-agente e runtime-conector. Para conectores valida handlerLerMensagem como caminho relativo seguro em conectores/<conector>/handlers/, exige executavel direto e, por padrao, chama escuta/sandbox-handler. O sandbox cria namespace privado, oculta espaco/ e todos os secretos/ previsiveis e reexpoe somente secretos/<conector>.json do proprio conector como leitura.");
    lista_add(itens, "8", NULL,
        "runtime-conector.c (siscore/escuta/runtime-conector.c): wrapper fino que chama runtime_comum.c com tipo=conector. A escuta invoca ./escuta/runtime-conector ler-mensagem <arquivo>; o runtime resolve handlerLerMensagem, aplica as guardas de caminho/execução e chama sandbox-handler salvo se SISC_SANDBOX_DESATIVADO estiver definido. Em gitconectores/testar-sandbox essa variável bloqueia emissão de selo.");
    lista_add(itens, "8", NULL,
        "DECISÃO — mensagem concluiu com resposta/evento esperado?");
    lista_add(itens, "8.6", NULL,
        "SIM: registrar evidência e liberar operação");
    lista_add(itens, "8.6", NULL,
        "NÃO: seguir para diagnóstico");

    lista_add(itens, NULL,
        "spec_resiliencia_timeout_retry_backpressure § C8-C12; spec_idempotencia_correlacao_e_ordem § C8; spec_operacao_runbooks_e_incidentes § C10: reprocessamento verifica idempotencia",
        "8 → DIAGNOSTICAR FALHAS DE CONECTOR");
    lista_add(itens, "9", NULL,
        "Se destino inativo: conferir ativo=true e destino conector__<conector> no catálogo");
    lista_add(itens, "9", NULL,
        "Se AJAX retorna acao front-api nao encontrada: conferir front-api.acao, front-api.ativo=true no catalogo modular e se o agregado web-api/catalogo-mensagens.json foi regenerado.");
    lista_add(itens, "9", NULL,
        "Se AJAX retorna campo invalido ou alvo visual recusado: conferir front-api.entrada, resposta.atualizar e o componente visual id/name com o nome do conector; a validação do servidor prevalece sobre required/HTML do navegador.");
    lista_add(itens, "9", NULL,
        "Se handler não encontrado: corrigir handlerLerMensagem e permissões de execução");
    lista_add(itens, "9",
        "spec_contratos_de_mensagem_espaco § C8: Todo payload deve possuir nome de contrato, versao semantica, descricao e exemplos validos",
        "Se formato inválido: revisar conectores/<conector>/formatos/ e payload enviado");
    lista_add(itens, "9",
        "spec_resiliencia_timeout_retry_backpressure § C8: timeout explicito; § C11: circuit breakers protegem dependencias; spec_segredos_configuracao_e_ambientes § C12: rotacao de segredo sem rebuild",
        "Se falha externa: conferir timeout, credenciais em secretos/, status do serviço e política de retry/idempotência");
    lista_add(itens, "9",
        "spec_idempotencia_correlacao_e_ordem § C8: duplicidade deve ser recusada ja na publicacao; § C14: duplicidade de idempotencia recusada no mesmo escopo",
        "Se mensagem duplicada: verificar chave de idempotência em espaco/idempotencia e catálogo");
    lista_add(itens, "9", NULL,
        "Para análise assistida: usar pp --agente=agente-at --ler-mensagem <arquivo-mensagem> quando aplicável");
    lista_add(itens, "9",
        "spec_contratos_de_mensagem_espaco § C9: Campos novos devem ser opcionais; remocoes e mudancas quebradoras exigem migracao planejada",
        "DECISÃO — correção exige mudança de código/contrato?");
    lista_add(itens, "9.7", NULL,
        "SIM: abrir GC orientado pelo pp --sa conforme operador-manual-gc e repetir testes");
    lista_add(itens, "9.7", NULL,
        "NÃO: ajustar dado/configuração e pulsar novamente");

    lista_add(itens, NULL,
        "spec_segredos_configuracao_e_ambientes § C11: Ambientes devem ser isolados e nao compartilhar credenciais produtivas",
        "9 → IMPORTAÇÃO, REUSO E EVOLUÇÃO");
    lista_add(itens, "10", NULL,
        "Antes de copiar de outro sistema, comparar nomes, formatos, handler e idmensagem para evitar colisão");
    lista_add(itens, "10",
        "spec_segredos_configuracao_e_ambientes § C11: Ambientes isolados sem compartilhar credenciais; spec_api_declarativa_catalogo_mensagens § C2: idmensagem unico por catalogo",
        "Após importar, nunca ativar automaticamente: revisar manifesto, segredos locais, catálogo local e contrato de payload");
    lista_add(itens, "10",
        "spec_contratos_de_mensagem_espaco § C9: Campos novos opcionais; remocoes exigem migracao planejada; versionamento semantico",
        "Quando evoluir operação, versionar formato e manter compatibilidade ou migração explícita");
    lista_add(itens, "10",
        "spec_testes_microservicos_web_api_espaco § C9: Contratos de API e de mensagem devem ter fixtures de sucesso, erro e versao anterior",
        "Atualizar testes e exemplos de dry-run sempre que novas operações forem adicionadas");
    lista_add(itens, "10", NULL,
        "Após alteração em comandos relacionados, reexecutar pp --atualizar-manual-conector para atualizar assinaturas e orientações");

    lista_add(itens, NULL,
        "spec_operacao_runbooks_e_incidentes § C11: preservar evidencias; spec_documentacao_adrs_e_catalogo_servicos § C8: documento de catalogo com dono, contrato, mensagens",
        "10 → AUDITORIA E ENCERRAMENTO");
    lista_add(itens, "11",
        "spec_operacao_runbooks_e_incidentes § C11: Incidentes devem preservar evidencias: processoId, mensagemId, logs, eventos e versoes de servico",
        "Guardar evidências: comando pp --api usado, idempotência, mensagemId/processoId, evento e resultado externo");
    lista_add(itens, "11",
        "spec_documentacao_adrs_e_catalogo_servicos § C8: Cada microservico/conector deve ter documento de catalogo com dono, contrato HTTP e mensagens",
        "Documentar operações suportadas e mapa idmensagem → destino no catálogo");
    lista_add(itens, "11",
        "spec_segredos_configuracao_e_ambientes § C12: Rotacao de segredo deve ser possivel sem rebuild da imagem e com procedimento documentado",
        "Registrar responsáveis por segredo externo e procedimento de rotação");
    lista_add(itens, "11",
        "spec_seguranca_zero_trust_web_api § C11: Erros, logs e mensagens de retorno nao devem expor segredos, tokens, stack traces ou conteudo sensivel",
        "Manter handler sem logs sensíveis e com tratamento de erro reproduzível");
    lista_add(itens, "11", NULL,
        "FIM — conector criado/operado de forma rastreável, testável e segura");

    lista_add(itens, NULL,
        "spec_documentacao_adrs_e_catalogo_servicos § C8: documento de catalogo com dono, contrato HTTP e mensagens; spec_testes_microservicos_web_api_espaco § C9: fixtures de sucesso, erro e versao anterior",
        "11 → MANUAL DE CONSTRUÇÃO PARA LLMS INTERNAS — lacunas cobertas");
    lista_add(itens, "12", NULL,
        "Finalidade deste manual: orientar exclusivamente LLMs internas quando precisarem construir, revisar ou completar conectores sob demanda. Não é manual humano, não é tutorial público e não deve ser tratado como material de distribuição externa. Fluxo externo obrigatório: o programador clona git@github.com:jrcostarrear/gitprog.git em qualquer diretório da própria máquina; esse conteúdo baixado é o kit completo para produzir, validar e enviar conector ao SISC.");
    lista_add(itens, "12", NULL,
        "Verificação: o manual antigo cobria operação interna, criação/importação, manifesto, formato, handler, catálogo, front-api, escuta e diagnóstico; faltavam instruções explícitas para a LLM montar pacote interno validado, usar validador local, preparar envio pós-validação, distinguir preencher/automático e generalizar exemplos diversos por arquivo. Esta versão do comando passa a gerar esses ramos.");
    lista_add(itens, "12", NULL,
        "Regra de linguagem para LLM interna: explicar como construir conector novo do zero; tratar nomes do exemplo como valores a substituir; tratar processoId, respostaA, idempotência recebida, defaults e campos resolvidos pelo ambiente como valores preservados/automáticos; não ensinar a depender de detalhe interno da instalação como contrato público.");
    lista_add(itens, "12", NULL,
        "Árvore mental obrigatória do pacote interno dentro do clone GitHub: conector-<nome>/manifesto, formato do payload, handler executável, manual HTML técnico do conector, catálogo modular, mensagem de teste, arquivo sample de configuração/segredos, README e validador local. A LLM deve verificar cada peça antes de sugerir empacotamento ou envio interno.");
    lista_add(itens, "12", NULL,
        "Qualidade esperada das respostas da LLM: para cada arquivo citado, dizer finalidade, campos que a LLM deve preencher/adaptar, campos fixos/automáticos, exemplo realista em bloco de código, riscos de segurança, como testar e erro comum com correção.");

    lista_add(itens, NULL,
        "spec_segredos_configuracao_e_ambientes § C8: segredos nunca versionados; spec_seguranca_zero_trust_web_api § C11: logs sem segredos; spec_testes_microservicos_web_api_espaco § C9: contratos testados",
        "12 → ESTRUTURA DO PACOTE INTERNO PARA NOVOS CONECTORES");
    lista_add(itens, "13", NULL,
        "Manifesto: declarar nome conector-<servico>, titulo, descricao, versao semantica, ativo, tipo=conector, controlador, formatoConector, dependencias.arquivos, servicoExterno, operacoes e manualUsuario. A LLM deve sugerir ativo=false durante preparação quando houver risco externo.");
    lista_add(itens, "13", NULL,
        "Formato: declarar tipo=formato-conector, nome, versao, conector, descricao, entrada.modelos com campos/tipos/obrigatoriedade/valoresAceitos/regras/exemplos e saida.modelos com sucesso, dados e erro. Campo sem descrição deve ser tratado como pendência.");
    lista_add(itens, "13", NULL,
        "Handler: pode ser PHP, Python, Node, Bash, C, Go, Rust ou outro executável; deve receber exatamente o caminho do JSON, ler _protocolo e payload.dados, validar dados, usar timeout em serviço externo, preservar correlação e sair com código 0 em sucesso ou diferente de 0 em erro.");
    lista_add(itens, "13", NULL,
        "Catálogo: declarar mensagem pública somente quando revisada, destino conector__<nome>, idmensagem previsível, tipoMensagem=comando, prioridade, ativo, publica, idempotenciaObrigatoria=true e correlacaoObrigatoria=true; front-api é opcional e começa inativo até revisão; se existir frontend, resposta.atualizar deve ser exatamente o nome do conector.");
    lista_add(itens, "13", NULL,
        "Manual técnico do conector: deve ensinar objetivo, operações, payloads, exemplos completos, saída, credenciais necessárias sem senha real, erros comuns, limites, timeouts, dependências e exemplos de consumo interno. Manual vazio ou genérico reprova qualidade mesmo que compile.");
    lista_add(itens, "13", NULL,
        "Harmonização obrigatória dos manuais: pp --atualizar-manual-conector deve percorrer sisc/ e atualizar todos os HTMLs cujo nome contenha manual-conector. Cada arquivo mantém seu tom e público: ajuda-conectores/manual-conectores.html é manual interno amplo de operador/revisor, gitprog/manual-conector.html é instrutivo para programador externo, e manual de conector específico é direto para consumidores daquele conector. Não copiar o manual amplo para <sistema>/public.");
    lista_add(itens, "13", NULL,
        "Segredos e configuração: pacote pode conter apenas .sample com placeholders; configuração real fica no ambiente de instalação. A LLM deve recusar qualquer sugestão que coloque token real, senha, chave privada, app password ou certificado privado no pacote.");
    lista_add(itens, "13", NULL,
        "Mensagem de teste: deve conter envelope mínimo, idmensagem do catálogo e payload.dados seguro. Teste não deve movimentar dinheiro, enviar mensagem real, alterar estoque real ou chamar produção sem sandbox/autorização. Para passar no validador e receber selo-sandbox, o manifesto deve declarar testeSandbox.permitido=true, testeSandbox.semEfeitoReal=true e descricao com justificativa.");

    lista_add(itens, NULL,
        "spec_testes_microservicos_web_api_espaco § C9: testes locais antes de publicar; spec_seguranca_zero_trust_web_api § C8-C11: validação e falha segura",
        "13 → VALIDADOR LOCAL — INFORMAÇÕES QUE A LLM DEVE CONHECER");
    lista_add(itens, "14", NULL,
        "O validador é inspetor de qualidade do pacote: confirma exatamente um conector, nome conector-<nome> sem underscore, manifesto com campos obrigatórios, testeSandbox obrigatório, formato com entrada/saída, catálogo com mensagem ativa, front-api.resposta.atualizar igual ao nome do conector, handler existente/executável direto com shebang/ELF, manual HTML completo, mensagem de teste, ausência de links simbolicos, caminhos inseguros e segredos evidentes.");
    lista_add(itens, "14", NULL,
        "Interpretação: [OK] passou; [AVISO] revisar documentação/clareza/compatibilidade; [ERRO] bloqueia empacotamento. A LLM nunca deve orientar empacotar com erro; com aviso deve pedir revisão consciente antes do envio.");
    lista_add(itens, "14", NULL,
        "Erros comuns: nome do diretório diferente do manifesto; nome com underscore; handler sem chmod +x ou sem shebang; handler fora de conectores/<nome>/handlers; caminho absoluto, .., ., // ou barra invertida; link simbolico; formato sem saida; catálogo sem mensagem ativa; front-api.resposta.atualizar diferente do nome do conector; testeSandbox ausente; mensagem de teste sem payload.dados; segredo real detectado; comando shell perigoso.");
    lista_add(itens, "14", NULL,
        "O validador não executa o handler nem garante que API externa está correta, serviço está online, regra de negócio está completa, runtime existe em todo servidor, nem que operação financeira/destrutiva tem aprovação humana. A LLM deve explicar que validação local não substitui selo-sandbox e revisão humana para integrações críticas.");

    lista_add(itens, NULL,
        "spec_documentacao_adrs_e_catalogo_servicos § C8: catalogo com dono e contrato; spec_operacao_runbooks_e_incidentes § C11: preservar evidencias",
        "14 → EMPACOTAR E ENVIAR DEPOIS DE VALIDADO");
    lista_add(itens, "15", NULL,
        "Fluxo pós-validação: dentro do clone gitprog baixado do GitHub em qualquer diretório da máquina do programador, rodar validador, confirmar aprovado, conferir ausência de segredos reais, conferir nome/versão, gerar compactado, abrir pacote em pasta temporária, validar de novo, enviar pelo canal interno indicado e guardar hash/versão/data/protocolo. Depois do envio, aguardar selo-validacao e selo-sandbox emitidos pelo servidor para o SHA256 do pacote exato.");
    lista_add(itens, "15", NULL,
        "Comando recomendado: mkdir -p dist; ./validar-conector && tar --exclude='./dist' --exclude='.git' --exclude='*.log' --exclude='.env' -czf dist/conector-<servico>-1.0.0.tar.gz .  Preferir .tar.gz/.tgz; .zip é aceito quando necessário, mas permissões do handler devem ser conferidas.");
    lista_add(itens, "15", NULL,
        "Checklist de envio: um único conector; manifesto/formato/catálogo/handler/manual/teste/sample presentes; handler executável direto em conectores/<nome>/handlers com shebang/ELF; sem links simbolicos; sem caminhos inseguros; dependencias instalaveis apenas em conectores/<nome>/ ou web-api/; README/manual explicam objetivo, payload, saída, erros e credenciais; testeSandbox declarado com permitido=true, semEfeitoReal=true e descricao; versão do manifesto bate com pacote; pacote abre e valida em diretório temporário.");
    lista_add(itens, "15", NULL,
        "Metadados do envio interno: nome do conector, versão, resumo em uma frase, operações suportadas, dependências/runtime, modo sandbox, limitações conhecidas e responsável técnico. Não depender de conversa externa: tudo necessário deve estar dentro do pacote.");
    lista_add(itens, "15", NULL,
        "Selos do servidor: validar-recebidos em /var/www/html/gitconectores emite <pacote>.selo-validacao.json; testar-sandbox instala no testesis, faz preflight do runtime/sandbox, recusa se SISC_SANDBOX_DESATIVADO estiver definido, chama api.php com dryRun=true e executar=true, aguarda conclusão e emite <pacote>.selo-sandbox.json. instalar-aprovados no siscore real deve recusar sem os dois selos válidos.");
    lista_add(itens, "15", NULL,
        "Cada selo deve estar preso ao SHA256 do pacote e assinado por HMAC-SHA256 com chave interna fora do controle do programador. Se o pacote mudar ou o selo for copiado de outro pacote, a assinatura/hash deve falhar.");

    lista_add(itens, NULL,
        "spec_contratos_de_mensagem_espaco § C8: exemplos válidos; spec_idempotencia_correlacao_e_ordem § C8: idempotência em operações com efeito externo",
        "15 → EXEMPLOS DIVERSOS PARA A LLM GENERALIZAR CONECTORES");
    lista_add(itens, "16", NULL,
        "Conector clima: operação consultar_previsao; campos cidade, data opcional e unidade; segredo sample com endpoint/apiKey; handler valida cidade/data, chama API com timeout e retorna temperatura/chuva/alertas. Risco baixo, mas exige limite de taxa e tratamento de indisponibilidade.");
    lista_add(itens, "16", NULL,
        "Conector CRM/leads: operações criar_lead e consultar_lead; campos nome, email, telefone, origemLead; segredo sample com endpoint/token; handler valida email, usa upsert/idempotência por email e retorna id/status. Risco médio por duplicidade e dados pessoais.");
    lista_add(itens, "16", NULL,
        "Conector pagamentos: operações criar_cobranca, consultar_cobranca, cancelar_cobranca; campos valor, moeda, referenciaPedido, vencimento; segredo sample com clientId/clientSecret/certificado; handler valida valor e usa Idempotency-Key. Risco alto: nunca criar cobrança sem referência estável.");
    lista_add(itens, "16", NULL,
        "Conector estoque/ERP: operações consultar_saldo e ajustar_saldo; campos sku, quantidade, deposito, motivo; segredo sample com endpoint/token; handler valida SKU, exige motivo para escrita e previne concorrência. Risco alto quando altera saldo.");
    lista_add(itens, "16", NULL,
        "Conector OCR/documentos: operação extrair_texto; campos arquivo, tipoDocumento, idioma, extrairCampos; segredo sample com endpoint/apiKey; handler valida caminho relativo permitido, tamanho e privacidade antes de enviar. Risco de sigilo e vazamento de documento.");
}

int main(int argc, char **argv)
{
    if (argc > 2 || (argc == 2 && strcmp(argv[1], "--ajuda") && strncmp(argv[1], "--ajuda:", 8) && strcmp(argv[1], "--help") && strcmp(argv[1], "-h"))) {
        uso();
        return 1;
    }
    if (argc == 2) {
        uso();
        return 0;
    }

    char raiz_sisc[PATH_MAX];
    if (localizar_raiz_sisc(raiz_sisc, sizeof(raiz_sisc)) != 0) {
        fprintf(stderr, "atualizar-manual-conector: nao foi possivel localizar a raiz sisc.\n");
        return 1;
    }

    char pp_path[PATH_MAX * 2], arvores_dir[PATH_MAX * 2], arvore_path[PATH_MAX * 2];
    snprintf(pp_path, sizeof(pp_path), "%s/pp", raiz_sisc);
    snprintf(arvores_dir, sizeof(arvores_dir), "%s/arvores", raiz_sisc);
    snprintf(arvore_path, sizeof(arvore_path), "%s/operador-manual-conector.json", arvores_dir);

    if (access(pp_path, X_OK) != 0) {
        fprintf(stderr, "atualizar-manual-conector: pp nao executavel em %s\n", pp_path);
        return 1;
    }
    if (mkdir_p(arvores_dir) != 0) {
        fprintf(stderr, "atualizar-manual-conector: nao foi possivel criar/acessar %s\n", arvores_dir);
        return 1;
    }

    char sistema_atual[PATH_MAX];
    detectar_sistema_atual(raiz_sisc, sistema_atual, sizeof(sistema_atual));

    ListaItens itens = {0};
    montar_itens(&itens, raiz_sisc, sistema_atual);

    if (unlink(arvore_path) != 0 && errno != ENOENT) {
        fprintf(stderr, "atualizar-manual-conector: nao foi possivel remover arvore antiga: %s: %s\n", arvore_path, strerror(errno));
        free(itens.v);
        return 1;
    }

    size_t root_count = 0;
    for (size_t i = 0; i < itens.n; i++) if (!itens.v[i].pai[0]) root_count++;

    for (size_t i = 0; i < itens.n; i++) {
        char texto_sa[3200];
        if (itens.v[i].spec[0]) {
            snprintf(texto_sa, sizeof(texto_sa), "%s\n📋 %s", itens.v[i].texto, itens.v[i].spec);
        } else {
            snprintf(texto_sa, sizeof(texto_sa), "%s", itens.v[i].texto);
        }
        int rc = executar_sa(pp_path, arvores_dir, itens.v[i].pai[0] ? itens.v[i].pai : NULL, texto_sa, i == 0);
        if (rc != 0) {
            fprintf(stderr, "atualizar-manual-conector: falha ao criar item %zu via pp --sa (codigo %d): %s\n", i + 1, rc, itens.v[i].texto);
            free(itens.v);
            return rc;
        }
    }

    int rc_codigo = adicionar_inspecao_codigo_fonte(pp_path, arvores_dir, raiz_sisc, sistema_atual, root_count + 1);
    if (rc_codigo != 0) {
        fprintf(stderr, "atualizar-manual-conector: falha ao adicionar inspecao dinamica de codigo (codigo %d)\n", rc_codigo);
        free(itens.v);
        return rc_codigo;
    }

    if (garantir_ajuda_conectores_protegida(raiz_sisc) != 0) {
        fprintf(stderr, "atualizar-manual-conector: falha ao garantir ajuda-conectores/.htaccess\n");
        free(itens.v);
        return 1;
    }

    ResultadoManuais res_manuais = harmonizar_manuais_conector(raiz_sisc);
    if (res_manuais.erros) {
        fprintf(stderr, "atualizar-manual-conector: falha ao harmonizar %d manual(is) HTML de conector\n", res_manuais.erros);
        free(itens.v);
        return 1;
    }

    printf("Árvore manual de conector atualizada via pp --sa: %s\n", arvore_path);
    printf("Itens gravados: %zu\n", itens.n);
    printf("Inspeção dinâmica de código gravada: sim\n");
    printf("Manuais HTML *manual-conector* harmonizados: encontrados=%d atualizados=%d alinhados=%d\n",
           res_manuais.encontrados, res_manuais.atualizados, res_manuais.alinhados);
    printf("Visualize com: pp --sa=%s\n", arvore_path);
    free(itens.v);
    return 0;
}
