## Bucle autonomo (`fn-orquestador` + `/autonomous-task`) — issue 0069 `fn-orquestador` recorre el ciclo reactivo (CONSTRUIR → EJECUTAR → RECOPILAR → ANALIZAR → MEJORAR) sin intervencion humana, hasta convergencia (suite verde), estancamiento (no progreso N iteraciones), timeout, o tope de iteraciones. Trabaja SIEMPRE en sandbox `auto/`, NUNCA merge a master. ### Cuando se invoca - Skill `/autonomous-task ` (humano lanza explicitamente). - Cron / dag_engine (`schedule:` en YAML; planificable, no implementado por defecto). - NO se invoca como reaccion a hooks ni a fallos de tests "en caliente". Siempre tarea explicita. ### Reglas duras 1. **Sandbox obligatorio**: rama `auto/-`. Si la rama existe -> reset hard contra master y reanudar. NUNCA commits a master, NUNCA push --force-with-lease a master. 2. **Paths protegidos**: respetar `dev/autonomous_protected_paths.json` exactamente. Cualquier intento de modificar un path protegido aborta la iteracion y registra `task_runs.status='aborted_protected_path'`. 3. **Filtro de proposals auto-aplicables**: el orquestador SOLO aplica proposals que cumplen: - `kind in (bug_fix, e2e_check_add, doc_update, capability_tag_add)` -> auto-aplicable. - `kind in (new_function, deprecate_function, refactor, schema_change)` -> NO auto-aplicable (queda `pending` para humano). - `priority in (low, medium)` -> auto-aplicable. `high|critical` -> requiere humano salvo override `--allow-high`. 4. **Watchdog**: si la metrica de progreso (`checks_pass / checks_total`) no sube en `N=3` iteraciones consecutivas -> abort. Registrar `task_runs.status='stalled'`. 5. **Tiempo**: cada `task_run` con timeout default 30 min. Override con `--timeout-min N` hasta max 4h. 6. **Idempotencia**: re-ejecutar `/autonomous-task ` sobre la misma issue reanuda desde la ultima iteracion exitosa, NO reinicia desde cero (lookup en `task_runs` por `issue_id`). 7. **Trazabilidad**: cada decision se persiste en `task_runs.events_json[]` con `{ts, agent, action, evidence, diff_summary}`. El humano puede leer el log entero para auditar. 8. **No self-modification**: orquestador NUNCA modifica `.claude/agents/`, `.claude/commands/`, `.claude/rules/`, `.claude/scripts/`, `.claude/CLAUDE.md`. Reforzado en `autonomous_protected_paths.json`. 9. **NUNCA paths absolutos fuera del worktree**. Refuerzo del piloto 1 (2026-05-15): el orquestador uso `/home/lucas/fn_registry/bash/functions/...` para fixear hooks bash y contamino el repo principal. Solucion correcta: fix vive solo en el worktree. Post-cada-iteracion: `git -C status --short` debe permanecer igual al baseline; cualquier diff = `status=sandbox_breach` -> ABORT. 10. **Pre-commit hooks compartidos**. Worktrees comparten `.git/hooks/` con main. Si un hook llama scripts via path absoluto, ejecutara la version de main. Si el hook bloquea progreso por bug en main: aplica el fix EN EL WORKTREE (commit en auto/*); si el bug del hook excede scope: `git commit --no-verify` para ESE commit con `task_runs.events_json[].decision="skip_hook"` + razon. NO editar main. ### Sub-repos vs worktree padre Cuando el issue toca `app.md` o codigo dentro de `apps//`, `projects/

