Files
egutierrez 516db8efc0 feat(infra): auto-commit con 10 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-03 16:56:53 +02:00

6.2 KiB

Apps son sub-repos Gitea independientes — gotcha al usar worktrees

Regla operativa critica descubierta el 2026-05-18 durante implementacion del flow 0008.

El gotcha

apps/*/ esta en .gitignore del repo fn_registry. Cada app es su propio repo Gitea en dataforge/<app_name> con su .git/ dentro de apps/<app_name>/. Esto significa:

  • Cuando un agente trabaja en un git worktree del repo padre y crea apps/<nueva_app>/, los archivos viven SOLO en el working directory del worktree.
  • Como apps/*/ esta gitignored en el repo padre, los archivos no se pueden commitear al worktree del repo padre.
  • Cuando se hace git worktree remove --force worktrees/<slug>/, el working directory entero se borra — el codigo de la app desaparece.

Consecuencia: una app creada dentro de un worktree del repo padre se pierde al limpiar el worktree salvo que se haya promovido a su propio sub-repo Gitea ANTES.

El patron correcto al crear apps en worktrees

# 1. Agente trabaja en worktree del repo padre
cd $HOME/fn_registry/worktrees/<slug>

# 2. Scaffold la app via pipeline canonico
./fn run init_cpp_app <name>           # apps C++
# o ./fn run init_jupyter_analysis ... # analysis
# o crear apps/<name>/ a mano (Go service, etc.)

# 3. ANTES de salir del worktree: inicializa la app como sub-repo
cd apps/<name>
git init -b master
git add -A
git -c user.email="agent@fn_registry" -c user.name="agent" \
    commit -m "feat: initial scaffold of <name>"

# 4. Trabajo continua en sub-repo (commits dentro de apps/<name>/.git)
# 5. Cerrar issue en repo padre (mv .md a completed/), commit del padre con cambios en cpp/CMakeLists.txt, etc.

Cuando el humano corre /full-git-push despues del merge, el script ensure_repo_synced_bash_infra detecta que apps/<name>/.git existe + no tiene remote + crea repo Gitea en dataforge/<name> + pushea master.

Que ESTA SI versionado en el repo padre

  • cpp/CMakeLists.txt (el if(EXISTS ...) add_subdirectory(apps/<name>) endif()).
  • dev/issues/completed/<NNNN>-<slug>.md (cierre del issue).
  • docs/capabilities/*.md si la app aporta a un capability group.
  • dev/feature_flags.json si introduce flags.

Todo lo demas (codigo de la app + app.md + appicon + service unit + tests propios de la app) vive en apps/<name>/.git independiente.

REGLA DURA: el repo padre NUNCA trackea contenido de artefactos hijos

El repo padre fn_registry solo versiona codigo del registry (functions/, types/, registry/, cmd/, docs/, .claude/, dev/, migrations/, y el framework/functions/vendor de cpp/). NUNCA debe trackear el contenido de un artefacto hijo:

  • apps: apps/*, cpp/apps/*, projects/*/apps/*
  • analyses: analysis/*, projects/*/analysis/*
  • projects: projects/*

Cada artefacto es un sub-repo Gitea independiente con su propio .git; su contenido completo (codigo, app.md, analysis.md, appicon.*, binarios, frontend, local_files/, tests propios) vive SOLO en ese sub-repo. fn index lee los .md de registro directamente del disco — no necesitan estar en el git del padre. Lo unico que el padre versiona dentro de esos arboles son los marcadores .gitkeep (mantienen apps/ y analysis/ presentes cuando estan vacios) y, en projects/, los project.md template si los hubiera.

Como se rompe (sintoma = repo padre permanentemente dirty): un git add -f apps/<x>/... (forzado, saltandose el .gitignore) o un commit que mete contenido del hijo al padre. Como el archivo ya queda en el indice, el .gitignore NO lo vuelve a ignorar y aparece para siempre en git status del padre como modificado cada vez que el sub-repo cambia (doble-tracking). Caso real (2026-06-03): apps/dag_engine/ (31 archivos: Go + frontend + app.md) y apps/shaders_lab/ (app.md + un binario .exe de 23 MB) quedaron forzados al indice del padre y lo dejaban dirty en cada cambio del sub-repo.

Auditoria (cero salida = sano):

git ls-files 'apps/*' 'analysis/*' 'projects/*/apps/*' 'projects/*/analysis/*' 'cpp/apps/*' \
  | grep -vE '(^|/)\.gitkeep$'

Fix si aparece contenido trackeado:

# --cached SIEMPRE: saca del indice del padre sin borrar el working tree.
# El codigo sigue a salvo en el .git del sub-repo.
git rm -r --cached apps/<x>
git commit -m "chore: untrack contenido del artefacto <x> (es sub-repo Gitea)"

NUNCA git rm sin --cached (borraria el working tree del sub-repo). Prevencion: jamas usar git add -f sobre paths de artefactos; las reglas apps/*/, analysis/*/, projects/*/ del .gitignore ya cubren el caso por defecto y solo un force las salta.

Sintomas de la perdida

Si limpias el worktree y luego corres ls apps/<name>/, devuelve "No such file or directory" pese a que el issue aparece cerrado en dev/issues/completed/. Patron = scaffold sin sub-repo init = trabajo perdido.

Recovery si pasa

  1. Re-crear worktree desde master.
  2. Re-spawn agente con instruccion explicita: git init dentro de la app antes de terminar.
  3. NO eliminar el worktree hasta confirmar que apps/<name>/.git esta inicializado con al menos un commit.

Aplica tambien a analysis

analysis/*/ y projects/*/analysis/*/ siguen mismo patron (cada analysis es repo Gitea). El pipeline init_jupyter_analysis_bash_pipelines ya hace git init automatico — por eso no hubo perdidas alli. Las apps C++/Go scaffolded a mano NO inicializan el sub-repo automaticamente — es responsabilidad del agente.

Lo que aprende parallel-fix-issues

El template del prompt de cada agente DEBE incluir la instruccion:

"Si tu issue crea una app nueva en apps/<name>/, inicializa el sub-repo (cd apps/<name> && git init -b master && git add -A && git commit ...) antes de terminar. Sin esto, apps/* esta gitignored y el codigo se perdera cuando el orquestador limpie el worktree."

Aplicar este parrafo al template del skill — ver .claude/skills/parallel-fix-issues/SKILL.md (o equivalente).

Relacion con otras reglas

  • apps_tbd — TBD en apps, esta regla complementa con el patron de sub-repo init.
  • artefactos — apps son artefactos, esta regla especifica gotcha de su sub-repo.
  • apps_vs_functions — apps en apps/, esta regla refuerza por que apps/* gitignored.