#!/usr/bin/env python3 """78_publicar_v010.py — Publicação da v0.10.0 no HF (UM ÚNICO upload_folder organizado — o HF bloqueia envios parciais em sequência; upload atômico). Fases: 1. inventário da conta + APAGAMENTO de estados de treino remanescentes; 2. varredura local do VALOR do token (nenhum arquivo pode contê-lo); 3. UM ÚNICO upload_folder com ignore_patterns EXPLÍCITOS + delete_patterns p/ monólitos dissolvidos (src/jepa.rs → src/jepa/…); 4. verificação pós-upload (0 estados, módulos-chave presentes); 5. varredura REMOTA do valor do token; 6. apagamento dos estados de treino LOCAIS (checkpoints + manifestos). v0.10.0: manifestos (*.manifest.json) NÃO são publicados — só têm sentido ao lado do checkpoint correspondente (que também não é publicado). Token: EXCLUSIVAMENTE via variável de ambiente HF_TOKEN (nunca em arquivo). """ import os, sys, tempfile ARQUIVOS_EXCLUIR_DIRS = {"target", ".cargo", "__pycache__", ".git", ".venv", "skills", "externos"} ARQUIVOS_EXCLUIR_NOME = {"shard_treino.jsonl", "shard_validacao.jsonl", "bpe.json", "rustup-init.sh"} SUFIXOS_ESTADO = (".pt", ".pth", ".ckpt", ".safetensors", ".bin", ".npz", ".msgpack") NOMES_ESTADO = {"gerador_conceitos.json", "tokenizador_conceitos.json", "gerador_aritmetica.json", "_drill_ck.json"} # monólitos da v0.9.0 dissolvidos em diretórios na v0.10.0 (r-35 §2) MONOLITOS_VELHOS = ["src/python.rs", "src/jepa.rs", "src/pensamento.rs", "src/moe_redirecionavel.rs"] def coletar(pasta): arquivos = {} for raiz, dirs, fs in os.walk(pasta): dirs[:] = [d for d in dirs if d not in ARQUIVOS_EXCLUIR_DIRS] for f in fs: if f in ARQUIVOS_EXCLUIR_NOME or f in NOMES_ESTADO: continue if f.endswith(SUFIXOS_ESTADO) or f.endswith(".estado.json"): continue if f.endswith(".manifest.json") or f.endswith(".manifest.json.tmp"): continue if f.endswith(".so") or f in (".gitignore", "Cargo.lock.ori"): continue if f.startswith("hf_") or f.startswith("intros_"): continue caminho = os.path.join(raiz, f) arquivos[os.path.relpath(caminho, pasta)] = caminho return arquivos def varre_token_em_arquivos(token, pares): tb = token.encode() achados = [] for rel, p in pares.items(): try: with open(p, "rb") as f: if tb in f.read(): achados.append(rel) except OSError: pass return achados def main(): from huggingface_hub import HfApi token = os.environ.get("HF_TOKEN") if not token: print("ERRO: HF_TOKEN ausente"); sys.exit(1) api = HfApi(token=token) repo = "PowerMachine/khtst-rust" # ---------------- 1) inventário da conta + apaga estados ---------------- print("=== 1) inventário da conta HF (procura estados de treino) ===") repos = list(api.list_models(author="PowerMachine")) print(f"repos: {len(repos)}") total_removidos = 0 for r in repos: try: files = api.list_repo_files(repo_id=r.id, repo_type="model") except Exception as e: print(f" {r.id}: erro ao listar ({e})"); continue estados = [f for f in files if f.endswith(SUFIXOS_ESTADO) or f.split("/")[-1] in NOMES_ESTADO or (".meta.json" in f and "checkpoint" in f)] if estados: print(f" {r.id}: APAGANDO {len(estados)} estados") for f in estados: api.delete_file(path_in_repo=f, repo_id=r.id, repo_type="model") total_removidos += len(estados) else: print(f" {r.id}: {len(files)} arquivos, 0 estados") print(f"estados removidos no total: {total_removidos}") # ---------------- 2) varredura local do token ---------------- pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) arquivos = coletar(pasta) print(f"\n=== 2) varredura local: {len(arquivos)} arquivos ===") achados = varre_token_em_arquivos(token, arquivos) if achados: print(f"ERRO: valor do token encontrado em: {achados}"); sys.exit(1) print("varredura de token local: limpa") # ---------------- 3) UM ÚNICO upload_folder ---------------- ignores = ( [f"{d}/**" for d in ARQUIVOS_EXCLUIR_DIRS] + [f"{d}" for d in ARQUIVOS_EXCLUIR_DIRS] + [f"**/{n}" for n in ARQUIVOS_EXCLUIR_NOME] + [f"**/{n}" for n in NOMES_ESTADO] + list(SUFIXOS_ESTADO) + ["*.so", ".gitignore", "hf_*.py", "hf_*.json", "intros_*.json", "*.estado.json", "**/*.manifest.json", "**/*.manifest.json.tmp", "*.tmp"] ) print(f"\n=== 3) upload_folder ÚNICO ({len(arquivos)} arquivos) ===") api.upload_folder( repo_id=repo, repo_type="model", folder_path=pasta, ignore_patterns=ignores, delete_patterns=MONOLITOS_VELHOS, commit_message="v0.10.0: análise/prova/teste das críticas de " "engenharia Qwen3.8 lote 3 (r-35) — divisão SRP dos monólitos " "jepa/pensamento/moe/python em 26 submódulos (API estável via " "re-exports; 'Amdahl de compilação' refutada por experimento " "controlado, builds frios neutros), checkpoints atômicos SHA-256 " "puro FIPS 180-4 + fsync + rename + manifesto (CP-1..CP-3; " "correções da proposta: sem destruir estado anterior, manifesto " "com barreira, sem bincode/unwrap), TemperaturaInversa T-V3 " "(fronteira tipada da convexidade N-2; alegação compile-time " "corrigida), trait CamadaKhtst+CamadaHomeostatica (premissa do " "controlador refutada no fonte; Vec; adaptador MoeComPapel " "bit-a-bit), CLI Typer 75 (fachada aditiva com resume verificado " "por hash) — 123/123 cargo, 107/107 gates, treino real Wikipédia " "PT-BR com checkpoints íntegros", ) print("upload concluído") # ---------------- 4) verificação pós-upload ---------------- print("\n=== 4) verificação pós-upload ===") files = api.list_repo_files(repo_id=repo, repo_type="model") estados = [f for f in files if f.endswith(SUFIXOS_ESTADO) or f.split("/")[-1] in NOMES_ESTADO or f.endswith(".manifest.json")] assert not estados, f"estados publicados: {estados}" chaves = ["src/checkpoint.rs", "src/tipos.rs", "src/camadas.rs", "src/jepa/mod.rs", "src/pensamento/mod.rs", "src/moe_redirecionavel/mod.rs", "src/python/mod.rs", "src/fnh.rs", "src/verificador.rs", "scripts/75_cli.py", "scripts/76_telemetria_v010.py", "scripts/77_suite_v010.py", "scripts/78_publicar_v010.py", "docs/memorias/r-35-analise-provas-qwen-v010.md", "resultados/suite_v010_final.json", "resultados/telemetria_v010.json", "resultados/fase_a_v010.json", "resultados/fase_b_v010.json", "resultados/treino_v090.json"] faltando = [c for c in chaves if c not in files] assert not faltando, f"faltando: {faltando}" velhos = [m for m in MONOLITOS_VELHOS if m in files] assert not velhos, f"monólitos velhos ainda no repo: {velhos}" print(f"repo: {len(files)} arquivos | 0 estados | módulos-chave OK | " f"monólitos velhos removidos") # ---------------- 5) varredura REMOTA do token ---------------- print("\n=== 5) varredura REMOTA do valor do token ===") with tempfile.TemporaryDirectory() as tmp: achados_remotos = [] for f in files: if f.endswith((".py", ".rs", ".md", ".json", ".toml", ".sh", ".cfg", ".txt", ".jsonl")): try: p = api.hf_hub_download(repo_id=repo, repo_type="model", filename=f, local_dir=tmp) with open(p, "rb") as fh: if token.encode() in fh.read(): achados_remotos.append(f) except Exception: pass if achados_remotos: print(f"ERRO: token remoto em: {achados_remotos}"); sys.exit(1) print("varredura remota: limpa") # ---------------- 6) apaga estados de treino LOCAIS ---------------- print("\n=== 6) estados de treino locais (checkpoints + manifestos) ===") apagados = 0 for nome in sorted(NOMES_ESTADO): for sufixo in ("", ".manifest.json"): p = os.path.join(pasta, "resultados", nome + sufixo) if os.path.exists(p): os.remove(p) apagados += 1 print(f" apagado: resultados/{nome}{sufixo}") print(f"locais apagados: {apagados}") print("\nPUBLICAÇÃO v0.10.0 CONCLUÍDA") if __name__ == "__main__": main()