Files
fn_registry/dev/issues/0171-project-subrepo-manifest-and-reclone.md
T
egutierrez eb8dbf66a1 feat(infra): auto-commit con 88 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-11 00:16:46 +02:00

10 KiB

id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
id title status type domain scope priority depends blocks related created updated tags
0171 Manifest de sub-repos por project + re-clonado y auditoría de cobertura en Gitea pendiente enhancement
registry-quality
infra
registry-only alta
0166
2026-06-10 2026-06-10
projects
subrepo
gitea
clone
backup
manifest
fn-doctor

Actualización 10/06/2026 — implementado el núcleo (enfoque KISS). El manifest subrepos.yaml propuesto abajo se descartó: registry.db (tablas apps/analysis con project_id, propagadas entre PCs por fn sync) ya es el manifest de sub-repos, y clone_project_subrepos_bash_pipelines ya lo consume. No hace falta un archivo nuevo. Lo que faltaba era integración + auditoría. Ver ## Estado de implementación al final.

0171 — Manifest de sub-repos por project + re-clonado y auditoría de cobertura en Gitea

APP Metadata

Campo Valor
ID 0171
Estado pendiente
Prioridad alta (riesgo de pérdida de datos)
Tipo enhancement — metadata de projects + /full-git-pull + fn doctor

Contexto

El 10/06/2026, al preparar un dashboard sobre el project aurgi, se descubrió que el project paraguas no existía en Gitea (dataforge/aurgi → 404). Sus 3 analyses sí estaban a salvo como sub-repos independientes (dataforge/venta_web, dataforge/sale_prices_comprobation, dataforge/presupuestos_callcenter), pero el project.md, vault.yaml y CONVENTIONS.md de nivel-project no estaban versionados en ningún sitio. Reconstruir el project obligó a adivinar los nombres de los sub-repos hijos uno a uno desde la lista completa de repos de Gitea.

Una auditoría de cobertura projects ↔ Gitea confirmó el agujero:

Project Repo Gitea Riesgo
fleet_monitoring, fn_monitoring, message_bus, web_scraping ninguno
obsidian, osint (solo en disco local) alto — resuelto en esta sesión (subidos a dataforge/obsidian, dataforge/osint)
aurgi (404, paraguas inexistente) pendiente — analyses salvados, docs nivel-project no

Dos problemas estructurales quedan abiertos:

  1. Projects sin repo Gitea: su contenido de nivel-project vive solo en disco. Si se borra el disco (o el project no se sincroniza a otro PC), se pierde. La regla projects.md dice que cada project debe ser su propio repo Gitea, pero no hay nada que lo verifique ni lo fuerce.

  2. Sub-repos hijos no referenciados: el .gitignore de cada project excluye apps/*/ y analysis/*/ (son sub-repos independientes). Por tanto, un clon fresco del project NO trae sus hijos, y no existe ningún manifest que diga qué hijos clonar. Hoy /full-git-pull solo descubre repos vía discover_git_repos_bash_infra (busca .git ya presentes en disco): si el hijo nunca se clonó, es invisible. Resultado: para reconstruir un project en una máquina nueva hay que adivinar sus sub-repos (exactamente lo que pasó con aurgi).

Objetivo

Que todo project (a) tenga su repo Gitea garantizado y (b) referencie declarativamente sus sub-repos hijos (apps + analyses), de modo que clonar el project en cualquier PC permita re-clonar automáticamente todo su árbol sin adivinar nada.

Propuesta

1. Manifest de sub-repos por project

Añadir a cada project un manifest declarativo de sus hijos. Dos opciones de formato (decidir una):

  • Opción A (KISS, preferida): subrepos.yaml en la raíz del project, análogo a vault.yaml:

    # projects/<p>/subrepos.yaml — sub-repos hijos de este project (apps + analyses)
    subrepos:
      - kind: analysis            # app | analysis
        name: venta_web
        path: analysis/venta_web
        repo: dataforge/venta_web
        url: https://gitea-.../dataforge/venta_web
      - kind: analysis
        name: sale_prices_comprobation
        path: analysis/sale_prices_comprobation
        repo: dataforge/sale_prices_comprobation
        url: https://gitea-.../dataforge/sale_prices_comprobation
    
  • Opción B: sección ## Sub-repos en project.md con una tabla kind | name | path | url.

subrepos.yaml (Opción A) es más fácil de parsear por las funciones de git y se versiona con el project (no está en el .gitignore). El manifest se autogenera/actualiza escaneando los .git hijos presentes en disco + su remote get-url origin (reusar discover_git_repos_bash_infra).

2. Generación y mantenimiento del manifest

Función/pipeline nueva (delegar a fn-constructor, grupo infra/git) que, dado un project:

  • Escanea apps/*/.git y analysis/*/.git, lee su remote origin.
  • Escribe/actualiza subrepos.yaml.
  • Idempotente. Se invoca dentro de /full-git-push (o fn index) para mantener el manifest al día.

3. Re-clonado desde el manifest en /full-git-pull

Extender /full-git-pull para que, tras actualizar cada project, lea su subrepos.yaml y clone los hijos que falten (urlpath). Así, en un PC nuevo: clonar dataforge/<project>/full-git-pull → reconstruye apps + analyses automáticamente. Requiere una función clone_missing_subrepos_bash_infra(project_dir) (delegar a fn-constructor).