/apps//`, `cpp/apps//`, o `analysis//` — estos directorios son **sub-repos Gitea independientes** y estan `.gitignore`d en el repo padre `fn_registry` (regla `apps_subrepo.md`). El orquestador: - **Crea worktree padre** `auto/` en `/tmp/fn_orq__/` por protocolo, **pero no escribe alli** porque los cambios no se versionan en el padre. - **Opera DIRECTAMENTE en el sub-repo** de la app/analysis target. Branch `auto/-` se crea dentro de `apps//.git`, NO en el padre. - **PR draft sale al sub-repo** en `dataforge/` (NO a `dataforge/fn_registry`). Humano revisa+mergea en el sub-repo. - **Worktree padre queda vacio** y se limpia normal con `git worktree remove` al terminar. Validado en piloto 0120 (`add_e2e_check` sobre `chart_demo`): PR creado en `dataforge/chart_demo/pulls/1`, sanity check del main repo `fn_registry` confirmo cero contaminacion. Si el issue toca AMBOS lados (codigo del registry padre + app de sub-repo), el orquestador commitea separado: cambios del padre en `auto/` (worktree padre), cambios de la app en `auto/-` (sub-repo). Dos PRs draft. Humano coordina merge. ### Gitea API vs `gh` Pre-condicion `gh auth status` es smoke check (target github.com). Mecanismo real de PR es `curl` a Gitea API: ```bash GITEA_TOKEN=$(pass gitea/dataforge-git-token | head -n1) curl -X POST -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title":"...","head":"auto/-","base":"master","draft":true,"body":"..."}' \ "https://gitea-.../api/v1/repos/dataforge//pulls" ``` Validado en pilotos 0076 y 0120. ### Estructura task_run Migration `fn_operations/migrations/006_task_runs.sql`. Campos minimos: `id`, `issue_id`, `branch`, `started_at`, `finished_at`, `status` (`running|done|failed|aborted_protected_path|stalled|timeout`), `iterations`, `checks_pass`, `checks_fail`, `proposals_applied_json`, `proposals_skipped_json`, `events_json`, `final_diff_sha`. ### Fases por iteracion ``` loop: 1. fn-constructor (Read+Edit+Write+Bash limitados) - aplica fix segun ultima proposal seleccionada 2. fn-executor - corre build + tests + smoke 3. fn-recopilador - audita operations.db de la app 4. fn-analizador - corre e2e_checks (registra e2e_runs) 5. SI todos los checks pasan -> commit + push rama + abre PR. status=done. exit. 6. SI no progreso N iteraciones -> abort. status=stalled. 7. fn-mejorador - crea proposals desde fallos 8. orquestador filtra proposals auto-aplicables -> selecciona la primera -> goto 1. ``` ### Output al humano ``` === /autonomous-task 0068 === task_run_id: run_e2e_a1b2c3 branch: auto/0068-e2e-validation iterations: 4 status: done checks_pass: 8/8 proposals_applied: 3 (run_e2e_run_001, run_e2e_run_002, run_e2e_run_003) proposals_skipped: 1 (refactor — needs human review) PR: https://gitea.../pulls/42 ``` ### Anti-patrones | Anti-patron | Por que es malo | |---|---| | Mergear `auto/` a master sin PR + humano | Salta gate, riesgo de regresion | | Auto-aplicar proposal `kind=refactor` | Cambios sistemicos requieren revision | | Modificar `go.sum`, `package-lock.json`, `uv.lock` | Cambios de deps requieren CVE/license review | | Bucle infinito sin watchdog | Coste descontrolado de tokens | | Borrar archivos sin backup en `task_runs.events_json` | Pierde auditoria | | Override de paths protegidos via env var | Bypass de seguridad | ### Relacion con otras reglas - [[e2e_validation]] — fn-analizador (fase 4) lee el contrato `e2e_checks` que el orquestador usa como gate. - [[apps_tbd]] — el orquestador opera en rama `auto/*`, no exenta de TBD. - [[feature_flags]] — si el fix no esta terminado, el orquestador puede meterlo detras de flag OFF antes de PR. - [[registry_calls]] — toda invocacion del orquestador y sub-agentes pasa por MCP/`fn run`/heredoc canonico, registrada en call_monitor.