4. Garantizar repo Gitea de cada project + auditoría en fn doctor

  • Subcomando nuevo fn doctor projects (función audit_projects_coverage_go_infra): por cada project en disco reporta repo_gitea (existe en Gitea sí/no), repo_url (declarado en project.md sí/no), y subrepos_manifest (presente + cuántos hijos en disco sin entrada / en manifest sin clonar). Salida --json. Cero hallazgos = sano.
  • Acción derivada documentada: repo_gitea=noensure_repo_synced_bash_infra projects/<p> dataforge <p> master "init: project <p>".

5. Backfill inicial

  • aurgi: traer su project.md / vault.yaml / CONVENTIONS.md de aurgi-pc (o home-wsl) y crear dataforge/aurgi + subrepos.yaml con los 3 analyses ya conocidos. No reconstruir a mano un project.md mínimo (divergiría del real).
  • Resto de projects con hijos (fleet_monitoring, fn_monitoring, message_bus, web_scraping): generar su subrepos.yaml con la función del punto 2.

Definition of Done

Escenario Tipo Comando / evidencia Resultado esperado
Golden: clon fresco reconstruye árbol e2e clonar dataforge/<p> en dir limpio → /full-git-pull apps + analyses del project re-clonados desde subrepos.yaml
Edge: project sin hijos (obsidian) e2e generar manifest subrepos.yaml válido y vacío (o ausente), sin error
Edge: hijo en disco sin .git unit auditoría fn doctor projects lo reporta como "hijo sin sub-repo"
Error: project sin repo Gitea e2e fn doctor projects --json lo marca repo_gitea=false, sugiere ensure_repo_synced
Cobertura audit fn doctor projects 0 projects sin repo, 0 hijos sin referenciar

Decisiones abiertas

  1. Formato del manifest: subrepos.yaml (A) vs. sección en project.md (B). Recomendado A.
  2. ¿Auto-generar el manifest en fn index o solo en /full-git-push? (evitar I/O de red en fn index; preferible en push).
  3. aurgi: ¿traer de aurgi-pc por SSH ahora, o dejarlo para cuando el project se sincronice?

Notas

En esta sesión ya se resolvió el riesgo inmediato: obsidian y osint se subieron a Gitea (dataforge/obsidian, dataforge/osint) con ensure_repo_synced_bash_infra y se les añadió repo_url en su project.md. Este issue cubre la solución estructural y reutilizable para que el caso no vuelva a ocurrir con ningún project. Relacionado con #0166 (dependencias app→app para build reproducible): ambos persiguen que clonar el ecosistema en un PC nuevo sea determinista.

Estado de implementación (10/06/2026)

Implementado con enfoque KISS, sin subrepos.yaml (registry.db + fn sync ya cumplen esa función). Cambios:

Funciones nuevas:

  • ensure_project_gitignore_bash_infra — garantiza idempotente el .gitignore canónico de un project (apps/*/, analysis/*/, vaults/* + excepciones) antes de cualquier git add -A, para no trackear el contenido de los sub-repos hijos.
  • audit_projects_coverage_go_infra (+ FormatProjectsCoverage) — motor de fn doctor projects. Reporta por project: git/remote/repo_url/children (cloned/inDB) + issues (no_gitea_repo, children_missing, dir_not_found). Solo git local + registry.db, sin red.

Integraciones:

  • full_git_push v1.1.0 — paso 1c: auto-inicializa y pushea los projects paraguas sin repo (antes solo apps/analyses), asegurando el .gitignore canónico primero. Cierra el agujero aurgi/obsidian/osint.
  • full_git_pull v1.1.0 — paso 6: tras fn sync, reclona los sub-repos hijos faltantes de cada project con clone_project_subrepos + re-index. Clonar el paraguas + /full-git-pull reconstruye el árbol entero.
  • fn doctor projects — nuevo subcomando (cmd/fn/doctor.go). Hoy reporta 0 projects con problemas.

Hecho aparte (riesgo inmediato): dataforge/obsidian + dataforge/osint creados, repo_url en sus project.md.

Pendientes (no bloquean el núcleo)

  1. Check inverso — HECHO (10/06/2026). FindOrphanProjectRefs + FormatOrphanProjectRefs en audit_projects_coverage_go_infra, enchufado en fn doctor projects. Detecta apps/analysis con project_id sin fila en projects. Hoy reporta 4 paraguas huérfanos (existen en otro PC, nunca subidos a Gitea — mismo caso que aurgi):
    • element_agents (6 apps: agents_and_robots, agents_dashboard, device_agent, element_matrix_chat, matrix_admin_panel, matrix_client_pc)
    • imagegen (image_to_3d_studio)
    • osint_graph (graph_explorer)
    • aurgi (sus analyses sí están en Gitea; el paraguas no)
  2. Fix de datos de los 4 paraguas huérfanos — pendiente, requiere el PC origen. No están en disco ni en Gitea en este PC (lucas-linux), así que no se pueden reconstruir aquí sin inventar. El fix correcto: correr /full-git-push en el PC donde cada paraguas existe en disco (aurgi-pc / home-wsl). Con full_git_push v1.1.0 (paso 1c) eso ya los crea en Gitea automáticamente. Tras eso, /full-git-pull aquí (paso 6) los traerá. NO reconstruir un project.md mínimo a mano.
  3. DoD vida útil: validar el reclonado en un PC nuevo real (clon limpio del paraguas → /full-git-pull → árbol reconstruido) antes de declarar el issue cerrado.